2016-01-14 15 views
19

Abbiamo un arresto anomalo, che punta alle classi di sistema. Appare all'avvio dell'applicazione.L'app si arresta in modo anomalo all'avvio a causa di NPE in android.content.Context.getString

irreversibile: java.lang.RuntimeException: Impossibile avviare l'attività ComponentInfo {} com.myapp.android/com.myapp.android.main.BaseMainActivity: java.lang.RuntimeException: Impossibile creare applicazioni com.myapp.android.main.MyApp: java.lang.NullPointerException a android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2377) a android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2429) a android.app.ActivityThread.access $ 800 (ActivityThread.java:151) su android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1342) su android.os.Handler.dispatchMessage (Handler.java:110) su android.os.Looper.loop (Looper.java:193) su android.app.ActivityThread.main (ActivityThread.java:5333) su java .lang.reflect.Method.invokeNative (Method.java) a java.lang.reflect.Method.invoke (Method.java:515) su com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java : 828) in com.android.internal.os.ZygoteInit.main (ZygoteInit.java:644) in dalvik.system.NativeStart.main (NativeStart.java) causato da java.lang.RuntimeException: impossibile creare l'applicazione com.myapp.android.main.MyApp: java.lang.NullPointerException su android.app.LoadedApk.makeApplication (LoadedApk.java:529) presso andro id.app.ActivityThread.performLaunchActivity (ActivityThread.java:2292) a android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2429) a 800 android.app.ActivityThread.access $ (ActivityThread.java:151) in Android .app.ActivityThread $ H.handleMessage (ActivityThread.java:1342) su android.os.Handler.dispatchMessage (Handler.java:110) su android.os.Looper.loop (Looper.java:193) su Android .app.ActivityThread.main (ActivityThread.java:5333) in java.lang.reflect.Method.invokeNative (Method.java) in java.lang.reflect.Method.invoke (Method.java:515) in com .android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:828) su com.android.internal.os .ZygoteInit.main (ZygoteInit.java:644) a dalvik.system.NativeStart.main (NativeStart.java) causata da java.lang.NullPointerException a android.content.Context.getString (Context.java:343) a com.myapp.android.api.singletons.AppTrackingInstance.initAdjust (AppTrackingInstance.java:114) su com.myapp.android.api.singletons.AppTrackingInstance. (AppTrackingInstance.java:92) su com.myapp.android.injection .modules.ApplicationScopeModule.provideAppTrackingInstance (ApplicationScopeModule.java:326) su com.myapp.android.injection.modules.ApplicationScopeModule $$ ModuleAdapter $ ProvideAppTrackingInstanceProvidesAdapter.get (ApplicationScopeModule $$ ModuleAdapter.java: 1618) su com.myapp.android .injection.modules.ApplicationScopeModule $$ ModuleAdapter $ ProvideAppTrackingInst anceProvidesAdapter.get (ApplicationScopeModule $$ ModuleAdapter.java: 1552) a dagger.internal.Linker $ SingletonBinding.get (Linker.java:364) a com.myapp.android.main.MyApp $$ InjectAdapter.injectMembers (MyApp $ $ InjectAdapter.java: 70) in com.myapp.android.main.MyApp $$ InjectAdapter.injectMembers (MyApp $$ InjectAdapter.java: 23) in dagger.ObjectGraph $ DaggerObjectGraph.inject (ObjectGraph.java:281) su com.myapp.android.main.MyApp $ 1.run (MyApp.java:57) su com.myapp.android.main.MyApp.onCreate (MyApp.java:51) su android.app.Instrumentation.callApplicationOnCreate (Instrumentation.java:1007) su android.app.LoadedApk.makeApplication (LoadedApk.java:526) su android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2292) su android.app. ActivityThread.handleLaunchActivity (ActivityThread.java:2429) su android.app.ActivityThread.access $ 800 (ActivityThread.java:151) su android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1342) su android.os .Handler.dispatchMessage (Handler.java:110) su android.os.Looper.loop (Looper.java:193) su android.app.ActivityThread.main (ActivityThread.java:5333) su java.lang.reflect .Method.invokeNative (Method.java) a java.lang.reflect. Method.invoke (Method.java:515) in com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:828) in com.android.internal.os.ZygoteInit.main (ZygoteInit.java: 644) a dalvik.system.NativeStart.main (NativeStart.java)

usiamo Dagger 1, la nostra applicazione è -ed. Modulo

Dagger: classe

@Module(
    library = true, 
    injects = { 
    MyApp.class 
    } 
) 

public class ApplicationScopeModule { 
    private final MyApp application; 

    public ApplicationScopeModule(MyApp application) { 
    this.application = application; 
    } 

    @Provides 
    @Singleton 
    @ForApplication 
    Context provideApplicationContext() { 
    return application.getApplicationContext(); 
    } 

    @Provides 
    @Singleton 
    AppTrackingInstance provideAppTrackingInstance(@ForApplication Context context) { 
    return new AppTrackingInstance(context); 
    } 
} 

MiaApp: classe

package com.myapp.android.main; 

public class MyApp extends MultiDexApplication { 
    private ObjectGraph objectGraph; 

    @Inject 
    AppTrackingInstance appTrackingInstance; 

    @Override 
    public void onCreate() { 
    super.onCreate(); 
    // workaround for multi-dex enabled projects 
    // taken from http://frogermcs.github.io/MultiDex-solution-for-64k-limit-in-Dalvik/ 
    // multi-dex separates dex files, and some classes going to additional dex file. 
    // Additional .dex files are loaded in Application.attachBaseContext(Context) method 
    // (by MultiDex.install(Context) invokation). It means, that before this moment 
    // we can’t use classes from them. So i.e. we cannot declare static fields 
    // with types attached out of main .dex file. 
    // Otherwise we’ll get java.lang.NoClassDefFoundError. 
    // 
    // the issue should be fixed on the Android level 
    // 
    new Runnable() { 
     @Override 
     public void run() { 
     initFabric(); 
     objectGraph = ObjectGraph.create(getModules().toArray()); 
     objectGraph.inject(MyApp.this); 
     appTrackingInstance.trackAppLaunch(); 
     } 
    }.run(); 
    } 

    private void initFabric() { 
    Fabric.with(MyApp.this, new Crashlytics.Builder().core(new CrashlyticsCore.Builder().disabled(BuildConfig.IS_DEBUG_BUILD).build()).build()); 
    } 

    public List<Object> getModules() { 
    return Arrays.<Object>asList(new ApplicationScopeModule(this)); 
    } 

    public ObjectGraph getObjectGraph() { 
    return objectGraph; 
    } 
} 

AppTrackingInstance:

package com.myapp.android.api.singletons; 

public class AppTrackingInstance { 
    Context context; 
    public AppTrackingInstance(Context context) { 
    this.context = context; 
    initAdjust(); 
    } 

    private void initAdjust() { 
    // "broken" context here 
    String variable = context.getString(R.string.adjust_variable); 
    } 
} 

F ROM l'attuazione e StackTrace otteniamo la causa incidente:

Causato da java.lang.NullPointerException a android.content.Context.getString (Context.java:343)

Significa che quando l'utente avvia l'applicazione, Dagger inietta nel contesto dell'applicazione "rotto" AppTrackingInstance. Come può essere possibile? Usiamo ampiamente Dagger e questo contesto viene iniettato in molti posti senza problemi. Solo in alcuni casi specifici (che non riesco a riprodurre) l'app si arresta in modo anomalo all'avvio a causa di un contesto interrotto. appare

Crash sui dispositivi e le versioni del sistema operativo diverso, per lo più su OS 4.x, ma su alcune versioni del sistema operativo 5.0.2 appare raramente anche: 1 screenshot 2 screenshot 3 screenshot

Poiché si tratta di un crash all'avvio app, Ho studiato molto e ho trovato problemi abbastanza simili (1, 2, app crash on update).

Rispetto a alcuni dispositivi di prova: Nexus 4 (Android 5.0.1), Samsung S3 (Android 4.3) - e ha cercato di riprodurre il problema:

  • applicazione aperto con/senza connessione internet
  • di apertura/chiusura 50x volte l'applicazione
  • applicativi aperti, disinstallare dal mercato del gioco, installare di nuovo mercato sotto forma di gioco e aprire nuovamente
  • applicazione aperta da diverse deeplink
  • applicazione aperta dal sito web mobile
  • installare l'applicazione dal mercato del gioco e non aprirlo. Partenza a freddo da deeplink
  • applicazione aperta dalle notifiche push
  • applicazione aperto con diversi locali
  • applicazione aperta dalle recents
  • chiari dati delle applicazioni e aperti
  • installare antico edificio, la produzione, l'aggiornamento all'ultima build di produzione manualmente
  • installa il vecchio build di produzione, aggiorna all'ultimo uno dal mercato dei giochi
  • naviga attraverso l'applicazione XXX minuti, quindi aggiorna all'ultima versione dal mercato dei giochi

0 si blocca durante questo test, ma l'arresto si verifica ancora sui dispositivi degli utenti e non ho idea del motivo.

Probabilmente, succede la causa di o Dagger 1, ma non posso dire con sicurezza.

+0

Non una soluzione reale (quindi un commento) ma un miglioramento che risolverebbe il problema impedendo la chiamata getString(): le impostazioni di configurazione non dovrebbero essere inserite in strings.xml! Se disponi di un ID registrazione-aggiustamento, dovresti aggiungerlo come buildConfigField ai tuoi sapori e fare riferimento a essi tramite BuildConfig.ADJUST_TRACKING_ID o nomi simili. – WarrenFaith

+0

grazie, usiamo le variabili e gli aromi di 'BuildConfig' per questi casi. –

+0

Ti sei assicurato che 'R.string.adjust_variable' sia stato tradotto correttamente? Inoltre, cercando di riprodurre lo schianto, dovresti provare ad usare altre lingue –

risposta

2

irreversibile: java.lang.RuntimeException: Impossibile avviare l'attività ComponentInfo {.......

ho avuto come stacktrace una volta e non è assolutamente così spaventoso, a suona . Significa che è stata generata un'eccezione in onCreate() di MyApp.

I.e. context.getResources(), fornito alla classe AppTrackingInstance è nullo e provoca l'arresto anomalo.

La ragione, per cui getResources() ritorno null (crash => accade) per me suona come una condizione di competizione , in particolare, in quanto non accade ogni volta (da quello che ho capito dal post).

Poiché utilizzo anche Dagger1 e MultiDex e non ho questo problema, posso supporre, la possibile soluzione sarebbe iniziare a inizializzare lo ObjectGraph pigramente.

Questo frammento funziona come un fascino per me:

public final class ApplicationScopeModule { 

    private final Context applicationContext; 

    public ApplicationScopeModule(final Context applicationContext) { 
     this.applicationContext = applicationContext; 
    } 

    @Provides 
    @Singleton 
    @SuppressWarnings("unused") // invoked by Dagger 
    public Context provideApplicationContext() { 
     return applicationContext; 
    } 

    @Provides 
    @Singleton 
    @SuppressWarnings("unused") // invoked by Dagger 
    public Analytics provideAnalytics(Context context) { 
     return new DefaultAnalytics(context); 
    } 

    //...<other providers>.. 
} 

MyApplication, che si estende Application:

public class MyApplication extends Application { 

    private ObjectGraph objectGraph; 

    private final Object lock = new Object(); 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
    } 

    protected List<Object> getModules() { 
     final ArrayList<Object> modules = new ArrayList<>(); 
     modules.add(new ApplicationScopeModule(getApplicationContext())); 
     return modules; 
    } 

    public ObjectGraph getApplicationGraph() { 
     synchronized (lock) { 
      if (objectGraph == null) { 
       objectGraph = ObjectGraph.create(getModules().toArray()); 
      } 

      return objectGraph; 
     } 
    } 
} 

Poi negli 's ActivityBase - la classe di base per ogni Activity sto usando in app:

public abstract class FragmentActivityBase extends ActionBarActivity { 

    private ObjectGraph activityGraph; 

    @Override 
    protected void onCreate(final Bundle savedInstanceState) { 
     inject(this); 
     super.onCreate(savedInstanceState); 
    } 

    public void inject(final Object object) { 
     try { 
      if (activityGraph == null) { 
       final MyApplication application = (MyApplication) getApplication(); 
       activityGraph = application.getApplicationGraph(); 
      } 

      activityGraph.inject(object); 
     } catch (IllegalArgumentException e) { 
      //log error 
     } 
    } 
} 

Dovrebbe essere d'aiuto, poiché durante il onCreate() del primo Activity (estensione di ActivityBase), le risorse sono definitivamente già definite, quindi getResources() non dovrebbe restituire null.

Altre due opzioni sono

  • Evitare Multidex
  • sondaggio per il momento, quando il contesto è pieno (anche se, una volta getResources() in mancanza - chissà cos'altro potrebbe essere sbagliato e ho paura porterà ad altri crash - imho)

Spero che sia d'aiuto.

+0

usiamo 'Runnable', poiché è una soluzione alternativa per le app Multidex. Sul contesto - sì, è iniettato correttamente ovunque, e non credo che setter separato risolverà il problema. L'oggetto non è nullo, 'getResources()' all'interno del contesto lancia un NPE, questa è la cosa strana. Grazie per l'aiuto, comunque. –

+0

@VeaceslavGaidarji hm .. Lo stacktrace si presenta come l'oggetto Context è null e causa NPE. Ad ogni modo, suggerisco di provare l'inizializzazione Lazy dell'oggetto obj.graph e trackAppLaunch. Aggiornerò la mia risposta, una volta tornato dalle piste da sci stasera. E controlla anche che la 343a riga nella classe Context faccia effettivamente :-) –

+0

no, l'oggetto 'context' stesso non è nullo, alcune risorse al suo interno sono nulle. –

0

Sembra che l'oggetto Context non venga inizializzato. Errore in questa chiamata:

@Provides 
@Singleton 
AppTrackingInstance provideAppTrackingInstance(@ForApplication Context context) { 
    return new AppTrackingInstance(context); 
} 

Verificare se il contesto è nullo in questo metodo. Credo che il problema ci sia.

+0

Come potete vedere sopra, ne abbiamo discusso - no, il contesto è ** non ** null - le risorse del contesto sono nulle. –

Problemi correlati