繁体   English   中英

如何在活动重新创建后处理 onCreate 中 Dagger 注入所需的未初始化资源?

How to handle uninitialized resources required for Dagger injection in onCreate after activity re-creation?

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

我将 Dagger 添加到我的旧 Android 应用程序中,并试图弄清楚如何处理依赖于非 Dagger 对象的依赖项,这些对象在正常应用程序初始化期间创建但在后台 + 不活动后的活动重启期间未重新创建。

现有代码

在旧代码中,在身份验证代码路径期间,我们构造了一个“会话”object,其中包含创建经过身份验证的 Retrofit 对象所需的令牌和其他内容。 某些活动依赖于存在的 session object,并且用户在不通过身份验证代码路径的情况下无法正常访问它们。 但是,如果应用程序处于非活动状态然后稍后恢复,则平台将尝试直接重新创建活动而不通过身份验证代码路径,因此 session object 将为 Z37A6259CC0C1DAE29BD9A7866489DFF。

为了防止这种情况发生,历史上依赖于登录的每个活动都派生自“SessionActivity”,它的 onCreate 检查我们是否已登录,如果没有完成活动并启动应用程序的入口点。 (这将触发“会话” object 被重新创建;用户将不得不再次导航回该屏幕,但至少没有崩溃)

class SessionActivity {

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);

    if( LegacySingleton.getInstance().session == null ) {
    {
        Intent intent = new Intent(this, LauncherActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
        finish();
        return;
    }
}

}

新代码

我现在正在添加 Dagger,并且希望能够注入一个 Retrofit object,它是使用 Z21D6F40CFB511982E4424E0E250A95549EB269693131 构建的 Retrofit object

@Provides
fun provideRetrofit(): Retrofit {
    return LegacySingleton.getInstance().session!!.authenticatedRetrofit
}

然后依赖于登录的示例活动将具有类似的 onCreate

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

有一个明显的问题:如果 LegacySingleton.getInstance().session 返回 null (因为它会在重新创建路径中)然后我们会崩溃。 是否有一个共同的模式来解决这个问题?

尝试1:

如果 session 是 null,我的第一个倾向是在 provideRetrofit 中抛出 IllegalStateException,然后依赖登录的活动会说

@Override
protected void onCreate(Bundle savedInstanceState)
{
    try {
       ((MyComponentProvider) getApplicationContext()).getComponent().inject(this);
   } catch (ex: IllegalStateException) {
        Intent intent = new Intent(this, LauncherActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
        finish();
        return;
   }        
    super.onCreate(savedInstanceState);
}

(显然这将被考虑到辅助方法中,但为了简单起见在这里写出来)

但是,这不起作用,因为 Android 要求所有对 onCreate 的调用都调用到 super.onCreate。

尝试2:

我可以说

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    try {
       ((MyComponentProvider) getApplicationContext()).getComponent().inject(this);
   } catch (ex: IllegalStateException) {
        Intent intent = new Intent(this, LauncherActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
        finish();
        return;
   }        
}

但这打破了在super.onCreate之前注入的匕首原则。 (然后确保在 super.onCreate 回调到派生的 class 并需要其中一个依赖项的情况下准备好依赖项)所以这在某些情况下可能有效,但如果有人开始依赖 super.onCreate 中的这些依赖项,那么我会在运行时命中 NPE。 不是很好。

尝试 3:

我可以执行注入并跟踪它是否成功,例如

@Override
protected void onCreate(Bundle savedInstanceState)
{
    Val injectionSucceeded = try {
       ((MyComponentProvider) getApplicationContext()).getComponent().inject(this);
       true
   } catch (ex: IllegalStateException) {
       false
   }
    super.onCreate(savedInstanceState);
   If (!injectionSucceeded)
        Intent intent = new Intent(this, LauncherActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
        finish();
        return;
   }        
}

但是和尝试2有同样的问题; 如果注入失败,那么无论如何我都会调用 super.onCreate 并且并非所有依赖项都可能已被注入。

尝试4:

我本可以提供 Nullable 对象

@Provides
fun provideRetrofit(): Retrofit? {
    return LegacySingleton.getInstance().session?.authenticatedRetrofit
}

但是每个客户在使用它们之前都需要检查依赖项的可空性,这将是一个巨大的痛苦。 (我什至不确定这是否可能)

代码实验室建议:

Google 的 Dagger 代码实验室暗示了这个问题: https://developer.android.com/codelabs/android-dagger#12

重要提示:进行条件字段注入(就像我们在 MainActivity.kt 中所做的那样,仅当用户登录时才进行注入)是非常危险的。 开发人员必须了解这些条件,并且在与注入的字段交互时可能会遇到 NullPointerExceptions。 为了避免这个问题,我们可以通过创建一个 SplashScreen 来添加一些间接性,该 SplashScreen 根据用户的 state 路由到 Registration、Login 或 Main。

但这对于一个现有的应用程序来说似乎并不实用,它有十几个 SessionActivity 子类,这些子类想要用 Retrofit 对象注入自己。

有没有人有更好的主意?

问题暂未有回复.您可以查看右边的相关问题.
1 匕首2清单重新创建

我遇到了使用Dagger2保存“缓存”数据的问题。 我有Application Component和Authentication Subcomponent 。 Authentication Subcomponent具有缓存模块: 前两个缓存对象工作正常。 国家列表有问题。 每 ...

2 Koin FragmentFactory 无法处理活动重新创建

我正在使用最新的 Koin 版本3.1.2 。 我有一个基本的Fragment ,它接受一个 String 参数给它的构造函数。 我的 Koin 设置如下: 活动: 分段: Koin模块: 为了模拟活动重新创建,我在开发人员选项中打开了Don't keep activities标志 ...

3 Android:方向更改后如何禁止重新创建Activity?

我有一个带有Frgment的Android活动。 当我的应用程序启动时,一个列表视图将加载从服务器发送的10个元素。 (简单的请求)。 当我更改设备的方向时,将重新创建该活动,同时还会看到微调框,其中包含我的请求以加载列表视图。 我该如何禁止重新创建活动? 我已经设置了标志 ...

4 活动重新创建意图附加项为空

我的应用程序包含MainActivity并使用全屏片段来显示内容。 我正在尝试在应用程序重新创建期间实现以下功能(当应用程序已经在后台运行了很长时间,被系统杀死然后它被带到了前台) 如果用户手动重新创建应用程序(通过从最近的应用程序列表中选择应用程序),则应重新创建主活动,然后重新创 ...

6 如何添加 Fragment 以便它不会在 Activity 重新创建中保留?

我正在动态地向/从我的活动添加和删除视图。 这些视图中的每一个都分配了一个 id 并充当特定片段的容器。 我使用条件逻辑向这些视图中的每一个添加一个片段,如下所示: 这种条件逻辑确保给定的 View 在 Activity 的生命周期内只添加了一次 Fragment。 除非重新创建活动(例如由于 ...

8 关于配置更改和上下文的活动重新创建的说明

我对Android开发很陌生,我正在寻找有关我正面临的问题的解释,以便更深入地了解Android。 我有这段代码: 如果下拉列表可见并且配置发生更改(屏幕方向),我将收到BadTokenException。 我知道活动被销毁并且创建了一个新的替换它,但是我不太明白实际发生了什 ...

2012-01-27 17:18:57 1 490   android
9 使用Fragments / FragmentActivity保留跨活动重新创建的数据

我一直在浏览android文档和网络上的各种资源,但是我似乎无法让我的应用在整个活动重新创建期间保留数据(例如按返回按钮退出,然后从图标进入应用或任务管理器)。 我有3个类:主要的一个类(扩展FragmentActivity),一个片段和一个应在应用程序不活动时在后台运行的类,创建活动后, ...

10 android片段在onDestroy之后重新创建 - FragmentManagerState ClassNotFound

我正在使用带有3个片段的viewpager进行活动。 在启动选择图像后,调用onactivityResult但是 启动器活动被销毁并再次创建。 (我已经开启了不要保留任何活动,开发者设置。) 现在问题是在创建活动之后,还会再次创建片段(通过日志观察) 这将显示在 ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM