如何完成多个 SingleInstance Activity?

How to finish several SingleInstance Activities?

我有几个使用 launchMode SingleInstance 的活动。注销时我想完成所有活动并打开 launchScreen。

val intent = Intent(context, LauncherActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
(context as AppCompatActivity).finishAffinity()
context.startActivity(intent)

但是,如果我在启动器上按回activity,我将被转发到之前使用单实例模式启动的活动

我不知道您到底想做什么,但我觉得您可以以不同的方式重新设计您的应用程序以做得更好。

关于你的问题 - 我猜你可以检查 onStart 的活动,如果用户已经注销,如果他确实启动了一个单一的实例启动器 activity 并用 finish() 关闭这些活动.

I have several activities with launchMode SingleInstance. On log out i want to finish all activities and open launchScreen.

这是一种方法:

  1. 让所有活动扩展自定义 BaseActivity
  2. 点击注销按钮后,您可以使用LocalBroadcastManager发送本地广播(在您的应用程序内)。
  3. 在基础中 activity 您可以实现侦听器。您可以在侦听器内部调用 finish()
  4. 所以当用户点击注销按钮时,你向所有打开的活动发送本地广播。由于您的所有活动都扩展了公共 BaseActivity,因此会调用侦听器并完成活动。
  5. 发送广播后,即可打开意向LauncherActivity.

How to use LocalBroadcastManager? 更多。

P.S:您可以在onDestroy中取消注册监听器。由于 activity 仍然存在,因此不会调用 onDestroy。如果它已经被摧毁,那么你就少了一个 activity 担心。

2018 年 11 月 1 日更新:

我已经测试了多种处理它的方法,例如事件传播、意图标志、计算 activity 个实例等。有一些奇怪的场景,例如顺序启动多个 singleInstance 活动。在这种情况下,中间活动根本不会启动(onCreate 方法不会被调用),在按下后退按钮后,它们就会启动。因此,之前的任何一种方法都行不通!由于这个问题有点奇怪,所以我尝试用有点奇怪的方式解决它。

我们在名为 LogoutHandler 的单例 object 中维护注销状态。它与 class LogoutAwareActivity 合作,除 LoginActivity 之外的所有活动都继承它,因为它不应受到注销机制的影响。当注销发生时,在 LogoutHandler 中设置一个标志,直到 LogoutAwareActivity 的最后一个 child 完成然后清除标志。

这是一个实现:

注销处理程序:

import java.util.*

object LogoutHandler {

    private var isLogout = false
    private var timerWatchDog: TimerWatchDog? = null

    fun isLogout() = isLogout

    fun onActivityDestroyed() {
        if (isLogout) {
            timerWatchDog?.refresh(Runnable {
                isLogout = false
                timerWatchDog = null
            })
        }
    }

    fun logout() {
        isLogout = true
        timerWatchDog = TimerWatchDog(500)
    }

    private class TimerWatchDog(private val delay: Long) : Runnable {

        private var timer: Timer? = null
        private var runnable: Runnable? = null

        fun refresh(runnable: Runnable) {
            this.runnable = runnable
            timer?.cancel()

            val timerTask = object : TimerTask() {
                override fun run() {
                    Thread(this@TimerWatchDog).start()
                }
            }
            timer = Timer()
            timer?.schedule(timerTask, delay)
        }

        override fun run() {
            runnable?.run()
        }
    }

}

LogoutAwareActivity:

import android.support.v7.app.AppCompatActivity

abstract class LogoutAwareActivity : AppCompatActivity() {

    override fun onResume() {
        super.onResume()
        if (LogoutHandler.isLogout()) {
            finish()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        LoginHandler.onActivityDestroyed()
    }

}

一个具体的Activity:

class ActivityA : LogoutAwareActivity() {

    // ...
}

再具体Activity:

class ActivityB : LogoutAwareActivity() {

    // ...
}

您的登出功能:

fun logout() {
    val intent = Intent(context, LoginActivity::class.java)
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

    LogoutHandler.logout()
    context.startActivity(intent)
}

视觉结果:

MainActivityActivityAActivityBActivityC 都是单实例。

通过按后退按钮在活动之间移动:

前往 LoginActivity 然后按后退按钮:

在启动启动画面之前添加此行

ActivityCompat.finishAffinity(this)

根据我扩展应用程序的经验,class 是存储需要在所有活动之间共享的有限数据量的最简单、最有效的方法。

在您的情况下,您可以创建一个 class 保存您的登录数据并将其实例存储在您的自定义应用程序对象中,所有活动都可以访问它。他们可以在开始时检查登录可用性、订阅更改并在需要完成时得到通知。 Application 对象本身可以订阅更改并在需要时启动登录 activity。