如何完成几个SingleInstance活动?

时间:2018-10-26 19:28:09

标签: android kotlin back-stack

我有若干与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)

但是,如果我在启动器活动上按回去,则会被转发到以前使用singleInstance模式启动的活动

5 个答案:

答案 0 :(得分:5)

更新11/1/2018:

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

我们在名为LogoutHandler的单例对象中维护注销状态。它与LogoutAwareActivity以外的所有活动继承的类LoginActivity合作,因为它不受注销机制的影响。注销发生时,在LogoutHandler中设置一个标志,直到LogoutAwareActivity的最后一个子项结束,然后清除该标志。

这是一个实现:

LogoutHandler:

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()
    }

}

具体活动:

class ActivityA : LogoutAwareActivity() {

    // ...
}

另一项具体活动:

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都是单个实例。

通过按返回按钮在活动之间进行遍历:

enter image description here

转到LoginActivity,然后按返回按钮:

enter image description here

答案 1 :(得分:2)

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

无论如何,我想您是否可以注销活动,如果用户已经注销,以及他是否确实启动了单个实例启动器活动并使用finish()关闭了这些活动,那么您可以检查活动的onStart。

答案 2 :(得分:2)

在启动初始屏幕之前,添加此行

ActivityCompat.finishAffinity(this)

答案 3 :(得分:1)

  

我有若干与launchMode SingleInstance有关的活动。注销后,我要完成所有活动并打开launchScreen。

这是一种方法:

  1. 让所有活动都扩展自定义BaseActivity
  2. 单击注销按钮后,您可以使用LocalBroadcastManager发送本地广播(在您的应用程序内)。
  3. 在基本活动中,您可以实现侦听器。您可以在监听器中调用finish()
  4. 因此,当用户单击注销按钮时,您会将本地广播发送到所有打开的活动。由于您的所有活动都扩展了公共BaseActivity,因此将调用侦听器并结束活动。
  5. 发送广播后,您可以打开预期的LauncherActivity

请参见How to use LocalBroadcastManager?  更多。

P.S:您可以在onDestroy中取消注册侦听器。由于活动仍然存在,因此不会调用onDestroy。而且,如果它已经被销毁了,那么您就不用担心其他活动了。

答案 4 :(得分:1)

以我的经验,扩展Application类是存储需要在所有活动之间共享的有限数据量的更简单,最有效的方法。

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