Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to finish several SingleInstance Activities?

I have several activities with launchMode SingleInstance. On log out i want to finish all activities and open 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)

However if i press back at Launcher activity i am forwarded to previously launched activities with singleInstance mode

like image 568
Yarh Avatar asked Dec 13 '22 14:12

Yarh


2 Answers

UPDATE 11/1/2018:

I've tested multiple approach to deal with it such as event propagation, intent flags, counting activity instances, etc. There is some weird scenarios such as starting multiple singleInstance activities sequentially. In this case, middle activities doesn't start at all (onCreate method isn't called) and after pressing back button, they'll be started. Therefore no one of the prior approaches works! As the issue is a bit strange, I tried to solve it using a bit strange way.

We maintain the logout state in a singleton object called LogoutHandler. It cooperates with a class LogoutAwareActivity which is inherited by all activities except LoginActivity because it should not be affected by logout mechanism. When the logout occurs, a flag is set in the LogoutHandler until the last child of LogoutAwareActivity has finished then clears the flag.

Here is an implementation of that:

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

}

A concrete Activity:

class ActivityA : LogoutAwareActivity() {

    // ...
}

Another concrete Activity:

class ActivityB : LogoutAwareActivity() {

    // ...
}

Your logout function:

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

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

Visual Result:

All of MainActivity, ActivityA, ActivityB and ActivityC are single instance.

Traversing between activities by pressing back button:

enter image description here

Going to LoginActivity then pressing back button:

enter image description here

like image 93
aminography Avatar answered Dec 17 '22 22:12

aminography


Before launching splash screen add this line

ActivityCompat.finishAffinity(this)
like image 25
Sachin Kasaraddi Avatar answered Dec 17 '22 22:12

Sachin Kasaraddi