android - this asynctask class should be static or leaks might occur




警告:此AsyncTask類應該是靜態的,否則可能會發生洩漏 (2)

如何使用靜態內部AsyncTask類

為了防止洩漏,可以使內部類靜態。 但問題是,您無法再訪問Activity的UI視圖或成員變量。 您可以傳入對 Context 的引用,但之後會遇到內存洩漏的相同風險。 (如果AsyncTask類具有對它的強引用,Android在關閉後不能對Activity進行垃圾收集。)解決方案是對Activity(或者你需要的任何 Context )進行弱引用。

public class MyActivity extends AppCompatActivity {

    int mSomeMemberVariable = 123;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // start the AsyncTask, passing the Activity context
        // in to a custom constructor 
        new MyTask(this).execute();
    }

    private static class MyTask extends AsyncTask<Void, Void, String> {

        private WeakReference<MyActivity> activityReference;

        // only retain a weak reference to the activity 
        MyTask(MyActivity context) {
            activityReference = new WeakReference<>(context);
        }

        @Override
        protected String doInBackground(Void... params) {

            // do some long running task...

            return "task finished";
        }

        @Override
        protected void onPostExecute(String result) {

            // get a reference to the activity if it is still there
            MyActivity activity = activityReference.get();
            if (activity == null || activity.isFinishing()) return;

            // modify the activity's UI
            TextView textView = activity.findViewById(R.id.textview);
            textView.setText(result);

            // access Activity member variables
            activity.mSomeMemberVariable = 321;
        }
    }
}

筆記

  • 據我所知,這種類型的內存洩漏危險一直都是真的,但我只是開始在Android Studio 3.0中看到警告。 許多主要的 AsyncTask 教程仍然沒有處理它(見 herehereherehere )。
  • 如果您的 AsyncTask 是頂級類,您也會遵循類似的過程。 靜態內部類與Java中的頂級類基本相同。
  • 如果您不需要Activity本身但仍需要Context(例如,顯示 Toast ),則可以傳入對應用程序上下文的引用。 在這種情況下, AsyncTask 構造函數將如下所示:

    private WeakReference<Application> appReference;
    
    MyTask(Application context) {
        appReference = new WeakReference<>(context);
    }
  • 有一些參數可以忽略這個警告,只使用非靜態類。 畢竟,AsyncTask旨在非常短暫(最長幾秒鐘),並且無論如何它將在活動結束時釋放對Activity的引用。 看到 thisthis
  • 優秀的文章: androiddesignpatterns.com/2013/01/…

科特林

在Kotlin中, 不要包含 內部類 的 inner 關鍵字 。 這使其默認為靜態。

我還不太擅長Kotlin,所以如果可以改進我的代碼,請更正下面的代碼:

class MyActivity : AppCompatActivity() {

    internal var mSomeMemberVariable = 123

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // start the AsyncTask, passing the Activity context
        // in to a custom constructor
        MyTask(this).execute()
    }

    private class MyTask
    internal constructor(context: MyActivity) : AsyncTask<Void, Void, String>() {

        private val activityReference: WeakReference<MyActivity> = WeakReference(context)

        override fun doInBackground(vararg params: Void): String {

            // do some long running task...

            return "task finished"
        }

        override fun onPostExecute(result: String) {

            // get a reference to the activity if it is still there
            val activity = activityReference.get()
            if (activity == null || activity.isFinishing) return

            // modify the activity's UI
            val textView = activity.findViewById(R.id.textview)
            textView.setText(result)

            // access Activity member variables
            activity.mSomeMemberVariable = 321
        }
    }
}

我在我的代碼中收到警告:

這個AsyncTask類應該是靜態的,否則可能會發生洩漏(匿名android.os.AsyncTask)

完整的警告是:

此AsyncTask類應該是靜態的,否則可能會發生洩漏(匿名android.os.AsyncTask)靜態字段將洩漏上下文。 非靜態內部類具有對其外部類的隱式引用。 如果該外部類是例如片段或活動,那麼這個引用意味著長時間運行的處理程序/加載器/任務將保存對活動的引用,這阻止它被垃圾收集。 同樣,對來自這些較長時間運行的實例的活動和片段的直接字段引用可能會導致洩漏。 ViewModel類絕不應指向視圖或非應用程序上下文。

這是我的代碼:

 new AsyncTask<Void,Void,Void>(){

        @Override
        protected Void doInBackground(Void... params) {
            runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    mAdapter.notifyDataSetChanged();
                }
            });

            return null;
        }
    }.execute();

我該如何糾正?


非靜態內部類包含對包含類的引用。 當您將 AsyncTask 聲明為內部類時,它可能比包含的 Activity 類更長壽。 這是因為對包含類的隱式引用。 這將防止活動被垃圾收集,從而導致內存洩漏。

要解決您的問題,請使用靜態嵌套類而不是匿名,本地和內部類,或使用頂級類。





android-runonuithread