Android - onCreate 中不一致的 finish() 行为

Android - Inconsistent finish() behavior in onCreate

我想创建一个 Android 应用程序,它能够设置计时器并处理隐式意图 AlarmClock.ACTION_SET_TIMER。这也将允许它对 Google 助手 'Set timer for' 命令做出反应。

收到此特殊意图后,我希望应用程序设置计时器而不显示 activity(尊重 AlarmClock.EXTRA_SKIP_UI)。

如果我使用 Google 助手设置定时器时应用程序没有启动,它按预期工作:activity 没有显示,但设置定时器的代码被执行。

但是,如果我用启动器启动 activity,然后使用主页按钮 return 到主屏幕(即 activity 仍然可以在最近的应用程序中找到),行为是错误的。显示 activity,调用 onStart() 方法(即使我从 onCreate 调用 finish())。

据我从 the documentation 了解到,如果我从 onCreate 调用 finish(),则不应调用其他生命周期回调,并且不应显示 activity .

更令人费解的是,显然onCreateonStart看到了不同的意图

来自 AndroidManifest.xml:

<activity android:name="com.example.testlifecycle.MainActivity">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>

  <intent-filter>
    <action android:name="android.intent.action.SET_TIMER" />
    <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

MainActivity.kt:

class MainActivity : AppCompatActivity() {
    companion object {
        const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        Log.d(TAG, "onCreate called")
        super.onCreate(savedInstanceState)
        logIntent()

        if (intent.action == AlarmClock.ACTION_SET_TIMER) {
            Log.d(TAG, "Timer intent received, closing")
            // Do something useful here
            setResult(Activity.RESULT_OK)
            finish()
            return
        }

        setContentView(R.layout.activity_main)
    }

    override fun onStart() {
        Log.d(TAG,"onStart called")
        super.onStart()
        logIntent()
    }

    private fun logIntent() {
        Log.d(TAG, "Intent action ${intent.action}")
        Log.d(TAG, "Intent flags ${intent.flags.toString(16)}")

        intent.extras?.keySet()?.forEach {
            Log.d(TAG, "Intent extra $it = ${intent.extras?.get(it)}")
        }
    }
}

场景 1

应用程序未启动,使用Google助手设置定时器。

2020-02-02 18:21:28.376 22269-22269/com.example.testlifycycle D/MainActivity: onCreate called
2020-02-02 18:21:28.408 22269-22269/com.example.testlifycycle D/MainActivity: Intent action android.intent.action.SET_TIMER
2020-02-02 18:21:28.409 22269-22269/com.example.testlifycycle D/MainActivity: Intent flags 10000000
2020-02-02 18:21:28.409 22269-22269/com.example.testlifycycle D/MainActivity: Intent extra android.intent.extra.alarm.SKIP_UI = true
2020-02-02 18:21:28.409 22269-22269/com.example.testlifycycle D/MainActivity: Intent extra com.google.android.apps.gsa.shared.util.starter.IntentStarter.ERROR_TOAST_ID = 2131951799
2020-02-02 18:21:28.410 22269-22269/com.example.testlifycycle D/MainActivity: Intent extra android.intent.extra.REFERRER_NAME = android-app://com.google.android.googlequicksearchbox/https/www.google.com
2020-02-02 18:21:28.410 22269-22269/com.example.testlifycycle D/MainActivity: Intent extra android.intent.extra.alarm.LENGTH = 3600
2020-02-02 18:21:28.410 22269-22269/com.example.testlifycycle D/MainActivity: Intent extra KEY_HANDOVER_THROUGH_VELVET = true
2020-02-02 18:21:28.410 22269-22269/com.example.testlifycycle D/MainActivity: Timer intent received, closing

此处一切正常。

场景 2

应用程序由启动器启动,按主页按钮,然后使用 Google 助手设置定时器。

使用启动器启动应用程序,看起来符合预期:

2020-02-02 18:24:30.052 22269-22269/com.example.testlifycycle D/MainActivity: onCreate called
2020-02-02 18:24:30.055 22269-22269/com.example.testlifycycle D/MainActivity: Intent action android.intent.action.MAIN
2020-02-02 18:24:30.055 22269-22269/com.example.testlifycycle D/MainActivity: Intent flags 10200000
2020-02-02 18:24:30.055 22269-22269/com.example.testlifycycle D/MainActivity: Intent extra profile = 0
2020-02-02 18:24:30.158 22269-22269/com.example.testlifycycle D/MainActivity: onStart called
2020-02-02 18:24:30.158 22269-22269/com.example.testlifycycle D/MainActivity: Intent action android.intent.action.MAIN
2020-02-02 18:24:30.158 22269-22269/com.example.testlifycycle D/MainActivity: Intent flags 10200000
2020-02-02 18:24:30.158 22269-22269/com.example.testlifycycle D/MainActivity: Intent extra profile = 0

按主页键,然后使用 Google 助手:

2020-02-02 18:26:21.398 23158-23158/com.example.testlifycycle D/MainActivity: onCreate called
2020-02-02 18:26:21.402 23158-23158/com.example.testlifycycle D/MainActivity: Intent action android.intent.action.SET_TIMER
2020-02-02 18:26:21.402 23158-23158/com.example.testlifycycle D/MainActivity: Intent flags 10400000
2020-02-02 18:26:21.402 23158-23158/com.example.testlifycycle D/MainActivity: Intent extra android.intent.extra.alarm.SKIP_UI = true
2020-02-02 18:26:21.402 23158-23158/com.example.testlifycycle D/MainActivity: Intent extra com.google.android.apps.gsa.shared.util.starter.IntentStarter.ERROR_TOAST_ID = 2131951799
2020-02-02 18:26:21.403 23158-23158/com.example.testlifycycle D/MainActivity: Intent extra android.intent.extra.REFERRER_NAME = android-app://com.google.android.googlequicksearchbox/https/www.google.com
2020-02-02 18:26:21.403 23158-23158/com.example.testlifycycle D/MainActivity: Intent extra android.intent.extra.alarm.LENGTH = 60
2020-02-02 18:26:21.403 23158-23158/com.example.testlifycycle D/MainActivity: Intent extra KEY_HANDOVER_THROUGH_VELVET = true
2020-02-02 18:26:21.403 23158-23158/com.example.testlifycycle D/MainActivity: Timer intent received, closing
2020-02-02 18:26:21.446 23158-23158/com.example.testlifycycle D/MainActivity: onStart called
2020-02-02 18:26:21.446 23158-23158/com.example.testlifycycle D/MainActivity: Intent action android.intent.action.MAIN
2020-02-02 18:26:21.446 23158-23158/com.example.testlifycycle D/MainActivity: Intent flags 10200000
2020-02-02 18:26:21.447 23158-23158/com.example.testlifycycle D/MainActivity: Intent extra profile = 0

我在这里看到的问题:

  1. onStart 被调用,即使 finsh 是从 onCreate
  2. 调用的
  3. onStart 记录带有操作 MAIN 的意图,而 onCreate 记录(预期)SET_TIMER

我想我可能对 Android intent/lifecycle 机制缺乏了解。对于此事,我将不胜感激。

您正在处理 MainActivity 的两个不同实例:

  • 您点击启动器图标
  • Android 创建了一个 MainActivity 的实例,onCreate()/onStart() 被调用
  • 你按主页
  • 你做了一些 Assistant-y 的事情触发了 SET_ALARM 隐含的 Intent
  • Android 在现有任务中创建 MainActivity 的第二个实例并将该任务置于前台
  • MainActivity 的第二个实例是用 onCreate() 调用的,你 finish() 那个实例
  • 由于你的任务在前台,而且那个任务中还有另一个activity(MainActivity的第一个实例),所以activity被带回前台, onStart() 被调用

我无法专门与 Google 助理交谈,因为我完全避免与它交谈。但是,如果您希望 Google 助理启动的 activity 位于单独的任务中,而不是将任何现有任务带到前台,您需要为此在清单中做一些事情。我的出发点是为不同的场景设置不同的活动,然后在 SET_ALARM activity 上使用 android:taskAffinity 让它路由到一个单独的任务。