0

Я довольно новичок в андроиде, и я участвую в курсе на веб-сайте coursera. У меня есть приложение, которое нужно было работать на планшетах в двухпанельном режиме и на обычных устройствах в однопанельном режиме. В качестве одного из бонусных упражнений мне нужно было поддерживать состояние в двухпанельном режиме, когда меняется ориентация устройства (помните, какой элемент был выбран в ListFragment с левой стороны и какой текст был отображен в Fragment с правой стороны).Android создает дополнительный ListFragment с каждым изменением ориентации

В конечном итоге я сделал это упражнение, однако я заметил, что приложение не уничтожает ListFragment должным образом - смотрите журнал. Выход журнала был очищен после запуска приложения, это просто изменение ориентации.

Как вы можете видеть, фрагмент был разрушен, но затем андроид снова привязал его из ниоткуда.

Я включил только код для одностраничного кода и макета - проблема прямо там. Двухпанельная компоновка работает правильно.

02-10 07:19:20.845: I/DEBUG(1297): ListFragment onPause() 
02-10 07:19:20.845: I/DEBUG(1297): Activity onPause() 
02-10 07:19:20.855: I/DEBUG(1297): ListFragment onStop() 
02-10 07:19:20.855: I/DEBUG(1297): Activity onStop() 
02-10 07:19:20.855: I/DEBUG(1297): ListFragment onDestroyView() 
02-10 07:19:20.875: I/DEBUG(1297): ListFragment onDestroy() 
02-10 07:19:20.875: I/DEBUG(1297): ListFragment onDetach() 
02-10 07:19:20.905: I/DEBUG(1297): Activity onDestroy() 
02-10 07:19:21.115: I/DEBUG(1297): ListFragment onAttach() 
02-10 07:19:21.115: I/DEBUG(1297): ListFragment onCreate() 
02-10 07:19:21.115: I/DEBUG(1297): Activity onCreate() 
02-10 07:19:21.315: I/DEBUG(1297): ListFragment onCreateView() 
02-10 07:19:21.455: I/DEBUG(1297): ListFragment onActivityCreated() 
02-10 07:19:21.466: I/DEBUG(1297): ListFragment onAttach() 
02-10 07:19:21.466: I/DEBUG(1297): ListFragment onCreate() 
02-10 07:19:21.466: I/DEBUG(1297): ListFragment onCreateView() 
02-10 07:19:21.535: I/DEBUG(1297): ListFragment onActivityCreated() 
02-10 07:19:21.535: I/DEBUG(1297): Activity onStart() 
02-10 07:19:21.535: I/DEBUG(1297): ListFragment onStart() 
02-10 07:19:21.535: I/DEBUG(1297): ListFragment onStart() 
02-10 07:19:21.555: I/DEBUG(1297): Activity onResum() 
02-10 07:19:21.555: I/DEBUG(1297): ListFragment onResume() 
02-10 07:19:21.555: I/DEBUG(1297): ListFragment onResume() 

MainActivity.java

public class MainActivity extends Activity implements 
     FriendsFragment.SelectionListener { 

    private static final String TAG = "Lab-Fragments"; 
    private static final String DEBUG = "DEBUG"; 
    private static final String STRING_DEBUG = "Activity "; 

    private FriendsFragment mFriendsFragment; 
    private FeedFragment mFeedFragment; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Log.i(DEBUG, STRING_DEBUG + "onCreate()"); 
     setContentView(R.layout.main_activity); 
     // If the layout is single-pane, create the FriendsFragment 
     // and add it to the Activity 

     if (!isInTwoPaneMode()) {   

      if (mFriendsFragment == null) {//TO REMOVE 
       mFriendsFragment = new FriendsFragment(); 
      } 

      //TODO 1 - add the FriendsFragment to the fragment_container 
      FragmentTransaction transaction = getFragmentManager().beginTransaction(); 
      transaction.add(R.id.fragment_container, mFriendsFragment); 
      transaction.commit();  

     } else { 

      // Otherwise, save a reference to the FeedFragment for later use 
      mFeedFragment = (FeedFragment) getFragmentManager().findFragmentById(R.id.feed_frag); 
     } 
    } 

    // If there is no fragment_container ID, then the application is in 
    // two-pane mode 

    private boolean isInTwoPaneMode() { 
     return findViewById(R.id.fragment_container) == null; 
    } 

    // Display selected Twitter feed 

    public void onItemSelected(int position) { 

     Log.i(TAG, "Entered onItemSelected(" + position + ")"); 

     // If there is no FeedFragment instance, then create one 

     if (mFeedFragment == null) 
      mFeedFragment = new FeedFragment(); 

     // If in single-pane mode, replace single visible Fragment 

     if (!isInTwoPaneMode()) { 

      //TODO 2 - replace the fragment_container with the FeedFragment 
      FragmentTransaction transaction = getFragmentManager().beginTransaction(); 
      transaction.replace(R.id.fragment_container, mFeedFragment); 
      transaction.addToBackStack(null); 
      transaction.commit(); 
      // execute transaction now 
      getFragmentManager().executePendingTransactions(); 
     } 

     // Update Twitter feed display on FriendFragment 
     mFeedFragment.updateFeedDisplay(position); 

    } 

    @Override 
    public void onStart() { 
     super.onStart(); 
     Log.i(DEBUG, STRING_DEBUG + "onStart()"); 
    } 

    @Override 
    public void onResume() { 
     super.onResume(); 
     Log.i(DEBUG, STRING_DEBUG + "onResum()"); 
    } 

    @Override 
    public void onPause() { 
     super.onPause(); 
     Log.i(DEBUG, STRING_DEBUG + "onPause()"); 
    } 

    @Override 
    public void onStop() { 
     super.onStop(); 
     Log.i(DEBUG, STRING_DEBUG + "onStop()"); 
    } 

    public void onRestart() { 
     super.onRestart(); 
     Log.i(DEBUG, STRING_DEBUG + "onRestart()"); 
    } 

    @Override 
    public void onDestroy() { 
     super.onDestroy(); 
     Log.i(DEBUG, STRING_DEBUG + "onDestroy()"); 
    } 
} 

ListFragment.java // FriendsFragment

public class FriendsFragment extends ListFragment { 

    private static final String[] FRIENDS = { "ladygaga", "msrebeccablack", "taylorswift13" }; 
    private static final String TAG = "Lab-Fragments"; 
    private static final String DEBUG = "DEBUG"; 
    private static final String STRING_DEBUG = "ListFragment "; 
    private int currentIndex = -1; 

    public interface SelectionListener { 
     public void onItemSelected(int position); 
    } 

    private SelectionListener mCallback; 

    @Override 
    public void onAttach(Activity activity) { 
     super.onAttach(activity); 
     Log.i(DEBUG, STRING_DEBUG + "onAttach()"); 
     // Make sure that the hosting Activity has implemented 
     // the SelectionListener callback interface. We need this 
     // because when an item in this ListFragment is selected, 
     // the hosting Activity's onItemSelected() method will be called.  
     try { 
      mCallback = (SelectionListener) activity; 
     } catch (ClassCastException e) { 
      throw new ClassCastException(activity.toString() 
        + " must implement SelectionListener"); 
     } 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Log.i(DEBUG, STRING_DEBUG + "onCreate()"); 
     // use different layout definition, depending on whether device is pre- 
     // or post-honeycomb 
     int layout = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB 
       ? android.R.layout.simple_list_item_activated_1 
       : android.R.layout.simple_list_item_1; 

     // Set the list adapter for this ListFragment 
     setListAdapter(new ArrayAdapter<String>(getActivity(), layout, FRIENDS)); 

     if (isInTwoPaneMode()) { 
      setRetainInstance(true); 
     } 
    } 

    // Note: ListFragments come with a default onCreateView() method. 
    // For other Fragments you'll normally implement this method. 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
     Bundle savedInstanceState) { 
     Log.i(DEBUG, STRING_DEBUG + "onCreateView()"); 
     return super.onCreateView(inflater, container, savedInstanceState); 
    } 


    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
     Log.i(DEBUG, STRING_DEBUG + "onActivityCreated()"); 
     Log.i(TAG, "Entered onActivityCreated()"); 
     // When using two-pane layout, configure the ListView to highlight the 
     // selected list item 

     if (isInTwoPaneMode()) { 
      getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); 
     } 

     if (isInTwoPaneMode() && -1 != currentIndex) { 
      getListView().setItemChecked(currentIndex, true); 
     } 
    } 

    @Override 
    public void onStart() { 
     super.onStart(); 
     Log.i(DEBUG, STRING_DEBUG + "onStart()"); 
    } 

    @Override 
    public void onResume() { 
     super.onResume(); 
     Log.i(DEBUG, STRING_DEBUG + "onResume()"); 
    } 

    @Override 
    public void onPause() { 
     super.onPause(); 
     Log.i(DEBUG, STRING_DEBUG + "onPause()"); 
    } 

    public void onStop() { 
     super.onStop(); 
     Log.i(DEBUG, STRING_DEBUG + "onStop()"); 
    } 

    public void onDestroyView() { 
     super.onDestroyView(); 
     Log.i(DEBUG, STRING_DEBUG + "onDestroyView()"); 
    } 

    public void onDestroy() { 
     super.onDestroy(); 
     Log.i(DEBUG, STRING_DEBUG + "onDestroy()"); 
    } 

    public void onDetach() { 
     super.onDetach(); 
     Log.i(DEBUG, STRING_DEBUG + "onDetach()"); 
    } 

    @Override 
    public void onListItemClick(ListView l, View view, int position, long id) { 
     // Notify the hosting Activity that a selection has been made. 
     currentIndex = position; 
     mCallback.onItemSelected(position); 
    } 

    // If there is a FeedFragment, then the layout is two-pane 
    private boolean isInTwoPaneMode() { 
     return getFragmentManager().findFragmentById(R.id.feed_frag) != null; 
    } 
} 

Фрагмент // QuoteFragment // DisplayFragment

package course.labs.fragmentslab; 

import android.app.Activity; 
import android.app.Fragment; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.TextView; 

public class FeedFragment extends Fragment { 

    private static final String TAG = "Lab-Fragments"; 

    private TextView mTextView; 
    private static FeedFragmentData feedFragmentData; 

    private static final String DEBUG = "DEBUG"; 
    private static final String STRING_DEBUG = "Fragment "; 

    //Index of current selected item to display in FeedFragment 
    private int currentIndex = -1; 

    @Override 
    public void onAttach(Activity activity) { 
     super.onAttach(activity); 
     Log.i(DEBUG, STRING_DEBUG + "onAttach()"); 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Log.i(DEBUG, STRING_DEBUG + "onCreate()"); 
     if (isInTwoPaneMode()) { 
      setRetainInstance(true); 
     } 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     Log.i(DEBUG, STRING_DEBUG + "onCreateView()"); 
     return inflater.inflate(R.layout.feed, container, false); 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
     Log.i(DEBUG, STRING_DEBUG + "onActivityCreated()"); 
     mTextView = (TextView) getView().findViewById(R.id.feed_view); 
     // Read in all Twitter feeds 
     if (null == feedFragmentData) { 

      feedFragmentData = new FeedFragmentData(getActivity()); 

     }  
     Log.d("DEBUG", "Index = " + currentIndex); 
     if (-1 != currentIndex) { 
      updateFeedDisplay(currentIndex); 
     } 

    } 


    // Display Twitter feed for selected feed 
    void updateFeedDisplay(int position) { 
     Log.i(TAG, "Entered updateFeedDisplay()"); 
     currentIndex = position; 
     mTextView.setText(feedFragmentData.getFeed(position)); 
    } 

    // If there is a FeedFragment, then the layout is two-pane 
    private boolean isInTwoPaneMode() { 
     return getFragmentManager().findFragmentById(R.id.feed_frag) != null; 
    } 

    @Override 
    public void onStart() { 
     super.onStart(); 
     Log.i(DEBUG, STRING_DEBUG + "onStart()"); 
    } 

    @Override 
    public void onResume() { 
     super.onResume(); 
     Log.i(DEBUG, STRING_DEBUG + "onResume()"); 
    } 

    @Override 
    public void onPause() { 
     super.onPause(); 
     Log.i(DEBUG, STRING_DEBUG + "onPause()"); 
    } 

    public void onStop() { 
     super.onStop(); 
     Log.i(DEBUG, STRING_DEBUG + "onStop()"); 
    } 

    public void onDestroyView() { 
     super.onDestroyView(); 
     Log.i(DEBUG, STRING_DEBUG + "onDestroyView()"); 
    } 

    public void onDestroy() { 
     super.onDestroy(); 
     Log.i(DEBUG, STRING_DEBUG + "onDestroy()"); 
    } 

    public void onDetach() { 
     super.onDetach(); 
     Log.i(DEBUG, STRING_DEBUG + "onDetach()"); 
    } 

} 

main_activity.xml

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/fragment_container" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" /> 

feed.xml

<TextView 
    android:id="@+id/feed_view" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/greeting" /> 

+0

хороший фон, если нужно .. http://stackoverflow.com/questions/12529499/problems-with-android-fragment-back-stack/14295368#14295368 –

ответ

1

В onCreate методе вашего фрагмента активности вы можете проверить, если savedInstanceState == null и создать и добавить свой фрагмент, только если это условие верно. В противном случае Android автоматически добавит существующий фрагмент. Я предлагаю следующий код:

... 
if (!isInTwoPaneMode()) {   
    if (savedInstanceState == null) { 
     mFriendsFragment = new FriendsFragment(); 
     FragmentTransaction transaction = getFragmentManager().beginTransaction(); 
     transaction.add(R.id.fragment_container, mFriendsFragment); 
     transaction.commit();  
    } 
} 
... 
+0

спасибо! Однако что, если я хотел бы сохранить что-то в 'Bundle' перед уничтожением активности, а затем восстановить его в' onCreate() '? Он снова запустит этот код, или мне не хватает чего-то о жизненном цикле :)? – ashur

0

Если вы просто изменить ориентацию, onDestroy() не будет называться. Он вызывается только тогда, когда Android уничтожает приложение (чтобы очистить память для других целей).

Таким образом, если вы переключите ориентацию, старые данные не будут очищены, но на каждой ориентации будет называться onCreate(). Таким образом, вы получаете двойные данные и объекты и т. Д.

Надеюсь, это может вам это объяснить.

К сожалению, я не получил никакого решения :(

Вы должны использовать onPause(), чтобы справиться с этим, на мой взгляд. onStop() также не является хорошим выбором

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

  • Нет связанных вопросов^_^