Den*_*uer 31 android samsung-mobile dagger-2 android-7.0-nougat
在我的Google Play控制台上,自从我开始使用Dagger 2以来,我看到了很多崩溃报告,但仅限于Android 7.0,主要是三星设备,一些Huawai和Motorola设备以及一些罕见的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)
Run Code Online (Sandbox Code Playgroud)
我无法重现这个问题,因为我手边没有任何受影响的设备,似乎并非所有类型的设备都受到影响,更像是随机启动失败.
从我通过研究得到的结果是,在活动实际附加到应用程序之前,很可能会调用活动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;
}
}
Run Code Online (Sandbox Code Playgroud)
我的MainActivity类:
public class MainActivity extends DaggerAppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
Run Code Online (Sandbox Code Playgroud)
相关的Dagger 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);
}
Run Code Online (Sandbox Code Playgroud)
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()));
}
Run Code Online (Sandbox Code Playgroud)
我不知道如何解决此崩溃问题,但崩溃的数量太大而无法忽略.由于我的Dagger 2使用在所有其他Android版本和设备上完美运行,我认为它不是由我使用Dagger 2的方式引起的,而是由某些特定于供应商的7.0实现引起的.如果有人遇到同样的问题并找到解决方案,请,请帮助我!
由于这个错误让我疯狂,我向100k用户推出了一个测试版本,试图了解整个问题出在哪里.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
该活动基于Dagger的内联AndroidInjection代码的活动.我的想法是,如果使用ApplicationContext而不是getApplication()我的堆栈跟踪来解决这个问题应该详细说明:
getApplication()堆栈跟踪引起的,则包含injectWithNullApplication()或injectWithWrongApplication()getApplicationContext()返回nullgetApplicationContext()不是我的应用程序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)
Run Code Online (Sandbox Code Playgroud)
所以,如果条款!(application instanceof HasActivityInjector)中inject()并没有重新路由到injectWithWrongApplication(),但相同的,如果子句中造成的RuntimeException injectNow(Application application)在同一个应用程序实例.WTF?我的代码看起来像100次,但如果我有错误请告诉我!否则,我猜在7.0的某些Vendor实现中有一些非常奇怪的事情可能无法修复......
根据对https://github.com/google/dagger/issues/748的讨论,我还推出了一个仅使用getApplicationContext()而不是getApplication()在所有Dagger组件中使用的测试版本,没有任何区别.
我的应用标签来自清单
<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>
Run Code Online (Sandbox Code Playgroud)
Den*_*uer 13
最后,我找到了一种方法来解决在我的应用程序中使用Android 7.0下的Dagger 2导致的崩溃.请注意,这不能解决自定义应用程序在Android 7.0下未正确使用的问题.在我的情况下,除了实现Dagger 2之外,我的自定义应用程序中没有重要的逻辑,所以我只是用下面的代码替换了DaggerApplication基础实现ApplicationlessInjection.
已知的问题
DaggerAppCompatActivity,DaggerIntentService而且DaggerFragment.如果您正在使用其他组件,DaggerDialogFragment或者DaggerBroadcastReceiver您需要创建自己的工具,但我想这应该不会太难:)履行
停止使用DaggerApplication.从标准中再次扩展自定义应用程序Application或完全删除自定义应用程序.对于Dagger 2的依赖注入,它不再需要了.只需延伸FixedDaggerAppCompatActivity,您就可以使用Dagger 2 DI进行活动.
您可能会注意到我仍然将应用程序上下文传递给ApplicationlessInjection.getInstance().依赖注入本身根本不需要上下文,但我希望能够轻松地将应用程序上下文注入到我的其他组件和模块中.在那里我不关心应用程序上下文是我的自定义应用程序还是来自Android 7.0的其他一些疯狂的东西,只要它是一个上下文.
ApplicationlessInjection
public class ApplicationlessInjection
implements
HasActivityInjector,
HasFragmentInjector,
HasSupportFragmentInjector,
HasServiceInjector,
HasBroadcastReceiverInjector,
HasContentProviderInjector {
private static ApplicationlessInjection instance = null;
@Inject DispatchingAndroidInjector<Activity> activityInjector;
@Inject DispatchingAndroidInjector<BroadcastReceiver> broadcastReceiverInjector;
@Inject DispatchingAndroidInjector<android.app.Fragment> fragmentInjector;
@Inject DispatchingAndroidInjector<Fragment> supportFragmentInjector;
@Inject DispatchingAndroidInjector<Service> serviceInjector;
@Inject DispatchingAndroidInjector<ContentProvider> contentProviderInjector;
public ApplicationlessInjection(Context applicationContext) {
AppComponent appComponent = DaggerAppComponent.builder().context(applicationContext).build();
appComponent.inject(this);
}
@Override
public DispatchingAndroidInjector<Activity> activityInjector() {
return activityInjector;
}
@Override
public DispatchingAndroidInjector<android.app.Fragment> fragmentInjector() {
return fragmentInjector;
}
@Override
public DispatchingAndroidInjector<Fragment> supportFragmentInjector() {
return supportFragmentInjector;
}
@Override
public DispatchingAndroidInjector<BroadcastReceiver> broadcastReceiverInjector() {
return broadcastReceiverInjector;
}
@Override
public DispatchingAndroidInjector<Service> serviceInjector() {
return serviceInjector;
}
@Override
public AndroidInjector<ContentProvider> contentProviderInjector() {
return contentProviderInjector;
}
public static ApplicationlessInjection getInstance(Context applicationContext) {
if(instance == null) {
synchronized(ApplicationlessInjection.class) {
if (instance == null) {
instance = new ApplicationlessInjection(applicationContext);
}
}
}
return instance;
}
}
Run Code Online (Sandbox Code Playgroud)
FixedDaggerAppCompatActivity
public abstract class FixedDaggerAppCompatActivity 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() {
ApplicationlessInjection injection = ApplicationlessInjection.getInstance(getApplicationContext());
AndroidInjector<Activity> activityInjector = injection.activityInjector();
if (activityInjector == null) {
throw new NullPointerException("ApplicationlessInjection.activityInjector() returned null");
}
activityInjector.inject(this);
}
}
Run Code Online (Sandbox Code Playgroud)
FixedDaggerFragment
public abstract class FixedDaggerFragment extends Fragment implements HasSupportFragmentInjector {
@Inject DispatchingAndroidInjector<Fragment> childFragmentInjector;
@Override
public void onAttach(Context context) {
inject();
super.onAttach(context);
}
@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return childFragmentInjector;
}
public void inject() {
HasSupportFragmentInjector hasSupportFragmentInjector = findHasFragmentInjector();
AndroidInjector<Fragment> fragmentInjector = hasSupportFragmentInjector.supportFragmentInjector();
if (fragmentInjector == null) {
throw new NullPointerException(String.format("%s.supportFragmentInjector() returned null", hasSupportFragmentInjector.getClass().getCanonicalName()));
}
fragmentInjector.inject(this);
}
private HasSupportFragmentInjector findHasFragmentInjector() {
Fragment parentFragment = this;
while ((parentFragment = parentFragment.getParentFragment()) != null) {
if (parentFragment instanceof HasSupportFragmentInjector) {
return (HasSupportFragmentInjector) parentFragment;
}
}
Activity activity = getActivity();
if (activity instanceof HasSupportFragmentInjector) {
return (HasSupportFragmentInjector) activity;
}
ApplicationlessInjection injection = ApplicationlessInjection.getInstance(activity.getApplicationContext());
if (injection != null) {
return injection;
}
throw new IllegalArgumentException(String.format("No injector was found for %s", getClass().getCanonicalName()));
}
}
Run Code Online (Sandbox Code Playgroud)
FixedDaggerIntentService
public abstract class FixedDaggerIntentService extends IntentService {
public FixedDaggerIntentService(String name) {
super(name);
}
@Override
public void onCreate() {
inject();
super.onCreate();
}
private void inject() {
ApplicationlessInjection injection = ApplicationlessInjection.getInstance(getApplicationContext());
AndroidInjector<Service> serviceInjector = injection.serviceInjector();
if (serviceInjector == null) {
throw new NullPointerException("ApplicationlessInjection.serviceInjector() returned null");
}
serviceInjector.inject(this);
}
}
Run Code Online (Sandbox Code Playgroud)
我的AppComponent
@Singleton
@Component(modules = {
AppModule.class,
ActivityBindingModule.class,
AndroidSupportInjectionModule.class
})
public interface AppComponent extends AndroidInjector<ApplicationlessInjection> {
@Override
void inject(ApplicationlessInjection instance);
@Component.Builder
interface Builder {
@BindsInstance
AppComponent.Builder context(Context applicationContext);
AppComponent build();
}
}
Run Code Online (Sandbox Code Playgroud)
我的AppModule
@Module
public abstract class AppModule {
@Binds
@ApplicationContext
abstract Context bindContext(Context applicationContext);
}
Run Code Online (Sandbox Code Playgroud)
为了完整起见,我的@ApplicationContext注释
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationContext {}
Run Code Online (Sandbox Code Playgroud)
希望我也能用我的代码帮助别人.对我来说,我可以解决所有与引入Dagger 2和奇怪的Android 7.0版本相关的崩溃.
如果需要更多说明,请告诉我!
| 归档时间: |
|
| 查看次数: |
3097 次 |
| 最近记录: |