在 activity 中使用嵌套的 AsycTask 时,处理程序引用将在 onDestroy 之后保留

When using nested AsycTask in activity will handler reference remain after onDestroy

我有示例代码,它非常简单地完成一些繁重的工作并向处理程序发送消息以更新 UIThread。我关心的是我传递给构造函数的处理程序引用。如果我的 activity 在 asncTask 仍为 运行 时被销毁,处理程序引用是否会为空?

    public class SomeActivity extends Activity
{
    private static final int UPDATE_BUTTON_TEXT = 1;
    private static final SomeActivity me = null;

    private static Handler handler = new Handler() { 
        public void handleMessage(Message msg)  {
          if (me == null) return;

          switch (msg.what)  {
            case UPDATE_BUTTON_TEXT:
              Button btn = (Button) me.findViewById(R.id.someButton);
              btn.setText((String) msg.obj);
          }
        }
    };

    private View.OnClickListener onClickListener = new View.OnClickListener() {
       public void onClick(View view) {
            new SomeLongRunningTask().execute();
        }
    };

    private static class SomeLongRunningTask extends AsyncTask<Void, Void, Boolean> {

        private Handler handler;

        public SomeLongRunningTask(Handler handler)  {
            this.handler = handler;
        }

        @Override
        protected Boolean doInBackground(Void... voids) {

            try {
                Thread.sleep(30000); // replace with some background logic
            } catch (InterruptedException e) {}

            return true;
        }



          @Override
            protected void onPostExecute(Boolean aBoolean) {
//can the handler be null here if activity is destroyed ????
                Message msg = handler.obtainMessage(UPDATE_BUTTON_TEXT);
                msg.obj = "success"
                handler.sendMessage(msg);
            }
        }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        final Button someButton = (Button) findViewById(R.id.someButton);
        someButton.setOnClickListener(onClickListener);
    }

    @Override
    protected void onStart() {
        super.onStart();

        me = this;
    }

    @Override
    protected void onStop() {
        me = null;

        super.onStop();
    }
}

是的,处理程序的引用将保留在内存中,直到它的引用计数 > 0。

我认为您应该使用 AsyncTask().onProgressUpdate 来更新 UI 上的进度,这正是您想要做的。

编辑

如果你在 onPostExecute 中更新 ui 那么你不需要使用 onProgressUpdate(抱歉)。

只需使用接口作为回调函数,如下所示:

private interface Callback {
    void updateUI(String value);
}

private static class SomeLongRunningTask extends AsyncTask<Void, String, Boolean> {
    private Callback mCallback;

    public SomeLongRunningTask(Callback callback)  {
        mCallback = callback;
    }

    @Override
    protected void onPostExecute(Boolean aBoolean) {
        mCallback.updateUI("success");
    }
}

// somewhere else...
Callback callback = new Callback() {
    @Override
    public void updateUI(String value) {
        Button btn = (Button) me.findViewById(R.id.someButton);
        btn.setText((String) msg.obj);
    }
};

new SomeLongRunningTask(callback).execute();

另外,将处理程序实例作为静态变量似乎也不对。它将持续到 class 被卸载。

通常,每当我编写 AsyncTask 子类时,我都会使用这样的模式:

    private WeakReference<Callback> mCallbackRef;

    public MyAsyncTask(Callback callback)  {
        mCallbackRef = new WeakReference<>(callback);
    }

    @Override
    protected void onPostExecute(Boolean aBoolean) {
        if (mCallbackRef != null) {
            Callback callback = mCallbackRef.get();
            if (callback != null) {
                callback.updateUI("success");
            }
        }
    }