Android UI线程消息队列调度顺序

时间:2013-11-13 20:58:40

标签: android android-asynctask

在Android中使用retain Fragments在配置更改期间保存AsyncTask时,我认为这是最好的方法,我脑海中出现了一些关于UI Thread的Message Queue调用顺序的疑问。

例: 想象一下这种情况:

  1. 发生配置更改,用户旋转设备。 AsyncTask正在运行。
  2. 称为片段onDetach()
  3. AsyncTask doInBackground()方法完成
  4. AsyncTask onPostExecute()被称为
  5. 称为片段onAttach()
  6. UI线程消息队列也可以这样:

      

    队列顶部 - > onDetach()| onPostExecute()| onAttach()

    我知道它不能,对onPostExecute()的调用将等到配置更改完成后,据我所知,但这是如何工作的?来自活动,碎片生命周期的调用是否连续执行?

2 个答案:

答案 0 :(得分:114)

在配置更改期间,onPostExecute()Fragment#onDetach()之间无法调用Fragment#onAttach()。这种说法背后的原因有三个:

  1. 配置更改在主线程的消息队列中的单个消息内处理。

  2. 只要doInBackground()方法返回,AsyncTask就会通过向主线程的消息队列发送消息来调度主线程上调用的onPostExecute()方法。

  3. 配置更改的消息将包含将调用ActivityFragment生命周期方法(例如onDetach()onAttach())的代码。 AsyncTask的消息将包含将调用onPostExecute()方法的代码。由于主线程按顺序处理其消息队列中的消息,因此两条消息不可能同时执行,因此在onPostExecute()和{onDetach()的调用之间永远不能调用onAttach() {{1}} {1}}。

  4. this thread中阅读我对Doug Stevenson的回复,以获得更详细的解释(包括证明索赔的源代码的链接)。

答案 1 :(得分:0)

我编写了一个简单的测试,以查看保留的AsyncTaskFragment的生命周期。 它可以确认@Alex Lockwood的答案是正确的。 因此可以肯定地说,保留的AsyncTask中的Fragment是最佳实践。 Google应该将此方法纳入其官方文档中。

public class RecordDataFragment extends Fragment {
    public static boolean detach = false;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Timber.d("retain, onAttach");
        detach = false;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Timber.d("retain, onDetach");
        detach = true;
    }

    public static class TestTask extends AsyncTask<String, Void, Void> {

        protected Void doInBackground(String... username) {

            Timber.d("retain, looping.");

            while(!detach){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            Timber.d("retain, exit looping.");

            return null;
        }

        protected void onPostExecute(Void nothing) {
            Timber.d("retain, onPostExecute");
        }
    }
}

public class RecordFragment extends Fragment {

    static boolean called = false;

    @Override
    public void onResume() {
        super.onResume();
        Timber.d("retain, onResume");

        if(!called) {
            new RecordDataFragment.TestTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
            called = true;
        }

    }
}

2019-11-22 12:28:55.503 D/RecordDataFragment: retain, onAttach
2019-11-22 12:32:00.263 D/RecordFragment: retain, onViewStateRestored
2019-11-22 12:32:03.538 D/RecordFragment: retain, onResume
2019-11-22 12:32:03.544 D/RecordDataFragment$TestTask: retain, looping.
2019-11-22 12:32:07.273 D/RecordDataFragment: retain, onDetach
2019-11-22 12:32:07.297 D/RecordDataFragment$TestTask: retain, exit looping.
2019-11-22 12:32:07.403 D/RecordFragment: retain, onDestroy
2019-11-22 12:32:07.566 D/RecordDataFragment: retain, onAttach
2019-11-22 12:32:08.621 D/RecordFragment: retain, onViewStateRestored
2019-11-22 12:32:08.870 D/RecordFragment: retain, onResume
2019-11-22 12:32:09.663 D/RecordDataFragment$TestTask: retain, onPostExecute