Miglior pratica per i frammenti nidificati in Android 4.0, 4.1 (<4.2) senza utilizzare la libreria di supporto

Sto scrivendo un'applicazione per le compresse 4.0 e 4.1, per le quali non voglio utilizzare le librerie di supporto (se non necessario) ma la 4.x api solo pertanto.

Quindi la mia piattaforma di destinazione è ben definita come:> = 4.0 e <= 4.1

  • objdump di un file .so? bisogno di aiuto per comprendere i messaggi
  • Selettore Android Disegnabile con VectorDrawables srcCompat
  • Come generare javadoc per la libreria android quando ha dependencies che sono anche biblioteche?
  • Ottenere l'errore http 407 come IOException
  • Come posso interrompere l'animation fotogramma utilizzando AnimationDrawable?
  • script di shell in android dà [: non trovato
  • L'applicazione dispone di un layout a più riframeworks (due frammenti, uno piccolo sulla sinistra, un frammento di contenuto a destra) e una barra delle azioni con tabs.

    Simile a questo:

    immettere qui la descrizione dell'immagine

    Facendo clic su una scheda sulla barra di azione, il frammento "esterno" cambia e il frammento interno è un frammento con due frammenti nidificati.

    Ora mi chiedo quale sia la pratica migliore per sostituire frammenti e frammenti particolarmente nidificati. Il ViewPager fa parte della libreria di supporto, non esiste un'alternativa 4.x nativa per questa class. Sembra essere "deprecato" nel mio senso. – http://developer.android.com/reference/android/support/v4/view/ViewPager.html

    Poi ho letto le note di rilascio per Android 4.2, riguardanti ChildFragmentManager , che sarebbe una buona misura, ma sto puntando su 4.0 e 4.1, quindi non si può usare neanche.

    ChildFragmentManager è disponibile solo in 4.2

    • http://developer.android.com/about/versions/android-4.2.html#NestedFragments
    • http://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager ()

    Purtroppo, ci sono praticamente buoni esempi là fuori che mostrano le migliori pratiche per usi di frammenti senza la libreria di supporto, anche in tutte le guide Android per gli sviluppatori; e soprattutto niente per quanto riguarda i frammenti nidificati.

    Quindi mi chiedo: non è semplicemente ansible scrivere 4.1 app con frammenti nidificati senza utilizzare la libreria di supporto e tutto ciò che viene fornito? (deve utilizzare FragmentActivity invece di frammento, ecc.) Oppure quale sarebbe la migliore pratica?


    Il problema che sto attualmente nello sviluppo è esattamente questa affermazione:

    • http://developer.android.com/about/versions/android-4.2.html#NestedFragments

    La libreria di supporto Android support anche frammenti nidificati, in modo da poter implementare disegni di frammenti nidificati su Android 1.6 e versioni successive.

    Nota: non è ansible gonfiare un layout in un frammento quando tale layout include un <fragment> . I frammenti nidificati vengono supportti solo quando vengono aggiunti dynamicmente a un frammento.

    Perché ho messo definire i frammenti nidificati in XML, che a quanto pare provoca un errore come:

     Caused by: java.lang.IllegalArgumentException: Binary XML file line #15: Duplicate id 0x7f090009, tag frgCustomerList, or parent id 0x7f090008 with another fragment for de.xyz.is.android.fragment.CustomerListFragment_ 

    Al momento, concludo per me stesso: anche su 4.1, quando non voglio nemless intendere la piattaforma 2.x, frammenti nidificati come mostrato nello screenshot non sono possibili senza la libreria di supporto.

    (Questa potrebbe essere più di una voce wiki che di una domanda, ma forse qualcun altro lo ha gestito prima).

    Aggiornare:

    Una risposta utile è a: Fragment Inside Fragment

  • Come rilevare le librerie condivise native caricate dall'applicazione Android
  • Come aggiornare la barra di progresso in un elemento di ListView
  • Cercando di build una richiesta SOAP corretta
  • Come evitare OutOfMemory ex durante la rotazione dell'image?
  • Come portre un task di background alla parte anteriore al favo?
  • come posso riprodurre due video su uno schermo?
  • 5 Solutions collect form web for “Miglior pratica per i frammenti nidificati in Android 4.0, 4.1 (<4.2) senza utilizzare la libreria di supporto”

    limitazioni

    Così i frammenti di nidificazione all'interno di un altro frammento non sono possibili con xml a prescindere da quale versione di FragmentManager si utilizza.

    Quindi devi aggiungere frammenti via codice, questo potrebbe sembrare un problema, ma a lungo termine rende i tuoi layout troppo stretti.

    Quindi, nidificando senza utilizzare getChildFragmentManger ? L'essenza dietro a childFragmentManager è che si blocca il caricamento finché la transazione di frammento precedente non è terminata. E naturalmente è supportto naturalmente solo in 4.2 o nella libreria di supporto.

    Nesting senza ChildManager – Soluzione

    Soluzione, certo! Lo sto facendo da molto tempo (dal ViewPager stato annunciato il ViewPager ).

    Vedi sotto; Questo è un Fragment che blocca il carico, in modo che i Fragment s possono essere caricati all'interno di esso.

    La sua semplicità, il Handler è una class molto efficace, in modo efficace il gestore attende uno spazio da eseguire sul thread principale dopo che la transazione di frammento attuale finisce di impegnarsi (in quanto frammenti interferiscono con l'interface utente che eseguono sul thread principale).

     // Remember this is an example, you will need to modify to work with your code private final Handler handler = new Handler(); private Runnable runPager; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) return inflater.inflate(R.layout.frag_layout, container, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); runPager = new Runnable() { @Override public void run() { getFragmentManager().beginTransaction().addFragment(R.id.frag_container, MyFragment.newInstance()).commit(); } }; handler.post(runPager); } /** * @see android.support.v4.app.Fragment#onPause() */ @Override public void onPause() { super.onPause(); handler.removeCallbacks(runPager); } 

    Non lo considero "pratica migliore", ma ho applicazioni live usando questo hack e devo ancora avere dei problemi con esso.

    Utilizzo anche questo metodo per incorporare pagine di visualizzazione – https://gist.github.com/chrisjenx/3405429

    Il modo migliore per farlo nel pre-API 17 è quello di non farlo affatto. Tentare di implementare questo comportmento causerà problemi. Tuttavia ciò non significa che non possa essere falso in modo convincente utilizzando l'attuale API 14. Quello che ho fatto è stato quanto segue:

    1 – guardare la comunicazione tra i frammenti http://developer.android.com/training/basics/fragments/communicating.html

    2 – spostare il layout xml FrameLayout dal tuo frammento esistente al layout di attività e nascondilo dando un'altezza di 0:

     <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent"> <FrameLayout android:id="@+id/content" android:layout_width="300dp" android:layout_height="match_parent" /> <FrameLayout android:id="@+id/lstResults" android:layout_width="300dp" android:layout_height="0dp" android:layout_below="@+id/content" tools:layout="@layout/treeview_list_content"/> <FrameLayout android:id="@+id/anomalies_fragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_toRightOf="@+id/content" /> 

    3 – Implementare l'interface nel frammento padre

      OnListener mCallback; // Container Activity must implement this interface public interface OnListener { public void onDoSomethingToInitChildFrame(/*parameters*/); public void showResults(); public void hideResults(); } @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 = (OnFilterAppliedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnListener"); } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mCallback.showResults(); } @Override public void onPause() { super.onPause(); mCallback.hideResults(); } public void onClickButton(View view) { // do click action here mCallback.onDoSomethingToInitChildFrame(/*parameters*/); } 

    4 – Implementare l'interface nell'attività principale

    class pubblica YourActivity estende Activity triggers yourParentFragment.OnListener {

     public void onDoSomethingToInitChildFrame(/*parameters*/) { FragmentTransaction ft = getFragmentManager().beginTransaction(); Fragment childFragment = getFragmentManager().findFragmentByTag("Results"); if(childFragment == null) { childFragment = new yourChildFragment(/*parameters*/); ft.add(R.id.lstResults, childFragment, "Results"); } else { ft.detach(childFragment); ((yourChildFragment)childFragment).ResetContent(/*parameters*/); ft.attach(childFragment); } ft.commit(); showResultsPane(); } public void showResults() { FragmentTransaction ft = getFragmentManager().beginTransaction(); Fragment childFragment = getFragmentManager().findFragmentByTag("Results"); if(childFragment != null) ft.attach(childFragment); ft.commit(); showResultsPane(); } public void showResultsPane() { //resize the elements to show the results pane findViewById(R.id.content).getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; findViewById(R.id.lstResults).getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; } public void hideResults() { //resize the elements to hide the results pane findViewById(R.id.content).getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT; findViewById(R.id.lstResults).getLayoutParams().height = 0; FragmentTransaction ft = getFragmentManager().beginTransaction(); Fragment childFragment = getFragmentManager().findFragmentByTag("Results"); if(childFragment != null) ft.detach(childFragment); ft.commit(); } 

    }

    5 – Godetevi, con questo metodo si ottiene la stessa funzionalità di fluido come con la function getChildFragmentManager () in un pre-API 17 envoronment. Come si può notare che il frammento del figlio non è più veramente un figlio del frammento genitore ma ora figlio dell'attività, questo non può essere evitato.

    Ho dovuto affrontare questo esatto problema a causa di una combinazione di NavigationDrawer, TabHost e ViewPager che hanno avuto complicazioni con l'utilizzo della libreria di supporto a causa di TabHost. E poi ho anche dovuto sostenere min API di JellyBean 4.1, quindi utilizzando frammenti nidificati con getChildFragmentManager non era un'opzione.

    Quindi il mio problema può essere distillato …

      TabHost (per il livello superiore)
     + ViewPager (per solo uno dei frammenti di tabulazione di livello superiore)
     = necessità di frammenti nidificati (che JellyBean 4.1 non supporterà) 

    La mia soluzione era quella di creare l'illusione di frammenti nidificati senza effettivamente annidare frammenti. Ho fatto questo avendo l'attività principale utilizzare TabHost AND ViewPager per gestire due viste di fratello, la cui visibilità è gestita selezionando layout_weight tra 0 e 1.

     //Hide the fragment used by TabHost by setting height and weight to 0 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 0); mTabHostedView.setLayoutParams(lp); //Show the fragment used by ViewPager by setting height to 0 but weight to 1 lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 1); mPagedView.setLayoutParams(lp); 

    Questo ha reso efficace il mio falso "Frammento Nidificato" per funzionare come una visualizzazione indipendente finché ho gestito manualmente i pesi di layout rilevanti.

    Ecco il mio activity_main.xml:

     <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.ringofblades.stackoverflow.app.MainActivity"> <TabHost android:id="@android:id/tabhost" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@android:id/tabcontent" android:background="@drawable/background_image" android:layout_width="match_parent" android:layout_weight="0.5" android:layout_height="0dp"/> <android.support.v4.view.ViewPager xmlns:tools="http://schemas.android.com/tools" android:id="@+id/pager" android:background="@drawable/background_image" android:layout_width="match_parent" android:layout_weight="0.5" android:layout_height="0dp" tools:context="com.ringofblades.stackoverflow.app.MainActivity"> <FrameLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" /> </android.support.v4.view.ViewPager> <TabWidget android:id="@android:id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> </TabHost> <fragment android:id="@+id/navigation_drawer" android:layout_width="@dimen/navigation_drawer_width" android:layout_height="match_parent" android:layout_gravity="start" android:name="com.ringofblades.stackoverflow.app.NavigationDrawerFragment" tools:layout="@layout/fragment_navigation_drawer" /> </android.support.v4.widget.DrawerLayout> 

    Si noti che "@ + id / pager" e "@ + id / container" sono fratelli con "android: layout_weight =" 0.5 "" e "android: layout_height =" 0dp "'. Questo è in modo che posso vederlo nell'anteprima per qualsiasi dimensione dello schermo. I loro pesi saranno manipolati nel codice durante il runtime, comunque.

    Basandosi su @ Chris.Jenkins rispondere, questa è la soluzione che sta funzionando bene per me, per rimuovere frammenti durante gli events del ciclo di vita (che hanno la tendenza a buttare illegalStateExceptions). Questo utilizza una combinazione dell'approccio Gestore e un controllo Activity.isFinishing () (altrimenti butterà un errore per "Imansible eseguire questa azione dopo onSaveInstanceState).

     import android.app.Activity; import android.os.Handler; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; public abstract class BaseFragment extends Fragment { private final Handler handler = new Handler(); /** * Removes the {@link Fragment} using {@link #getFragmentManager()}, wrapped in a {@link Handler} to * compensate for illegal states. * * @param fragment The {@link Fragment} to schedule for removal. */ protected void removeFragment(@Nullable final Fragment fragment) { if (fragment == null) return; final Activity activity = getActivity(); handler.post(new Runnable() { @Override public void run() { if (activity != null && !activity.isFinishing()) { getFragmentManager().beginTransaction() .remove(fragment) .commitAllowingStateLoss(); } } }); } /** * Removes each {@link Fragment} using {@link #getFragmentManager()}, wrapped in a {@link Handler} to * compensate for illegal states. * * @param fragments The {@link Fragment}s to schedule for removal. */ protected void removeFragments(final Fragment... fragments) { final FragmentManager fragmentManager = getFragmentManager(); final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); for (Fragment fragment : fragments) { if (fragment != null) { fragmentTransaction.remove(fragment); } } final Activity activity = getActivity(); handler.post(new Runnable() { @Override public void run() { if (activity != null && !activity.isFinishing()) { fragmentTransaction.commitAllowingStateLoss(); } } }); } } 

    Uso:

     class MyFragment extends Fragment { @Override public void onDestroyView() { removeFragments(mFragment1, mFragment2, mFragment3); super.onDestroyView(); } } 

    Sebbene l'OP possa avere circostanze particolari che impediscono l'utilizzo della libreria di supporto, la maggior parte della gente dovrebbe usarla. La documentazione di Android lo consiglia e renderà ansible la tua app per il più ampio pubblico ansible.

    Nella mia risposta più completa ho fatto un esempio che dimostra come utilizzare frammenti nidificati con la libreria di supporto.

    immettere qui la descrizione dell'immagine

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.