在无头片段

时间:2016-05-16 08:26:01

标签: android android-fragments android-activity android-asynctask

我已经读过在AsyncTask中执行Activity的缺点是该任务无法很好地应对配置更改,因为AsyncTask的生命周期并未受到限制在Activity生命周期。因此,如果任务应更新活动的UI,但同时Activity因配置更改而被销毁,则AsyncTask不知道新创建的Activity的任何内容因此它没有机会更新它。这也可能导致内存泄漏。

解决方法建议使用无头FragmentFragment没有UI),只是为了执行AsyncTask,因为它可以在配置更改后继续存在。我不理解,它是如何成为一种可行的方法,因为Activity及其观点在任何情况下都已被破坏。例如:

  public MyFragment extends Fragment {
        private SomeAsync myAsync = new SomeAsync();
        private WeakReference<View> someActivityView;

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

        public void setActivityView(View View) {
            someActivityView = new WeakReference<View>(view);
        } 

        ...

        class SomeAsync extends AsyncTask<Void, Integer, Object> {

        protected Object doInBackground(Void... args) {
         ...
        }

        protected void onPostExecute(Object result) {
             doUpdate(someActivityView, result);
         }

         }
       }

someActivityView是属于View的{​​{1}},并且设置为要更新的Activity。 我认为在Fragment再次创建时配置发生变化时不会保留someActivityView,因此在这种情况下使用无头Activity有什么好处?

1 个答案:

答案 0 :(得分:2)

是的,你读到的关于AsyncTask的内容是真的,是的viewLess片段是一种解决方法。

使用片段做一些事情的一般想法是,它可以访问当前活动活动中的任何活动。这样,您不应使用public void setActivityView(View View) {存储实际视图,而应仅存储此视图的 id ,并在需要时在活动中找到它。

我会复制你的代码并在其上更改一些内容以显示结果。但还有其他方法可以做到这一点。我最后会简要地谈谈它们。

  public MyFragment extends Fragment {
        private SomeAsync myAsync = new SomeAsync();
        private int viewId = -1;

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

            // restore the view id
            if(savedInstanceState != null && savedInstanceState.containsKey("myViewId")){
                  viewId = savedInstanceState.getInt("myViewId");
            }
        }

        @Override
        public void onSaveInstanceState (Bundle outState) {
             super.onSaveInstanceState(outState);
             // save the view ID
             if(viewId > 0) {
                outState.putInt("myViewId", viewId);
             }
        }

        public void setActivityView(View View) {
            viewId = view.getId();
        } 

        ...

        class SomeAsync extends AsyncTask<Void, Integer, Object> {

        protected Object doInBackground(Void... args) {
         ...
        }

        protected void onPostExecute(Object result) {
             Activity activity = getActivity();
             if(viewId > 0 && activity != null) {
                 View view = activity.findViewById(viewId);
                 doUpdate(view, result);
             }
         }

         }
       }

是的,有必要保存ID,因为还有其他原因导致您的活动被杀死(例如,进入后台并且系统内存不足);

<强>备选方案:

  1. 将视图ID直接放入片段setArguments(bundle)
  2. 使活动实现与接收AsyncTask的方法的接口。然后onPostExecute调用getActivity,投射到此界面并将结果直接传递给活动。
  3. (替代方案是我最喜欢的,因为它是最干净的):不要使用AsyncTask,也不要将处理结果与UI组件联系在一起。使用数据,处理和UI分离创建适当的结构。 UI元素应仅基于对数据元素的订阅进行更新。有几种模式可以帮助分离责任人。选择MVP,MVC,MVVM等。