Util

【Util】ActivityManage Activity 管理器 範例

【Util】ActivityManage Activity 管理器 範例

Android ActivityManage,是Android在應用中使用的管理活動的繼承框架。

它能讓Android開發者建立可以執行靈活活動之間切換,管理進入及離開活動,活動間切換時候的暫停及繼續和加載活動及資源等更為完善與靈活的應用。

本文將說明Android ActivityManage的重要性及功能,並且介紹如何實現它以及它對Android應用開發的影響。


文章目錄

  1. ActivityManage
  2. ActivityManage Application
  3. ActivityManage Activity
  4. ActivityManage pop
  5. ActivityManage popUntil
  6. ActivityManage onExit

1.ActivityManage

ActivityManage.kt
object ActivityManage {

    private val STACK = ActivityStack()
    private lateinit var topActivity: WeakReference<Activity>
    private lateinit var operations: ExtraOperations

    /**
     * 取得當前Activity
     */
    fun peek(): Activity? {
        return if (null != topActivity.get()) {
            topActivity.get()
        } else {
            STACK.peekFromStack()
        }
    }

    /**
     * 關閉當前Activity
     */
    fun pop() {
        STACK.popFromStack()?.finish()
    }

    /**
     * 關閉直到給定的Activity
     */
    fun <T : Activity?> popUntil(clazz: Class<T>?): T? {
        if (clazz != null) {
            while (!STACK.isEmpty()) {
                val activity = STACK.popFromStack()
                if (activity != null) {
                    if (clazz.name == activity.javaClass.name) {
                        return activity as T
                    }
                    activity.finish()
                }
            }
        }
        return null
    }

    /**
     * 關閉後的清理狀態
     */
    private const val MAX_DOUBLE_EXIT_MILLS = 1000L
    private var lastExitPressedMills = 0L

    interface ExtraOperations {
        fun onExit()
        fun onActivityFinish(activity: Activity)
    }

    fun setOperations(operations: ExtraOperations) {
        this.operations = operations
    }

    fun onExit() {
        val now = System.currentTimeMillis()
        if (now <= lastExitPressedMills + MAX_DOUBLE_EXIT_MILLS) {
            finishAll()
            operations.onExit()
            exitProcess(0)
        } else {
            lastExitPressedMills = now
        }
    }

    /**
     * 關閉全部Activity
     */
    private fun finishAll() {
        while (!STACK.isEmpty()) {
            val activity = STACK.popFromStack()
            activity?.apply {
                finish()
                operations.onActivityFinish(this)
            }
        }
    }

    fun setTopActivity(topActivity: Activity) {
        this.topActivity = WeakReference(topActivity)
    }

    fun push(activity: Activity) {
        STACK.pushToStack(activity)
    }

    fun remove(activity: Activity) {
        STACK.removeFromStack(activity)
    }

    private class ActivityStack {
        private val activityStack = Stack<WeakReference<Activity>>()

        fun isEmpty() = activityStack.isEmpty()

        fun pushToStack(activity: Activity) {
            activityStack.push(WeakReference(activity))
        }

        fun popFromStack(): Activity? {
            while (!activityStack.isEmpty()) {
                val weak = activityStack.pop()
                val activity = weak.get()
                if (activity != null) {
                    return activity
                }
            }
            return null
        }

        fun peekFromStack(): Activity? {
            while (!activityStack.isEmpty()) {
                val weak = activityStack.peek()
                val activity = weak.get()
                if (activity != null) {
                    return activity
                } else {
                    activityStack.pop()
                }
            }
            return null
        }

        fun removeFromStack(activity: Activity) {
            for (weak in activityStack) {
                val act = weak.get()
                if (act === activity) {
                    activityStack.remove(weak)
                    return
                }
            }
        }
    }
}

2.ActivityManage Application

MyApplication.kt
class MyApplication : Application() {

    private val TAG = MyApplication::class.java.simpleName
    var count = 0

    override fun onCreate() {
        super.onCreate()

        registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                ActivityManage.push(activity)
            }

            override fun onActivityStarted(activity: Activity) {
                ActivityManage.setTopActivity(activity)
                if (count++ == 0) {
                    Log.e(TAG, "前台")
                }
            }

            override fun onActivityResumed(activity: Activity) {

            }

            override fun onActivityPaused(activity: Activity) {

            }

            override fun onActivityStopped(activity: Activity) {
                count--
                if (count == 0) {
                    Log.e(TAG, "後台")
                }
            }

            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {

            }

            override fun onActivityDestroyed(activity: Activity) {
                ActivityManage.remove(activity)
            }
        })
    }
}
AndroidManifest.xml
<application
    android:name=".MyApplication">
</application>

3.ActivityManage Activity

activity_first.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FirstActivity">

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/appCompatButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="next"
        android:text="跳頁"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
FirstActivity.kt
class FirstActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        title = "First"
    }

    fun next(view: View) {
        ActivityManage.peek()
            ?.startActivity(Intent(ActivityManage.peek(), SecondActivity::class.java))
    }
}
activity_second.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SecondActivity">

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/appCompatButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="next"
        android:text="跳頁"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
SecondActivity.kt
class SecondActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)

        title = "Second"
    }

    fun next(view: View) {
        ActivityManage.peek()
            ?.startActivity(Intent(ActivityManage.peek(), ThirdActivity::class.java))
    }
}

5.ActivityManage pop

activity_third.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ThirdActivity">

    <androidx.appcompat.widget.AppCompatButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="finish"
        android:text="結束"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
ThirdActivity.kt
class ThirdActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_third)

        title = "Third"
    }

    fun finish(view: View) {
        ActivityManage.pop()
    }
}

6.ActivityManage popUntil

ThirdActivity.kt
class ThirdActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_third)

        title = "Third"
    }

    fun finish(view: View) {
        ActivityManage.popUntil(FirstActivity::class.java)
    }
}

7.ActivityManage onExit

ThirdActivity.kt
class ThirdActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_third)

        title = "Third"
    }

    fun finish(view: View) {
        ActivityManage.setOperations(object : ActivityManage.ExtraOperations {
            override fun onExit() {
                Log.e(ThirdActivity::class.java.simpleName, "onExit")
            }

            override fun onActivityFinish(activity: Activity) {
                Log.e(ThirdActivity::class.java.simpleName, activity.localClassName)
            }
        })

        ActivityManage.onExit()
    }
}

發表迴響