【问题标题】:android: what is needed to restore Activity status after back-navigation?android:返回导航后恢复Activity状态需要什么?
【发布时间】:2019-02-27 11:43:05
【问题描述】:

免责声明:我是一名经验丰富的程序员,但几乎是 Android 新手;我可能会问显而易见的问题。

我的暂定应用程序有一个相当简单的 GUI。

具体来说,我有一个最上面的Switch 来打开/关闭我的应用程序。

启动时开关关闭。

当它打开时,我可以从菜单中选择一个子 MonitorActivity 来显示正在发生的事情(某种运行日志)。

MonitorActivity 已正确链接到父级,所以我可以返回到MainActivity

到目前为止,一切都很好。一切正常。

问题是当我向后导航时MainActivity 完全重置,就像重新开始一样;特别是我的开/关Switch 回到off 位置。

我对@9​​87654321@的理解是MainActivity应该已经停止了;相关的sn-p是:

前一个活动仍保留在堆栈中,但已停止。当一个 活动停止,系统保留其用户的当前状态 界面。当用户按下返回按钮时,当前活动 从堆栈顶部弹出(活动被破坏)和 上一个活动恢复(其 UI 的上一个状态是 已恢复)。

据我了解,我不应该做任何特定的事情来恢复MainActivity 状态;这是正确的吗?

我应该发布我的AndroidMainfest.xml(或其他文件)吗?

更新(根据要求):

我严格遵循MyFirstApp的模式:

  • 使用startActivity(intent)MainActivity开始MonitorActivity
  • 使用主菜单上的左箭头进行后退导航(使用:<activity android:name=".DisplayMessageActivity" android:parentActivityName=".MainActivity"> in AndroidManifest.xml

注意:这正是MyFirstApp 的行为:当从DisplayMessageActivity 回来时,EditText 小部件的内容消失了(即使没有明确清除它)。

也许我应该重命名问题:“如何在 'MyFirstApp' 中的 'Send' 之后保留 'message'?”

UPDATE2:我重写了几个回调来追踪真正发生的事情; 这是日志(cmets inline,查找'

02/27 16:05:24: Launching app
$ adb install-multiple -r -t -p it.condarelli.myfirstapp /home/mcon/AndroidStudioProjects/MyfirstApp/app/build/intermediates/split-apk/debug/slices/slice_2.apk 
Split APKs installed in 483 ms
$ adb shell am start -n "it.condarelli.myfirstapp/it.condarelli.myfirstapp.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -D
Waiting for application to come online: it.condarelli.myfirstapp | it.condarelli.myfirstapp.test
Waiting for application to come online: it.condarelli.myfirstapp | it.condarelli.myfirstapp.test
Connecting to it.condarelli.myfirstapp
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/elli.myfirstap: Not late-enabling -Xcheck:jni (already on)
W/elli.myfirstap: Unexpected CPU variant for X86 using defaults: x86
W/ActivityThread: Application it.condarelli.myfirstapp is waiting for the debugger on port 8100...
I/System.out: Sending WAIT chunk
I/System.out: Debugger has connected
    waiting for debugger to settle...
Connected to the target VM, address: 'localhost:8603', transport: 'socket'
I/System.out: waiting for debugger to settle...
I/System.out: waiting for debugger to settle...
I/System.out: waiting for debugger to settle...
I/chatty: uid=10085(it.condarelli.myfirstapp) identical 2 lines
I/System.out: waiting for debugger to settle...
I/System.out: debugger has settled (1354)
W/elli.myfirstap: JIT profile information will not be recorded: profile file does not exits.
I/chatty: uid=10085(it.condarelli.myfirstapp) identical 10 lines
W/elli.myfirstap: JIT profile information will not be recorded: profile file does not exits.
I/InstantRun: starting instant run server: is main process
I/MainActivity: onCreate(null)             <<<<< This is App start
W/elli.myfirstap: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)
    Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (light greylist, reflection)
I/MainActivity: onStart()
I/MainActivity: onResume()
I/MainActivity: onPostResume()
D/OpenGLRenderer: HWUI GL Pipeline
D/: HostConnection::get() New Host Connection established 0xcb81c0c0, tid 17161
I/ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
    android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
I/OpenGLRenderer: Initialized EGL, version 1.4
D/OpenGLRenderer: Swap behavior 1
W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
D/OpenGLRenderer: Swap behavior 0
D/EGL_emulation: eglCreateContext: 0xde3584a0: maj 2 min 0 rcv 2
D/EGL_emulation: eglMakeCurrent: 0xde3584a0: ver 2 0 (tinfo 0xcb943060)
D/EGL_emulation: eglMakeCurrent: 0xde3584a0: ver 2 0 (tinfo 0xcb943060)
I/AssistStructure: Flattened final assist data: 2344 bytes, containing 1 windows, 8 views
I/MainActivity: onPause()                  <<<<< This is first message after I pressed 'Send' button.
W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@18e99e1
I/DisplayMessageActivity: onStart()
I/DisplayMessageActivity: onResume()
I/DisplayMessageActivity: onPostResume()
D/EGL_emulation: eglMakeCurrent: 0xde3584a0: ver 2 0 (tinfo 0xcb943060)
D/EGL_emulation: eglMakeCurrent: 0xde3584a0: ver 2 0 (tinfo 0xcb943060)
D/EGL_emulation: eglMakeCurrent: 0xde3584a0: ver 2 0 (tinfo 0xcb943060)
D/EGL_emulation: eglMakeCurrent: 0xde3584a0: ver 2 0 (tinfo 0xcb943060)
D/EGL_emulation: eglMakeCurrent: 0xde3584a0: ver 2 0 (tinfo 0xcb943060)
I/MainActivity: onStop()
I/MainActivity: onSaveInstanceState()      <<<<< This is where log stops while DisplayMessageActivity is focused
I/DisplayMessageActivity: onPause()        <<<<< This is first message after Back-navigation
I/MainActivity: onDestroy()                <<<<< WHY THIS NOW??
W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@bd33145
I/MainActivity: onCreate(null)             <<<<< MainActivity is recreated from scratch
I/MainActivity: onStart()
I/MainActivity: onResume()
I/MainActivity: onPostResume()
D/EGL_emulation: eglMakeCurrent: 0xde3584a0: ver 2 0 (tinfo 0xcb943060)
D/EGL_emulation: eglMakeCurrent: 0xde3584a0: ver 2 0 (tinfo 0xcb943060)
D/EGL_emulation: eglMakeCurrent: 0xde3584a0: ver 2 0 (tinfo 0xcb943060)
I/DisplayMessageActivity: onStop()
I/DisplayMessageActivity: onDestroy()

我做错了什么?

【问题讨论】:

  • 我认为你使用了从 MonitorActivity 到 MainActivity 的意图,你能补充一下吗?
  • @GianlucaBenucci:谢谢。我按要求更新了问题。

标签: android android-activity navigation back


【解决方案1】:

您的问题与您使用“向上导航”(即:菜单栏中的箭头)而不是使用“返回”按钮有关。我假设,如果您按 BACK 按钮返回您的MainActivity,一切都会按您的意愿进行。

您应该通过删除来禁用“向上导航”:

android:parentActivityName=".MainActivity"

来自清单中的&lt;activity&gt; 声明。

当您详细了解如何自定义“向上导航”的行为时,您可以确保当您使用它返回时,不会创建先前Activity 的新实例,而是现有的实例被重用。

【讨论】:

  • 我可以确认使用系统 [
【解决方案2】:

我认为您可以存储 MainActivity 的状态并使用 startActivityForResult() 启动子项。

这是 kotlin 中的一个示例(我省略了代码中不相关的部分):

class ProductDataActivity : BaseActivity(),ProductDataFragment.ProductDataListener {

    private var productData: ProductBinding? = null

    companion object {
        private const val INSTANCE_STATE_PRODUCT_DATA = "state_product_data"
        private const val RESULT_DATA = 1
    }

    override fun onSaveInstanceState(outState: Bundle?) {
        outState?.putSerializable(INSTANCE_STATE_PRODUCT_DATA, this.productData)
        super.onSaveInstanceState(outState)
    }

    override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
        this.productData = savedInstanceState?.getSerializable(INSTANCE_STATE_PRODUCT_DATA) as ProductBinding
        super.onRestoreInstanceState(savedInstanceState)
    }

    override fun onDataClicked() {
        val intent = TabProductDetailsActivity.getCallingIntent(this, productData!!, false)
        this.startActivityForResult(intent, RESULT_DATA)
    }

还有其他活动:

class TabProductDetailsActivity : BaseActivity() {

    private var productData: ProductBinding? = null //The activity is started with an intent as you can see above in the ProducDataActivity.

   companion object {
        const val INTENT_EXTRA_PRODUCT_DATA = "intent_product_data"
    }

   override fun onBackPressed() {
        val resultIntent = Intent()
        resultIntent.putExtra(INTENT_EXTRA_PRODUCT_DATA, productData)
        setResult(Activity.RESULT_OK, resultIntent)
        finish()
    }

我希望你能理解我在这里做什么,基本上我将一个对象从一个活动传递到另一个活动,当我按下后退按钮时,我启动活动没有问题。不确定这是否正是您想要的,但我认为它为您可以采用的众多方法之一提供了一些启示。

【讨论】:

  • 我能理解你在说什么。 AFAIK 这是将一些自定义数据传递回启动活动所必需的;小部件属性应该不需要;注意 onCreate() 是 not 当我返回导航时调用的。另外:我不确定对“finish()”的调用是否正确,因为子活动很快就会被销毁。
  • 嗯,我明白你的意思了。也许如果您向我们展示您的活动代码,我们将获得更多帮助。关于finish(),在这种情况下我使用它是因为我已经完全覆盖了后按。
  • 请查看更新。我现在正在使用普通的 [MyFirstApp)(developer.android.com/training/basics/firstapp/…),所以“我的代码”是无关紧要的(如果需要,我可以粘贴 bin,但那里很混乱)。我刚刚添加了一些“Log.i()”消息来跟踪 Activity 生命周期。
【解决方案3】:

事实证明,“罪魁祸首”是 android.support.v7.app.AppCompatActivity 的使用,似乎(经过大量调试后)在 dispatchMessage() 末尾无条件调用 requestDestroy()startActivity(intent)发起的链。

onSaveInstanceState() 的默认实现尽职尽责地将小部件状态保存在 Bundle 中,但这没有传递给 MainActivity.onCreate(null)

制作public class MainActivity extends Activity { ...(而不是public class MainActivity extends AppCompatActivity)可以解决问题(它还会对ActionBar 和其他组件造成严重破坏,但这是另一回事了)。

【讨论】:

  • 其实没有。如果你不从AppCompatActivity 继承,那么各种各样的东西都不适合你。在现代 Android 中,您必须从 AppCompatActivity 继承才能获得预期的外观和行为。请参阅我的答案以解决您的问题。
  • @DavidWasser:我已经猜到了这么多,但官方文档似乎暗示“(back|up)-navigation”应该开箱即用。这显然是不真实的;欢迎任何指针。
猜你喜欢
  • 1970-01-01
  • 2013-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-26
  • 1970-01-01
相关资源
最近更新 更多