2014-09-06 47 views
0

我一直在關注如何在配置更改後將線程報告返回到新活動實例的Alex Lockwood(2013)的本教程。片段在屏幕旋轉後目標不在片段管理器中

http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html

全部是偉大的工作,直到我試圖嵌套片段內做到這一點。基本上活動添加片段A和片段A被片段B替換,片段B內部啓動一個異步任務線程。但是,如果我回到碎片A(通過backstack),然後嘗試旋轉,我會在標題中說明以下異常。

下面是代碼

主要活動

public class MainActivity extends ActionBarActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     if(savedInstanceState == null) 
     { 
      FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
      ft.add(android.R.id.content, new FragmentA()).commit(); 
     } 

    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.main, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     // Handle action bar item clicks here. The action bar will 
     // automatically handle clicks on the Home/Up button, so long 
     // as you specify a parent activity in AndroidManifest.xml. 
     int id = item.getItemId(); 
     if (id == R.id.action_settings) { 
      return true; 
     } 
     return super.onOptionsItemSelected(item); 
    } 
} 

片段A

public class FragmentA extends Fragment implements OnClickListener 
{ 

    private Button GoToFragmentB; 
    private ViewGroup container; 

    @Override 
    public View onCreateView(LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) 
    { 
    // TODO Auto-generated method stub 

    View view = inflater.inflate(R.layout.fragment_a, container, false); 
    this.container = container; 
    GoToFragmentB = (Button)view.findViewById(R.id.bGoToFragmentB); 
    GoToFragmentB.setOnClickListener(this); 
    return view; 
    } 

    @Override 
    public void onClick(View v) 
    { 
     // TODO Auto-generated method stub 
     FragmentManager fragmentManager = getFragmentManager(); 
     FragmentB fb = new FragmentB(); 
     FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 
     fragmentTransaction.replace(container.getId(), fb, FragmentB.class.getName()); 
     fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); 
     fragmentTransaction.addToBackStack(null); 
     fragmentTransaction.commit(); 
    } 

} 

片段B

public class FragmentB extends Fragment implements OnClickListener, ThreadFragment.AsyncTaskCallbacks{ 

    private ThreadFragment mThreadFragment; 
    private ProgressBar progress_horizontal; 
    private TextView percent_progress; 
    private Button task_button; 

    private static final String KEY_CURRENT_PROGRESS = "current_progress"; 
    private static final String KEY_PERCENT_PROGRESS = "percent_progress"; 


    @Override 
    public View onCreateView(LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) { 
     // TODO Auto-generated method stub 
     View view = inflater.inflate(R.layout.fragment_b, container, false); 

     progress_horizontal = (ProgressBar) view.findViewById(R.id.progress_horizontal); 
     percent_progress = (TextView)view.findViewById(R.id.percent_progress); 
     task_button = (Button)view.findViewById(R.id.task_button); 
     task_button.setOnClickListener(this); 



     return view; 
    } 


    @Override 
    public void onActivityCreated(Bundle savedInstanceState) 
    { 
     // TODO Auto-generated method stub 
     super.onActivityCreated(savedInstanceState); 

     if(savedInstanceState != null) 
     { 
      progress_horizontal.setProgress(savedInstanceState.getInt(KEY_CURRENT_PROGRESS)); 
      percent_progress.setText(savedInstanceState.getString(KEY_PERCENT_PROGRESS)); 

     } 

     FragmentManager fm = getActivity().getSupportFragmentManager(); 
     mThreadFragment = (ThreadFragment) fm.findFragmentByTag(ThreadFragment.class.getName()); 

     if(mThreadFragment == null) 
     { 
      mThreadFragment = new ThreadFragment(); 
      mThreadFragment.setTargetFragment(this, 0); 
      fm.beginTransaction().add(mThreadFragment, ThreadFragment.class.getName()).commit(); 
     } 

     if(mThreadFragment.isRunning() == true) 
     { 
      task_button.setText(getString(R.string.cancel)); 
     } 
     else 
     { 
      task_button.setText(getString(R.string.start)); 
     } 

    } 

    @Override 
    public void onSaveInstanceState(Bundle outState) { 
     // TODO Auto-generated method stub 
     super.onSaveInstanceState(outState); 
     outState.putInt(KEY_CURRENT_PROGRESS, progress_horizontal.getProgress()); 
     outState.putString(KEY_PERCENT_PROGRESS, percent_progress.getText().toString()); 

    } 

    @Override 
    public void onClick(View v) 
    { 
     // TODO Auto-generated method stub 
     if(mThreadFragment.isRunning() == true) 
     { 
      mThreadFragment.cancel(); 
     } 
     else 
     { 
      mThreadFragment.start(); 
     } 
    } 


    @Override 
    public void onPreExecute() 
    { 
     // TODO Auto-generated method stub 
     task_button.setText(getString(R.string.cancel)); 
     Toast.makeText(getActivity(), R.string.task_started_msg, Toast.LENGTH_SHORT).show(); 
    } 


    @Override 
    public void onProgressUpdate(int percent) 
    { 
     // TODO Auto-generated method stub 
     progress_horizontal.setProgress(percent * progress_horizontal.getMax()/100); 
     percent_progress.setText(percent + "%"); 
    } 


    @Override 
    public void onCancelled() 
    { 
     // TODO Auto-generated method stub 
     task_button.setText("Start"); 
     progress_horizontal.setProgress(0); 
     percent_progress.setText("0%"); 

    } 


    @Override 
    public void onPostExecute() 
    { 
     // TODO Auto-generated method stub 
     task_button.setText(getString(R.string.start)); 
     progress_horizontal.setProgress(progress_horizontal.getMax()); 
     percent_progress.setText(getString(R.string.one_hundred_percent)); 
     Toast.makeText(getActivity(), R.string.task_complete_msg, Toast.LENGTH_SHORT).show(); 

    } 

    @Override 
    public void onPause() { 
     // TODO Auto-generated method stub 
     mThreadFragment.pause(); 
     super.onPause(); 
    } 

    @Override 
    public void onResume() { 
     // TODO Auto-generated method stub 
     mThreadFragment.resume(); 
     super.onResume(); 
    } 

} 

主題片段

public class ThreadFragment extends Fragment { 


    static interface AsyncTaskCallbacks 
    { 
     void onPreExecute(); 
     void onProgressUpdate(int percent); 
     void onCancelled(); 
     void onPostExecute(); 
    } 

    private AsyncTaskCallbacks mCallback; 
    private boolean mRunning; 
    private boolean isPause; 

    private TestTask mTask; 

    @Override 
    public void onAttach(Activity activity) { 
     // TODO Auto-generated method stub 
     super.onAttach(activity); 
     if(!(getTargetFragment() instanceof AsyncTaskCallbacks)) 
     { 
      throw new IllegalStateException("Target fragment must implement the AsyncTaskCallbacks interface."); 
     } 


     if(getTargetFragment() != null) 
     { 
     mCallback = (AsyncTaskCallbacks) getTargetFragment(); 
     } 


    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     // TODO Auto-generated method stub 
     super.onCreate(savedInstanceState); 
     setRetainInstance(true); 
    } 

    @Override 
    public void onDestroy() { 
     // TODO Auto-generated method stub 
     super.onDestroy(); 
     cancel(); 

    } 

    public void start() 
    { 
     if(mRunning == false) 
     { 
      mTask = new TestTask(); 
      mTask.execute(); 
      mRunning = true; 
     } 
    } 

    public void cancel() 
    { 
     if(mRunning == true) 
     { 
      mTask.cancel(false); 
      mTask = null; 
      mRunning = false; 
      isPause = false; 
     } 
    } 

    public void pause() 
    { 
     if(mRunning == true) 
     { 
      isPause = true; 
     } 
    } 

    public void resume() 
    { 
     isPause = false; 
    } 

    public boolean isRunning() 
    { 
     return mRunning; 
    } 

    private class TestTask extends AsyncTask<Void, Integer, Void> 
    { 

     @Override 
     protected void onPreExecute() 
     { 
      // TODO Auto-generated method stub 
      mCallback.onPreExecute(); 
      mRunning = true; 
     } 

     @Override 
     protected Void doInBackground(Void... params) 
     { 


       // TODO Auto-generated method stub 
       for(int i = 0; !isCancelled() && i < 100; i++) 
       { 
        if(isPause == true) 
        { 
         sleep(); 
        } 

        SystemClock.sleep(100); 
        publishProgress(i); 
       } 



      return null; 
     } 

     @Override 
     protected void onProgressUpdate(Integer... values) { 
      // TODO Auto-generated method stub 
      mCallback.onProgressUpdate(values[0]); 
     } 

     @Override 
     protected void onCancelled() { 
      // TODO Auto-generated method stub 
      mCallback.onCancelled(); 
      mRunning = false; 
     } 

     @Override 
     protected void onPostExecute(Void result) { 
      // TODO Auto-generated method stub 
      mCallback.onPostExecute(); 
      mRunning = false; 
     } 

     private void sleep() 
     { 
      try 
      { 
       while(isPause) 
       { 
       Thread.sleep(500); 
       } 
      } 
      catch(InterruptedException e) 
      { 
       e.printStackTrace(); 
      } 
     } 


    } 



} 

我logcat的

09-06 19:49:31.068: E/AndroidRuntime(2402): FATAL EXCEPTION: main 
09-06 19:49:31.068: E/AndroidRuntime(2402): java.lang.IllegalStateException: Failure saving state: ThreadFragment{40ce2700 #2 com.ersen.asynctaskpausetest.ThreadFragment} has target not in fragment manager: FragmentB{40d3a170} 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at android.support.v4.app.FragmentManagerImpl.saveAllState(FragmentManager.java:1699) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at android.support.v4.app.FragmentActivity.onSaveInstanceState(FragmentActivity.java:547) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at android.app.Activity.performSaveInstanceState(Activity.java:1147) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1216) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3666) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at android.app.ActivityThread.access$700(ActivityThread.java:141) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1240) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at android.os.Handler.dispatchMessage(Handler.java:99) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at android.os.Looper.loop(Looper.java:137) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at android.app.ActivityThread.main(ActivityThread.java:5041) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at java.lang.reflect.Method.invokeNative(Native Method) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at java.lang.reflect.Method.invoke(Method.java:511) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 
09-06 19:49:31.068: E/AndroidRuntime(2402):  at dalvik.system.NativeStart.main(Native Method) 
+0

嗨,你有沒有找到解決方案?我有同樣的問題... – alex 2015-01-24 12:28:48

+0

可能重複的[片段目標不在片段管理器屏幕旋轉後保留的異步任務片段](http://stackoverflow.com/questions/25710124/fragment-has-target-not -in-fragment-manager-after-rotation-of-screen-with-retain) – blahdiblah 2016-08-20 00:31:10

回答

0

不知道這是否會工作,但你可能需要添加這行代碼:

setRetainInstance(true) 

在你的片段的onViewCreated()方法。

您還將零添加到片段A中的backstack,以便可能也是一個問題。

+0

您好我在線程片段的onCreate方法中有setRetainInstance(true)行。儘管我嘗試onCreateView。 backstack的參數是可選的,它只是一個標籤,如果你願意,它可以是null。我不認爲它會導致任何問題,我在許多教程中看到它爲空/ – user3364963 2014-09-07 10:18:18

+0

您應該將該行添加到所有片段中。好吧,我沒有意識到這一點。 – 2014-09-07 13:01:20

相關問題