【发布时间】:2018-03-28 19:45:01
【问题描述】:
在我的 Google Play 控制台上,自从我开始使用 Dagger 2 以来,我看到了很多崩溃报告,但仅限于 Android 7.0 并且主要在三星设备、一些华为和摩托罗拉设备以及一些罕见的 Xperia 设备上:
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)
我无法重现该问题,因为我手头没有任何受影响的设备,而且似乎并非某种类型的所有设备都受到影响,更像是随机启动失败。
从我通过研究了解到的情况是,活动的 onCreate 很可能在活动实际附加到应用程序之前被调用。但我无法证明这个说法......
我正在遵循 Google 的 MVP+Dagger 架构蓝图。
我的应用程序类:
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;
}
}
我的 MainActivity 类:
public class MainActivity extends DaggerAppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
匕首2相关代码:
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);
}
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()));
}
我不知道如何解决这个崩溃,但是崩溃的数量太多了,不容忽视。由于我的 Dagger 2 使用在所有其他 Android 版本和设备上都能完美运行,我认为这不是由我使用 Dagger 2 的方式引起的,而是由某些供应商特定的 7.0 实现引起的。如果有人遇到同样的问题并找到解决方案,请帮帮我!
由于这个错误让我发疯,我向 10 万用户推出了一个测试版本,试图了解整个事情的问题所在。
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);
}
}
该活动基于 Dagger 的活动,内嵌 AndroidInjection 代码。我的想法是,如果这个问题不能通过使用 ApplicationContext 而不是 getApplication() 来解决,我的堆栈跟踪应该详细说明发生了什么:
- 如果问题是由
getApplication()引起的,堆栈跟踪将包含injectWithNullApplication()或injectWithWrongApplication() - 抛出的 NPE 将显示
getApplicationContext()返回 null - 抛出的 RuntimeException 将表明
getApplicationContext()不是我的应用程序 - 如果不抛出异常,
getApplication()或getApplicationContext()将返回我的应用程序,我不会关心实际解决问题的方法
这是堆栈跟踪:
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)
所以 inject() 中的 if 子句 !(application instanceof HasActivityInjector) 没有重新路由到 injectWithWrongApplication() 但相同的 if 子句在同一 Application 实例上导致 injectNow(Application application) 中的 RuntimeException。怎么回事?我的代码看起来像 100 次,但如果我有错误,请告诉我!否则,我想在 7.0 的一些供应商实现中会发生一些非常奇怪的事情,这些事情可能无法修复......
基于对https://github.com/google/dagger/issues/748的讨论,我还推出了一个测试版本,它在所有Dagger组件中只使用getApplicationContext()而不是getApplication(),没有任何区别。
清单中的我的应用程序标记
<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>
【问题讨论】:
-
目前我们的应用程序中也发生了同样的事情。看起来我们的自定义
Application类根本没有被调用(即使它在清单中指定),这可能意味着使用默认的Application类,这反过来意味着强制转换将失败。不过仍在寻找解决方案。 -
我不确定我是否有答案(还),但我确实注意到DaggerApplication#onCreate 在调用
applicationInjector()之后在你的应用程序组件上调用inject,所以你可能没有'不需要自己这样做。还有,你用multidex吗,能不能把Application的动态类型记录下来,来证实上面Dmitry的理论? -
杰夫,我试图获取应用程序的类型,但 Play 管理中心没有收集异常消息,并且发生崩溃时 Firebase 尚未初始化。
-
好的,请看更新3。
标签: android dagger-2 samsung-mobile android-7.0-nougat