2015-05-18 10 views
9

Recentemente mi sono imbattuto in un problema difficile da riprodurre. L'NPE si verifica quando un frammento tenta di inizializzare ArrayAdapter con i dati di Activity. L'elenco predefinito inizializzata nel metodo onCreate di attività:Why Fragment's onCreate() viene talvolta chiamato prima di onCreate() di Activity?

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    // ... 
    mAccounts = new ArrayList<>(); 
    // ... 
} 

@Override 
public List<Account> getAccounts(){ 
    return mAccounts; 
} 

Il frammento crea un adattatore lista anche nella sua onCreate():

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setRetainInstance(true); 
    setHasOptionsMenu(true); 

    //mAccountProvider is an interface implemented by the activity 
    mAccounts = mAccountProvider.getAccounts(); 

    mAccountAdapter = new AccountAdapter(getActivity(), R.layout.account_list_item, mAccounts); 
} 

La NPE avviene all'interno del AccountAdapter quando predefinita Il metodo getCount() viene chiamato. Il motivo è che mAccounts è null. Il problema appare raramente e non sono stato in grado di riprodurlo.

Quando è possibile che del frammento onCreate() viene chiamato prima onCreate di attività()? In base al codice sorgente, Framment's onCreate() viene inviato nell'attività onCreate(). Perché viene poi chiamato dopo che Activity onCreate() ha terminato la sua esecuzione?

+0

no, non è possibile. – Blackbelt

+0

Dovresti pubblicare più codice su come il tuo frammento viene mostrato nella tua attività. – jobcrazy

+0

Sono d'accordo con @Ilya Vorobiev. Il frammento di onCreate() viene inviato quando viene chiamato super.onCreate() dell'attività. La domanda è: perché nella maggior parte dei casi viene eseguita dopo l'attività su onCreate. – Zzokk

risposta

5

onCreate() del tuo frammento può essere chiamato prima del onCreate() metodo della vostra attività è stato terminato. Hai il callback onActivityCreated() nel tuo frammento e onCreateView(). È possibile utilizzare qualsiasi di esso - viene eseguito dopo il metodo di attività onCreate.

+0

Conosci le circostanze esatte? Come ho detto, il problema è riprodotto raramente. – Zzokk

+0

Ci sono molte situazioni in cui questo problema si verifica. Se dai un'occhiata al metodo onCreate() di FragmentActivity vedrai che l'attività prima si attacca ai frammenti, quindi esegue super.onCreate(). Quindi non vi è alcuna garanzia che il codice verrà eseguito prima del onCreate() del frammento. –

+0

Beh, lo capirei quando il problema è riproducibile al 100% poiché effettivamente onCreate() del mio frammento viene chiamato prima di onCreate() dell'attività. Credo che dovrei modificare la domanda. Dovrebbe essere invertito. Perché onCreate() del frammento viene chiamato dopo activiy's onCreate() anche se viene inviato in Activty's onCreate(). – Zzokk

6

La richiamata Attività non viene chiamata dopo i frammenti; il frammento viene chiamato durante le attività.

inizializzazione mAccounts prima di chiamare super.onCreate() in Activity.onCreate()

+0

Grazie per il suggerimento. Ci sono sicuramente diversi modi per risolvere il problema. La domanda è perché il comportamento è diverso. In che modo viene attivato esattamente onCreate() e perché a volte accade dopo onCreate() dell'attività. – Zzokk

2

Questo bug può essere riproducono accendendo "Dont't mantenere attività" nelle opzioni di sviluppo. Ho riscontrato problemi simili e ho risolto la soluzione fornita da FunkTheMonk.

1

Recentemente si è imbattuto nel problema. Vedere la traccia dello stack in basso.

Come ha dichiarato FunkTheMonk, il crash è dovuto al fatto che il codice onCreate() personalizzato nella tua attività (subito dopo super.onCreate()) viene eseguito dopo il codice personalizzato onCreate() nel frammento (subito dopo super.onCreate())

Se si ha realmente bisogno il callback essere promettente eseguito dopo onCreate dell'intera attività(), mettere i frammenti di codice in onActivityCreated() piuttosto che onCreate()

in caso contrario, la condizione di cui sopra avverrà quando la memoria è basso e l'attività è riciclata.

Secondo la mia esperienza, quando MyActivity invia un intent, l'App si arresta in modo anomalo una volta tornato a MyFragment premendo il tasto Indietro.

Caused by: java.lang.NullPointerException 
    at MyFragment.onCreate(MyFragment.java:20) 
    at android.support.v4.app.Fragment.performCreate(Fragment.java:1939) 
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1029) 
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248) 
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1230) 
    at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:2037) 
    at android.support.v4.app.FragmentController.dispatchCreate(FragmentController.java:154) 
    at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:289) 
    at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:58) 
    at MyActivity.onCreate(MyActivity.java:129) 
    at android.app.Activity.performCreate(Activity.java:5248) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2162) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257) 
    at android.app.ActivityThread.access$800(ActivityThread.java:139) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:136) 
    at android.app.ActivityThread.main(ActivityThread.java:5086) 
    at java.lang.reflect.Method.invokeNative(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:515) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) 
    at dalvik.system.NativeStart.main(Native Method) 
0

io possa essere troppo tardi per rispondere, ma ancora. L'ho incontrato qualche giorno fa.Succede quando si utilizzano i frammenti dinamici e nel layout si utilizza il tag del frammento per visualizzare il frammento. Usa invece un layout (preferibilmente FrameLayout). Supponendo che stiate usando la libreria dei frammenti di supporto.

Vale la pena provare.

Problemi correlati