Sur mon Google Play de la console, je vois beaucoup les rapports de plantage depuis que j'ai commencé à utiliser la Dague 2, mais seulement sur Android 7.0 et principalement sur les appareils Samsung, certains Huawai et appareils Motorola et quelques rares Xperia appareils:
java.lang.RuntimeException:
at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2984)
at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3045)
at android.app.ActivityThread.-wrap14 (ActivityThread.java)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1642)
at android.os.Handler.dispatchMessage (Handler.java:102)
at android.os.Looper.loop (Looper.java:154)
at android.app.ActivityThread.main (ActivityThread.java:6776)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1518)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1408)
Caused by: java.lang.RuntimeException:
at dagger.android.AndroidInjection.inject (AndroidInjection.java:48)
at dagger.android.support.DaggerAppCompatActivity.onCreate (DaggerAppCompatActivity.java:43)
at com.package.MainActivity.onCreate (MainActivity.java:83)
at android.app.Activity.performCreate (Activity.java:6956)
at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1126)
at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2927)
Je ne peux pas reproduire le problème depuis, je n'ai pas touché appareil à portée de main, aussi, il semble que tous les appareils d'un type qui sont touchés, plus comme un hasard échec de démarrage.
De ce que j'ai appris par le biais de la recherche est que le plus probable de l'activité onCreate est appelée avant que l'activité est réellement attaché à une application. Mais je ne peux pas prouver cette affirmation...
Je suis de Google suivant l'architecture du plan de MVP+Dague.
Ma classe d'Application:
public class App extends DaggerApplication {
@Override
public void onCreate() {
super.onCreate();
}
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
AppComponent appComponent = DaggerAppComponent.builder().application(this).build();
appComponent.inject(this);
return appComponent;
}
}
Ma classe MainActivity:
public class MainActivity extends DaggerAppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
Pertinentes de la Dague 2 code:
DaggerAppCompatActivity: https://github.com/google/dagger/blob/e8d7cd4c29c1316c5bb1cf0737d4f29111fcb1c8/java/dagger/android/support/DaggerAppCompatActivity.java#L42-L45
protected void onCreate(@Nullable Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
AndroidInjection: https://github.com/google/dagger/blob/e8d7cd4c29c1316c5bb1cf0737d4f29111fcb1c8/java/dagger/android/AndroidInjection.java#L43-L52
public static void inject(Activity activity) {
checkNotNull(activity, "activity");
Application application = activity.getApplication();
if (!(application instanceof HasActivityInjector)) {
throw new RuntimeException(
String.format(
"%s does not implement %s",
application.getClass().getCanonicalName(),
HasActivityInjector.class.getCanonicalName()));
}
Je n'ai aucune idée de comment résoudre ce crash, mais le nombre d'accidents est trop important pour qu'on l'ignore. Depuis ma Dague 2 utilisation fonctionne parfaitement sur toutes les autres versions d'Android et les périphériques je suppose qu'elle n'est pas causée par la façon dont j'utilise la Dague 2, mais en quelque sorte par certains fournisseurs spécifiques 7.0 implémentations. Si quelqu'un a connu le même problème et trouvé une solution s'il vous plaît, veuillez, s'il vous plaît aidez-moi!
Depuis cette erreur est me rend fou, j'ai roulé une version de test à 100k utilisateurs à essayer de comprendre où tout cela va mal.
public abstract class TestDaggerAppCompatActivity extends AppCompatActivity implements HasFragmentInjector, HasSupportFragmentInjector {
@Inject DispatchingAndroidInjector<Fragment> supportFragmentInjector;
@Inject DispatchingAndroidInjector<android.app.Fragment> frameworkFragmentInjector;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
inject();
super.onCreate(savedInstanceState);
}
@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return supportFragmentInjector;
}
@Override
public AndroidInjector<android.app.Fragment> fragmentInjector() {
return frameworkFragmentInjector;
}
private void inject() {
Application application = getApplication();
if(application == null) {
injectWithNullApplication();
return;
}
if (!(application instanceof HasActivityInjector)) {
injectWithWrongApplication();
return;
}
// Everything seems ok...
injectNow(application);
}
private void injectWithNullApplication() {
Application application = (Application) getApplicationContext();
injectNow(application);
}
private void injectWithWrongApplication() {
Application application = (Application) getApplicationContext();
injectNow(application);
}
private void injectNow(Application application) {
checkNotNull(application, "Application must not be null");
if (!(application instanceof HasActivityInjector)) {
throw new RuntimeException(String.format("%s does not implement %s", application.getClass().getCanonicalName(), HasActivityInjector.class.getCanonicalName()));
}
AndroidInjector<Activity> activityInjector = ((HasActivityInjector) application).activityInjector();
checkNotNull(activityInjector, "%s.activityInjector() returned null", application.getClass().getCanonicalName());
activityInjector.inject(this);
}
}
L'activité est basée sur la Dague de l'activité avec inline AndroidInjection code. Mon raisonnement était que si ce problème ne serait pas résolu par l'utilisation de ApplicationContext au lieu de getApplication()
de mon stack trace doit décrire en détail ce qui se passe:
- si le problème est causé par
getApplication()
la trace de la pile contiendrainjectWithNullApplication()
ouinjectWithWrongApplication()
- la levée d'entrées en phase nationale devrait montrer qu'
getApplicationContext()
retourné null - la levée d'une RuntimeException voudrais montrer que l'
getApplicationContext()
n'est pas ma Demande - si aucune exception ne serait jeté le
getApplication()
ougetApplicationContext()
renvoyé ma demande et je n'ai pas de soins de ce qui s'est réellement résolu le problème
Et ici, c'est la trace de la pile:
Caused by: java.lang.RuntimeException:
at com.package.di.TestDaggerAppCompatActivity.inject (TestDaggerAppCompatActivity.java:49)
at com.package.di.TestDaggerAppCompatActivity.onCreate (TestDaggerAppCompatActivity.java:31)
at com.package.MainActivity.onCreate (MainActivity.java:83)
at android.app.Activity.performCreate (Activity.java:6942)
at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1126)
at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2880)
Si la clause if !(application instanceof HasActivityInjector)
en inject()
n'a pas rediriger vers injectWithWrongApplication()
mais même si la clause a causé la RuntimeException en injectNow(Application application)
sur la même instance de l'Application. WTF? J'ai regardé 100 fois à mon code, mais si j'ai une erreur s'il vous plaît laissez-moi savoir! Sinon, je pense qu'il y a vraiment des choses bizarres qui se passe dans certaines implémentations de Fournisseur de 7.0 qui sont peut-être pas réparable...
Sur la base des discussions sur https://github.com/google/dagger/issues/748 j'ai aussi sorti une version de test qui utilise uniquement l' getApplicationContext()
au lieu de getApplication()
dans tous Poignard composants, sans aucune différence.
Ma balise application de manifester
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/SplashScreenTheme"
android:fullBackupContent="false">
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
<meta-data android:name="com.google.android.gms.games.APP_ID" android:value="@string/app_id" />
<meta-data android:name="android.max_aspect" android:value="2.1" />
<activity
android:name="com.package.MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.package.GeneratorService" android:exported="false"/>
</application>