2014-09-06 5 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); 
    } 
} 

фрагмента А

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

+0

Возможный дубликат [Фрагмент имеет цель не в фрагменте Manager после поворота экрана с сохраненным фрагментом задачи асинхронной работы] (http://stackoverflow.com/questions/25710124/fragment-has-target-not -in-fragment-manager-after-rotation-of-screen-with-retain) – blahdiblah

ответ

0

Не уверен, если это будет работать, но вы можете добавить эту строку кода:

setRetainInstance(true) 

в ваш метод onViewCreated() вашего фрагмента.

Вы также добавляете нуль в стопку в фрагменте A, что также может быть проблемой.

+0

Привет У меня есть строка setRetainInstance (true) внутри метода onCreate фрагмента Thread. Однако я стараюсь использовать onCreateView. Параметр backstack необязателен, его просто тег, который может быть нулевым, если вы этого хотите. Я не думаю, что это вызывает какие-либо проблемы, я видел, что это неверно во многих учебниках/ – user3364963

+0

Возможно, вы должны добавить эту строку ко всем своим фрагментам. И хорошо, я не знал об этом. –

Смежные вопросы