在setRetainInstance设置为true的片段上调用findFragmentByTag时,不会返回相同的实例

时间:2015-06-01 16:29:54

标签: android android-fragments android-asynctask

我有一个包含两个片段的活动应用程序:

  1. 包含所有UI的片段;
  2. 没有视图的片段,其成员AsyncTasksetRetainInstance设置为true。
  3. 目标是在活动被破坏后保持AsyncTask运行,并在应用程序重新聚焦时重用它。

    我没有使用setTargetFragment,片段之间的所有通信都是通过MainActivity完成的。

    我认为setRetainInstance所做的是阻止重新创建片段并保持完全相同的实例,所以当我在重新创建被破坏的活动时调用findFragmentByTag时,它应该返回相同的保留实例,因为它创建时,但似乎并非如此。

    结果是我最终得到了一个在后台继续计数的noUi片段(我可以在调试器中看到这个混蛋),另一个,重新创建了一个没有对我运行的AsyncTask的引用...... < / p>

    我做错了什么?

    以下是一些代码:

    public class MainActivity extends Activity
    implements FragmentCounter.Callback, FragmentMainScreen.Callback {
    
    private static final String TAG_MAINFRAGMENT = "TAG_MAINFRAGMENT";
    private static final String TAG_COUNTERFRAGMENT = "TAG_COUNTERFRAGMENT";
    private FragmentMainScreen mFragmentMain;
    private FragmentCounter mFragmentCounter;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        if (savedInstanceState == null) {
            mFragmentMain = FragmentMainScreen.getInstance();
            mFragmentCounter = FragmentCounter.getInstance();
            getFragmentManager().beginTransaction()
                .add(R.id.container, mFragmentMain, TAG_MAINFRAGMENT)
                .add(mFragmentCounter, TAG_COUNTERFRAGMENT)
                .commit();
        } else {
            mFragmentMain = (FragmentMainScreen) getFragmentManager()
                .findFragmentByTag(TAG_MAINFRAGMENT);
     //The fragment that gets returned here is not the same instance as the one
     //I returned with getInstance() above.
            mFragmentCounter = (FragmentCounter) getFragmentManager()
                    .findFragmentByTag(TAG_COUNTERFRAGMENT);
        }
    }
    }
    

    noGui片段:

    public class FragmentCounter extends Fragment
    implements CounterAsyncTask.Callback, FragmentMainScreen.Callback {
    
    private Callback mListener;
    
    private CounterAsyncTask mCounterTask;
    
    public static FragmentCounter getInstance(){
        return new FragmentCounter();
    }
    
    public interface Callback {
        public void onData(int aValue);
    }
    
    @Override
    public void onAttach(Activity activity){
        super.onAttach(activity);
        if (activity instanceof Callback)
            mListener = (Callback) activity;
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        return null;
    }
    
    @Override
    public void onValueChanged(int value) {
    //In the debugger, I can see this callback beeing called,
    //even after my activity gets destroyed.
    //The mListener is null since I set it that way in the onDetach to
    //prevent memory leaks.
    //The new activity has a different instance of this Fragment.
        if (mListener != null)
            mListener.onData(value);
    }
    
    @Override
    public void startCounting(int from) {
        mCounterTask = new CounterAsyncTask(this);
        mCounterTask.execute(from);
    }
    
    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }
    }
    

    AsyncTask:

    public class CounterAsyncTask extends AsyncTask<Integer, Integer, Void>{
    
    private int counter;
    private Callback mListener;
    private static final int SKIP = 5000;
    
    public CounterAsyncTask(Callback listener) {
        mListener = listener;
    }
    
    @Override
    protected Void doInBackground(Integer...values) {
        if (values != null)
            counter = values[0];
        while(!this.isCancelled()){
            publishProgress(counter+=SKIP);
            try{
                Thread.sleep(SKIP);
            }
            catch(InterruptedException e){
                e.printStackTrace();
            }
        }
        return null;
    }
    
    @Override
    protected void onProgressUpdate(Integer... values) {
        mListener.onValueChanged(values[0]);
    }
    
    public interface Callback{
        public void onValueChanged(int value);
    }
    }
    

    提前致谢!

1 个答案:

答案 0 :(得分:0)

我的错误。使用setRetainInstance,片段在配置更改时仅保留 。因此片段状态将在屏幕旋转时保持,或者如果活动在后台,则,如果活动被破坏。

为了达到我想要的结果,我应该使用服务。