Android启动应用程序等到异步代码执行完成后再打开活动

时间:2017-01-18 12:36:07

标签: android android-lifecycle

在我的应用程序启动时,我想执行一些初始化代码。

我需要初始化:

  • RESTkit通过设置一些HTTP标头
  • 需要向服务器发出请求以获取有关当前用户的信息
  • 需要向服务器发出请求以从当前用户获取配置

如您所知,这些是我需要执行的异步任务。

我目前拥有的是MainActivity.onCreate()中的初始化代码,其中包含一个将打开CoreActivity的回调方法。当我对应用程序进行冷启动时,这可以正常工作。

问题从应用程序移动到后台开始,Android可以将其杀死以释放内存。我现在通过禁止Developer options下的后台进程强制执行此操作。

因此,如果我打开了ExampleActivity并将应用程序移至后台,则当我将其移动到前台时,Android会尝试重新初始化ExampleActivity。这意味着我的应用程序无法正确初始化,因为MainActivity.onCreate()永远不会被执行。

所以我想我可以将初始化代码移到Application.onCreate()。我面临的问题是onCreate()完成执行并在初始化代码仍在运行时打开ExampleActivity。

我注意到在Application.onCreate()中睡眠主线程很糟糕。还有一个观看isInitialized布尔值的while循环永远不会变为真,并以无限循环结束。

我应该如何处理这种情况?

我想做这些步骤

  1. App启动
  2. 应用正在初始化,需要等待我的回调方法
  3. 初始化完成后调用回调方法,打开活动。

3 个答案:

答案 0 :(得分:2)

我的申请多年来一直存在非常接近的问题。即在开始几乎任何活动之前(甚至onResume ...)我需要确保我的应用程序已初始化。 到目前为止,我已经将同步初始化代码的调用插入到许多活动的onCreate方法中(在初始化已经完成的情况下,调用当然立即完成)。

随着应用程序的逐渐增长,初始化需要花费越来越多的时间,这有时会在不同的活动中导致ANR,所以我还需要在任何活动开始时实现异步初始化。

所以,我最近实现了以下方法,可以查看/测试(参见GitHub项目,特别是这个类:MyContextHolder.java

  1. 将对我的静态定义的应用程序初始化代码的调用插入到每个活动的onCreate方法中,这需要初始化应用程序,将调用的Activity实例(this)传递给初始化代码。基本上它看起来像:

    if (MyContextHolder.initializeThenRestartMe(this)) {
        return;
    }
    
  2. 一个。如果已完成初始化,请立即返回 false 。 完成。

    湾如果需要初始化,请抓住Activity的启动参数+应用程序的上下文,以便稍后可以重新启动活动。最简单的情况:存储Activity的Intent。 (activity.getIntent()和activity.getApplicationContext())

  3. 使用.finish()方法完成尚未显示的Activity。

  4. 可选择显示一些"请稍等..."对用户的活动。 (我还不需要这个......)

  5. 使用applicationContext在后台线程(专用AsyncTask)中进行应用程序初始化。见MyFutureContext.java

  6. 完成后,使用其存储的参数重新启动Activity。例如。使用存储的Intent和应用程序的Context。像这样: applicationContext.startActivity(意图);

  7. 一个有用的提示:为了不看正在重启的闪烁活动,将默认应用程序的主题(在Android Manifest中)设置为透明的。超强!

    以下样式定义来自themes.xml文件

    <style name="Theme.Transparent" parent="Theme.AppCompat.NoActionBar">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:backgroundDimEnabled">false</item>
    </style>
    

答案 1 :(得分:1)

为什么不添加一个会执行INIT或至少听到回调的Splash Activity - INIT_DONE 。收到此类回调后,您就可以开始所需的活动。

通过这个你正在实现以下目标

  • 良好的用户体验
  • 用户知道推迟实际活动的原因。
  • 没有滞后以查看所需的活动。
  • 由于挫折感,用户不会卸载应用的概率增加:D

更新:为什么不从Application.java文件中检查INIT_State。如果app INIT没有完成,则加载基本Activity或Splash,然后应用程序将仅在app init完成的状态下工作。

为了实现这一点,你应该有一个baseActivity,它将被除了splash活动之外的流中的每个其他活动扩展。因此,在每个活动Resume事件中,您可以检查INIT状态,并根据它可以继续加载活动,或者可以将用户重定向到启动屏幕,以便INIT进程完成,然后用户登陆其他活动。

此外,为此您还可以从启动画面启动AppInit进程。这将有助于监控控件,或者您甚至可以将事件用于相同的目的以符合您的设计准则。

答案 2 :(得分:0)

我看到两种选择:

  • 如果“MainActivity被os杀死”

    • 再次启动asyc加载并松开之前的结果
    • MainActivity = SplashActivity触发AsyncTask。当AsyncTask成功完成或完成错误时,将启动其他活动(您的MainGuiActivity)。
  • 如果不能再次执行Async-stuff:

    • 实现一个即使活动被取消也会继续运行的LoginService。
    • mainActivity检查LoginService是否已在运行,如果没有,则启动它。