[Android] 警告:此AsyncTask類應該是靜態的或可能發生洩漏


Answers

如何使用靜態內部AsyncTask類

為了防止洩漏,您可以使內部類為靜態。 但是,問題在於你不再有權訪問活動的UI視圖或成員變量。 你可以傳入一個對Context的引用,但是你運行內存洩漏的風險相同。 (如果AsyncTask類有強引用,那麼Android在關閉後無法收集活動。)解決方案是對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教程仍然沒有涉及它(參見herehere ,以及here )。
  • 如果你的AsyncTask是一個頂級的類,你也會遵循一個類似的過程。 靜態內部類與Java中的頂級類基本相同。
  • 如果您不需要活動本身,但仍需要上下文(例如,顯示Toast ),則可以傳遞對應用上下文的引用。 在這種情況下, AsyncTask構造函數看起來像這樣:

    private WeakReference<Application> appReference;
    
    MyTask(Application context) {
        appReference = new WeakReference<>(context);
    }
    
  • 有一些觀點忽略了這個警告,只是使用非靜態類。 畢竟,AsyncTask的使用壽命非常短(最長時間為幾秒),並且無論如何都會釋放對Activity的引用。 看到thisthis
  • 優秀的文章: androiddesignpatterns.com/2013/01/…
Question

我在我的代碼中發出警告,指出:

這個AsyncTask類應該是靜態的或者可能發生洩漏(anonymous android.os.AsyncTask)

完整的警告是:

這個AsyncTask類應該是靜態的或者可能發生洩漏(anonymous 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();

我該如何糾正?