Aggiungere Nidificati Frammento dopo Genitore Frammento di vista è già creata

Sto cercando di creare un Frammento, che dispone di un metodo pubblico per l’aggiunta di bambino Frammenti di sé.

Ho letto con potenzialmente domande simili ma non ho trovato niente per aiutare finora. Io ho ridotto il problema con un semplice test app mostrato di seguito.

Una volta fragA è stato aggiunto al layout, che io chiamo il metodo pubblico fragA.addFragB() di ottenere per aggiungere un’istanza di FragmentClassB a se stesso, ma in questo modo, l’applicazione per la prova di crash, che indica “l’Attività è stata distrutta” (vedi LogCat alla fine del post). Questo significa fragA è stato distrutto, quindi non posso aggiungere fragB, o significa fragB è stato distrutto, quindi non posso aggiungere fragA? O significa qualcosa di completamente diverso?

MainActivity.java

public class MainActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FragmentManager fragMan = getSupportFragmentManager();

        //add Fragment A to the main linear layout
        FragmentTransaction fragTrans = fragMan.beginTransaction();
        FragmentClassA fragA = new FragmentClassA();
        fragTrans.add(R.id.mainLinearLayout, fragA);
        fragTrans.addToBackStack("A");
        fragTrans.commit();

        //get Fragment A to add a Fragment B to itself
        fragA.addFragB();
    }

}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/mainLinearLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:orientation="horizontal" >
    </LinearLayout>

</RelativeLayout>

FragmentClassA.java

public class FragmentClassA extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_a, container, false);
    }

    public void addFragB() {
        FragmentManager childFragMan = getChildFragmentManager();

        FragmentTransaction childFragTrans = childFragMan.beginTransaction();
        FragmentClassB fragB = new FragmentClassB();
        childFragTrans.add(R.id.fragA_LinearLayout, fragB);
        childFragTrans.addToBackStack("B");
        childFragTrans.commit();

    }
}

fragment_a.xml

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


</LinearLayout>

FragmentClassB.java

public class FragmentClassB extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_b, container, false);
    }

}

fragment_b.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />

</LinearLayout>

LogCat

11-18 16:17:05.627: E/AndroidRuntime(14351): FATAL EXCEPTION: main
11-18 16:17:05.627: E/AndroidRuntime(14351): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.nestedfragmenttest/com.example.nestedfragmenttest.MainActivity}: java.lang.IllegalStateException: Activity has been destroyed
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.app.ActivityThread.access$600(ActivityThread.java:141)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.os.Handler.dispatchMessage(Handler.java:99)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.os.Looper.loop(Looper.java:137)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.app.ActivityThread.main(ActivityThread.java:5103)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at java.lang.reflect.Method.invokeNative(Native Method)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at java.lang.reflect.Method.invoke(Method.java:525)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at dalvik.system.NativeStart.main(Native Method)
11-18 16:17:05.627: E/AndroidRuntime(14351): Caused by: java.lang.IllegalStateException: Activity has been destroyed
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1365)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at com.example.nestedfragmenttest.FragmentClassA.addFragB(FragmentClassA.java:26)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at com.example.nestedfragmenttest.MainActivity.onCreate(MainActivity.java:25)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.app.Activity.performCreate(Activity.java:5133)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
11-18 16:17:05.627: E/AndroidRuntime(14351):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
11-18 16:17:05.627: E/AndroidRuntime(14351):    ... 11 more

EDIT:

ianhanniballake la risposta di GrIsHu successivamente la risposta che si espande nello stesso punto sia stato utile puntualizzare la radice del problema. Tuttavia questo pone un ulteriore problema.

L’intenzione finale è che FragmentClassA sarà parte di una libreria. Sarà utilizzato in molteplici situazioni e il numero di FragmentClassB istanze di variare, o ci può anche essere nessuno. Quindi ho bisogno di essere in grado di attivare l’aggiunta del bambino frammenti di un’istanza di FragmentClassA dal padre di attività. Ho appena dato un’occhiata a mantenere fragA come una variabile a livello di classe in MainActivity e quindi chiamando fragA.AddFragB() in MainActivity‘s onActivityCreated() metodo, ma non è disponibile ad essere sottoposto a override. Ogni pensiero?

  • Check out la mia risposta.



3 Replies
  1. 8

    Non si può caricare direttamente il frammento che hai dichiarato in FragA. Il FragmentA sarà caricato per primo e poi dopo si può caricare il FragmentB chiamando il metodo addFragB() dal tuo fragA's onCreateView() metodo.

    Provare come di seguito:

    Rimuovere la riga fragA.addFragB(); dal tuo obbiettivo principale l’allevamento

    public class MainActivity extends FragmentActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            FragmentManager fragMan = getSupportFragmentManager();
    
            //add Fragment A to the main linear layout
            FragmentTransaction fragTrans = fragMan.beginTransaction();
            FragmentClassA fragA = new FragmentClassA();
            fragTrans.add(R.id.mainLinearLayout, fragA);
            fragTrans.addToBackStack("A");
            fragTrans.commit();
    
        }
    
    }

    E provare a caricare il FragmentB da FragmentA come di seguito:

    public class FragmentClassA extends Fragment {
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            addFragB(); //Call and load fragment B here.
            return inflater.inflate(R.layout.fragment_a, container, false);
        }
    
        public void addFragB() {
            FragmentManager childFragMan = getChildFragmentManager();
    
            FragmentTransaction childFragTrans = childFragMan.beginTransaction();
            FragmentClassB fragB = new FragmentClassB();
            childFragTrans.add(R.id.fragA_LinearLayout, fragB);
            childFragTrans.addToBackStack("B");
            childFragTrans.commit();
    
        }
    }
    • Questo è stato utile. Grazie. Si prega di controllare la mia domanda Modifica però.
    • Beh, la cosa che si desidera implementare è un po ‘ complicato e non è valido modo per implementare. Mi puoi dire in quali librerie FragmentA classe vi risiedono ?
    • Per chiarire, FragmentA sarà parte di un Android Library Project. Per funzionare in modo simile a uno Strumento di Pallet come si trova nell’editor grafici, testi etc. Il contenuto dello Strumento Pallet variare a seconda su ciò che è logico per il tipo di file aperto in app. Stavo pensando che in movimento Nidificate Frammenti può essere molto comodo per ri-organizzare questi strumenti Pallet come necessario. Ma dal suono di esso, probabilmente dovrei attaccare con il mio vecchio metodo di costruzione di un Strumento di Pallet Personalizzati Composto Widget piuttosto che da Bambino Frammenti. È questo quello che stai dicendo?
    • In realtà, ora penso di più su di esso, il mio test app non rispecchiare la reale situazione. Lo Strumento Pallet (FragmentA) verrà creato ma non compilato quando l’applicazione si avvia. Non sarà popolata fino a quando l’utente apre un file, in modo FragmentA sarà sicuramente esistono già da allora. Forse posso ancora utilizzare il Nidificati Frammento di approccio, dopo tutto?
    • Questa soluzione presuppone che FragmentB è un bambino di FragmentA. Che cosa succede se FragmentB sorella di FragmentA e si voleva caricare FragmentB DOPO FragmentA ha caricato? Mi viene il dubbio che è possibile utilizzare getChildFragmentManger per che.
    • Sarebbe onAttach (Context context) essere migliore, perché è garantito che il genitore frammento sarebbe stato attaccato per la sua attività

  2. 3

    FragmentTransaction.commit non è un’azione immediata per la documentazione quindi il tuo fragA non è associato a un’Attività (quindi, perché restituisce che l’attività viene distrutto) quando si chiama fragA.addFragB().

    Si dovrebbe invece chiamare addFragB() in FragmentClassA.onCreate() per garantire fragA è collegato ad un’attività di e pronto per inizializzare il proprio stato.

    • Questo è stato utile. Grazie. Si prega di controllare la mia domanda Modifica però.
  3. 0

    Fatto si tenta di aggiungere che questo bambino frammenti:

    @Override
        public void onDetach() {
            super.onDetach();
    
            try {
                Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
                childFragmentManager.setAccessible(true);
                childFragmentManager.set(this, null);
    
            } catch (NoSuchFieldException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        } 

    questo per evitare di runtime problemi, mentre il passaggio tra i diversi frammenti.

    Diciamo che hanno un’attività con un Frammento, che a loro volta hanno due bambini e frammenti: fragA e FragB.

    È possibile implementare bambino frammenti di qualcosa di simile a questo:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.activity_mymessages, container, false);
        FragmentManager manager = getChildFragmentManager();
        FragmentTransaction ft = manager.beginTransaction();
        ft.replace(R.id.headlines, fragA);
        ft.replace(R.id.article, fragB);
        ft.commit();
    
        return root;
    }

    activity_mymessages.xml

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal">
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="horizontal">
            <FrameLayout android:id="@+id/headlines"
                android:layout_height="match_parent"
                android:name="com.example.fragA"
                android:layout_width="103dp"
                android:layout_marginRight="10dp"/>
            <FrameLayout android:id="@+id/article"
                android:layout_height="fill_parent"
                android:name="com.example.fragB"
                android:layout_width="fill_parent" />
        </LinearLayout>
    
    </FrameLayout>

    Fammi sapere se funziona, se non posso fornire codice di lavoro dal mio GitHub.

Lascia un commento