android esempio - OnCreateView chiamato più volte / Utilizzo di ActionBar e Fragments




example tutorial (3)

Ho cambiato parte della mia app da Attività a Frammenti in modo da poter utilizzare le schede ActionBar pulite.

Tuttavia, dopo aver completato la transizione mi sono imbattuto in un problema: ogni volta che passo a un'altra scheda, quel Frammento viene creato tutto da capo. Sia onCreate che onCreateView vengono richiamati ogni volta che arrivo a una scheda.

Ho 4 schede, ognuna delle quali ha lo scopo di aprire uno di questi frammenti:

Fragment ShopFragment = new WebActivity();
Fragment SearchFragment = new SearchActivity(context);
Fragment StoreFragment = new StoreLocatorActivity(context, this);
Fragment BlogsFragment = new BlogsActivity(context, this);

Ecco il mio codice per l'ascoltatore:

    class MyTabsListener implements ActionBar.TabListener {
        public Fragment fragment;

        public MyTabsListener(Fragment fragment) {
            this.fragment = fragment;
        }

        @Override
        public void onTabReselected(Tab tab, FragmentTransaction ft) {
            ft.hide(fragment);
        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            ft.replace(R.id.fragment_container, fragment);
        }

        @Override
        public void onTabUnselected(Tab tab, FragmentTransaction ft) {          

        }

    }

Qualcuno potrebbe per favore indirizzarmi nella giusta direzione?


Answers

Quando chiami FragmentTransaction.replace(...) , Android eseguirà effettivamente una sequenza di FragmentTransaction.remove(...) (per tutti i Fragments attualmente aggiunti a quel contenitore) e FragmentTransaction.add(...) (per i tuoi forniti Frammento). La rimozione di un frammento da FragmentManager causerà la distruzione del frammento e il suo stato non sarà più gestito. Più chiaramente, quando si aggiunge nuovamente il frammento, tutte le viste saranno state ripristinate. Nota: poiché si riutilizza la stessa istanza di Fragment, il Fragment manterrà comunque il valore di qualsiasi variabile di istanza.

Una soluzione a questo problema sarebbe utilizzare FragmentTransaction.detach(Fragment) e FragmentTransaction.attach(Fragment) quando si passa. Ciò causerà la ricreazione delle viste Fragment onCreateView() verrà richiamato onDestroyView() e onCreateView() ), ma il bundle dello stato dell'istanza verrà salvato e restituito onCreateView() tra le chiamate e quindi lo stato di visualizzazione può essere mantenuto. Questo è l'approccio adottato da FragmentPagerAdapter quando tenta di passare da Fragment.

In alternativa, puoi consentire che i Frammenti vengano distrutti, ma mantengono il loro stato salvato per loro in modo indipendente. Ciò userebbe meno memoria, a scapito di un tempo di commutazione più lento. I metodi di nota sarebbero FragmentManager.saveFragmentInstanceState(Fragment) e FragmentManager.setInitialSavedState(Fragment.SavedState) , in combinazione con l'aggiunta / rimozione. Questo è l'approccio adottato da FragmentStatePagerAdapter .

Puoi dare un'occhiata all'origine di FragmentPagerAdapter e dell'origine di FragmentStatePagerAdapter per i suggerimenti di implementazione.


Esiste l'opzione show / hide proprio per evitare che i frammenti vengano ridipinti / ricreati e onCreate() e onCreateView() non vengano reinvocati.


Si tratta di un bug Samsung nella loro implementazione dell'interfaccia utente di Lollipop. Colpisce Galaxy S4, S5, Nota 3 e probabilmente più dispositivi. Per noi si verifica nelle lingue de_DE e de_AT, ma sembra essere un problema che interessa più lingue.

L'ho risolto forzando i dispositivi Samsung a utilizzare il tema Holo per il selezionatore di date. Nel nostro DatePickerFragment:

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    /* calendar code here */

    Context context = getActivity();
    if (isBrokenSamsungDevice()) {
        context = new ContextThemeWrapper(getActivity(), android.R.style.Theme_Holo_Light_Dialog);
    }
    return new DatePickerDialog(context, this, year, month, day);
}

private static boolean isBrokenSamsungDevice() {
    return (Build.MANUFACTURER.equalsIgnoreCase("samsung")
            && isBetweenAndroidVersions(
            Build.VERSION_CODES.LOLLIPOP,
            Build.VERSION_CODES.LOLLIPOP_MR1));
}

private static boolean isBetweenAndroidVersions(int min, int max) {
    return Build.VERSION.SDK_INT >= min && Build.VERSION.SDK_INT <= max;
}

Grazie a Samsung, i loro utenti non riceveranno il simpatico raccoglitore di date progettato dal materiale.







android android-fragments android-activity android-actionbar