Ho questo strano problema in cui il mio frammento di lista viene creato due volte, una volta quando il super.oncreate viene chiamato sull'attività padre e una volta quando viene chiamato setContentView sulla stessa attività principale. È una semplice applicazione in cui utilizzo layout diversi per orientamento verticale e orizzontale.frammento Android creato due volte sul cambiamento di orientamento
Qui è l'attività principale:
private HeadlinesFragment headlines;
@Override
public void onCreate(Bundle savedInstanceState) {
Log.w("MainActivity", "Before super.onCreate: " + this.toString());
super.onCreate(savedInstanceState);
Log.w("MainActivity", "Before setContentView: " + this.toString());
setContentView(R.layout.news_articles);
//check to see if its portrait
if (findViewById(R.id.fragment_container) != null) {
if(getSupportFragmentManager().findFragmentById(R.id.fragment_container) == null) {
headlines = new HeadlinesFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, headlines).commit();
}
}
}
Ecco l'news_articles nella cartella di layout-terra:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.example.android.fragments.HeadlinesFragment"
android:id="@+id/headlines_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.android.fragments.ArticleFragment"
android:id="@+id/article_fragment"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
Ecco l'news_articles nella cartella di layout (per l'orientamento verticale)
<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" />
qui è il thats headlinesfragment state create due volte
public class HeadlinesFragment extends ListFragment {
OnHeadlineSelectedListener mCallback;
// The container Activity must implement this interface so the frag can deliver messages
public interface OnHeadlineSelectedListener {
/** Called by HeadlinesFragment when a list item is selected */
public void onArticleSelected(int position);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.w("HeadlinesFragment", "inside onCreate: " + this.toString());
// We need to use a different list item layout for devices older than 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;
// Create an array adapter for the list view, using the Ipsum headlines array
setListAdapter(new ArrayAdapter<String>(getActivity(), layout, Ipsum.Headlines));
}
@Override
public void onStart() {
super.onStart();
// When in landscape layout, set the listview to highlight the selected list item
// (We do this during onStart because at the point the listview is available.)
if (getFragmentManager().findFragmentById(R.id.article_fragment) != null) {
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception.
try {
mCallback = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// TODO Auto-generated method stub
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public void onDestroy() {
Log.w("HeadlinesFragment", "inside onDestroy: " + this.toString());
super.onDestroy();
}
}
Ecco l'articlefragment
public class ArticleFragment extends Fragment {
final static String ARG_POSITION = "position";
int mCurrentPosition = 0;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.w("ArticleFragment", "inside onCreateView: " + this.toString());
if (savedInstanceState != null) {
mCurrentPosition = savedInstanceState.getInt(ARG_POSITION);
}
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.article_view, container, false);
return view;
}
@Override
public void onStart() {
super.onStart();
Bundle args = getArguments();
if (args != null) {
// Set article based on argument passed in
updateArticleView(args.getInt(ARG_POSITION));
} else if (mCurrentPosition != -1) {
// Set article based on saved instance state defined during onCreateView
updateArticleView(mCurrentPosition);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save the current article selection in case we need to recreate the fragment
outState.putInt(ARG_POSITION, mCurrentPosition);
}
@Override
public void onDestroy() {
Log.w("ArticleFragment", "inside onDestroy: " + this.toString());
super.onDestroy();
}
}
Il problema in dettaglio è questo:
1) avviare l'applicazione in orientamento verticale 2) viene chiamato setContentView e caricato news_articles ma è quello con il frag ment_container. Viene creato 3) headlinesfragment // finora comportamento normale 4) modifica orientamento orizzontale 5) mainActivity viene distrutto -> headlinefragment viene distrutto 6) super.onCreate su mainactivity è chiamato 7) Headlinefragment viene creato 8) setContentView su mainactivity è chiamato 9) viene creato un altro headlinefragment // problema
ho inserito i registri come si può vedere nel codice sopra e qui è l'uscita quando avvio l'app in modalità verticale e passo in orizzontale.
W/MainActivity(6925): Before super.onCreate: [email protected]8
W/MainActivity(6925): Before setContentView: [email protected]
W/HeadlinesFragment(6925): inside onCreate: HeadlinesFragment{41d8d4d8 #0 id=0x7f050001}
W/MainActivity(6925): inside onDestroy: [email protected]
W/HeadlinesFragment(6925): inside onDestroy: HeadlinesFragment{41d8d4d8 # 0id=0x7f050001}
W/MainActivity(6925): Before super.onCreate: [email protected]
W/HeadlinesFragment(6925): inside onCreate: HeadlinesFragment{41ea7290 #0 id=0x7f050001}
W/MainActivity(6925): Before setContentView: [email protected]
W/HeadlinesFragment(6925): inside onCreate: HeadlinesFragment{41eb1f30 #1 id=0x7f050002}
W/ArticleFragment(6925): inside onCreateView: ArticleFragment{41eb5f20 #2 id=0x7f050003}
Spero di essere stato chiaro con il mio codice e tronchi, mi sembra super.onCreate e setContentView sia creare un un headlinesfragment ciascuno; almeno penso.
la mia domanda è perché vengono create 2 istanze di frammenti di intestazioni e come posso evitare una situazione del genere.
molte grazie per qualsiasi aiuto per quanto riguarda questo
Grazie per la risposta, tuttavia, il problema è quando l'applicazione si trasforma in orientamento orizzontale, quindi il codice che hai dato non viene comunque eseguito. Riguardo anche al codice che hai dato, quando il primato dell'applicazione inizia in modalità verticale, l'istanza savedState è nullo e il blocco else viene eseguito così come possiamo trovare un HeadlinesFragment per tag se non dovessimo mai crearlo in primo luogo? –
Penso che la condizione dell'istruzione if sia indietro qui. Se c'è uno stato di istanza salvato, dovresti trovare il frammento esistente. Se lo stato dell'istanza salvato è nullo, è necessario creare un nuovo frammento. – Razz
@Razz è corretto. NOTA: se savedInstanceState è null, si crea un nuovo frammento, altrimenti il frammento esiste già! Quindi, basta cambiare l'istruzione if interna a if (savedInstanceState == null) –