Skip to content

如何知晓当前是在哪一个Activit

在 Android 开发中,获取当前正在显示的 Activity 可以通过以下方法实现(Kotlin 代码示例):


方法 1:通过基类 Activity 记录当前实例

为所有 Activity 添加一个公共基类,通过静态变量记录当前 Activity。

步骤 1:创建基类 BaseActivity

kotlin
open class BaseActivity : AppCompatActivity() {
    companion object {
        // 使用弱引用避免内存泄漏
        private var currentActivityRef: WeakReference<Activity>? = null

        // 获取当前 Activity
        fun getCurrentActivity(): Activity? {
            return currentActivityRef?.get()
        }
    }

    override fun onResume() {
        super.onResume()
        currentActivityRef = WeakReference(this)
    }

    override fun onPause() {
        super.onPause()
        // 可选:根据需要清空引用
        // currentActivityRef?.clear()
    }
}

步骤 2:其他 Activity 继承 BaseActivity

kotlin
class MainActivity : BaseActivity() { /* ... */ }
class DetailActivity : BaseActivity() { /* ... */ }

步骤 3:获取当前 Activity

kotlin
val currentActivity = BaseActivity.getCurrentActivity()
if (currentActivity is MainActivity) {
    Log.d("CurrentActivity", "当前是 MainActivity")
}

方法 2:通过 Application 监听 Activity 生命周期

利用 Application.ActivityLifecycleCallbacks 全局监听所有 Activity 的生命周期。

步骤 1:注册生命周期回调

kotlin
class MyApp : Application() {
    companion object {
        private var currentActivityRef: WeakReference<Activity>? = null

        fun getCurrentActivity(): Activity? {
            return currentActivityRef?.get()
        }
    }

    override fun onCreate() {
        super.onCreate()
        registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
            override fun onActivityResumed(activity: Activity) {
                currentActivityRef = WeakReference(activity)
            }

            override fun onActivityPaused(activity: Activity) {
                // 可选:清空引用
                // if (currentActivityRef?.get() == activity) {
                //     currentActivityRef = null
                // }
            }

            // 其他生命周期方法留空即可
            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
            override fun onActivityStarted(activity: Activity) {}
            override fun onActivityStopped(activity: Activity) {}
            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
            override fun onActivityDestroyed(activity: Activity) {}
        })
    }
}

步骤 2:在 AndroidManifest.xml 中声明 Application

xml
<application
    android:name=".MyApp"
    ... >
</application>

步骤 3:获取当前 Activity

kotlin
val currentActivity = (applicationContext as MyApp).getCurrentActivity()
Log.d("CurrentActivity", "当前 Activity: ${currentActivity?.javaClass?.simpleName}")

方法 3:通过反射获取 Activity 栈(需权限)

直接访问系统 Activity 栈(适用于调试,但可能不兼容所有设备)。

代码示例

kotlin
fun getCurrentActivityViaReflection(): Activity? {
    return try {
        val activityThreadClass = Class.forName("android.app.ActivityThread")
        val activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null)
        val activitiesField = activityThreadClass.getDeclaredField("mActivities")
        activitiesField.isAccessible = true

        val activities = activitiesField.get(activityThread) as Map<*, *>
        for (entry in activities.values) {
            val activityRecordClass = entry?.javaClass
            val pausedField = activityRecordClass?.getDeclaredField("paused")
            pausedField?.isAccessible = true
            if (pausedField?.getBoolean(entry) == false) { // 找到未暂停的 Activity
                val activityField = activityRecordClass.getDeclaredField("activity")
                activityField.isAccessible = true
                return activityField.get(entry) as Activity
            }
        }
        null
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

注意事项

  • 需要权限:部分设备需要 android.permission.GET_TASKS(已废弃)。
  • 兼容性差:不同 Android 版本实现可能不同,不推荐正式环境使用。

方法 4:使用第三方库

例如 Android-ActivityManager 或自定义工具类。

示例:通过 ActivityManager 获取前台 Activity

kotlin
fun getForegroundActivity(context: Context): String? {
    val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    val tasks = am.getRunningTasks(1) // 已废弃,仅适用于旧版本
    return if (tasks.isNotEmpty()) {
        tasks[0].topActivity?.className
    } else {
        null
    }
}

注意

  • Android 10+ 限制getRunningTasks 已废弃,无法获取其他应用的信息。
  • 仅限调试:正式环境需使用前两种方法。

最佳实践

  1. 推荐方法
    • 优先使用 方法 2(Application 监听),无需侵入 Activity 代码。
    • 若需要兼容性,使用 方法 1(基类)
  2. 避免场景
    • 不要依赖当前 Activity 处理核心业务逻辑(应通过 ViewModel 或数据驱动)。
    • 避免在后台线程频繁获取当前 Activity。

总结

方法优点缺点
基类记录简单直接需所有 Activity 继承基类
Application 监听全局监听,无侵入性需自定义 Application
反射无需修改代码兼容性差,可能被系统限制
第三方库/系统 API快速实现权限限制,Android 版本差异

根据需求选择合适方案,推荐 方法 2 作为通用解决方案。

随时随地退出程序

在 Android 开发中,要实现在任何界面都能「彻底退出应用」,需结合 任务栈管理进程终止。以下是 Kotlin 的完整解决方案:


方案 1:优雅退出(推荐)

通过清理任务栈并跳转到主界面,适用于需要保留应用进程但关闭所有 Activity 的场景(如退出到登录页)。

步骤 1:创建退出工具类

kotlin
object AppExitUtils {

    /**
     * 退出到指定 Activity(如登录页),并清空任务栈
     * @param context 上下文
     * @param targetActivity 目标 Activity 类(如 LoginActivity::class.java)
     */
    fun exitToActivity(context: Context, targetActivity: Class<*>) {
        val intent = Intent(context, targetActivity).apply {
            flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
        }
        context.startActivity(intent)
        (context as? Activity)?.overridePendingTransition(0, 0) // 禁用过渡动画
    }

    /**
     * 完全退出应用(关闭所有 Activity 并终止进程)
     */
    fun exitApp(context: Context) {
        // 1. 关闭所有 Activity
        ActivityCollector.finishAll()
        // 2. 终止进程(可选,通常不需要)
        // android.os.Process.killProcess(android.os.Process.myPid())
        // System.exit(0)
    }
}

// Activity 管理器(用于跟踪所有 Activity)
object ActivityCollector {
    private val activities = mutableListOf<WeakReference<Activity>>()

    fun addActivity(activity: Activity) {
        activities.add(WeakReference(activity))
    }

    fun removeActivity(activity: Activity) {
        activities.removeAll { it.get() == activity }
    }

    fun finishAll() {
        activities.forEach { ref ->
            ref.get()?.finish()
        }
        activities.clear()
    }
}

步骤 2:在 BaseActivity 中集成

kotlin
abstract class BaseActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ActivityCollector.addActivity(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        ActivityCollector.removeActivity(this)
    }
}

使用示例

kotlin
// 退出到登录页
AppExitUtils.exitToActivity(this, LoginActivity::class.java)

// 完全退出应用
AppExitUtils.exitApp(this)

方案 2:强制终止进程(不推荐)

直接杀死应用进程,可能导致资源未正确释放,仅用于极端情况。

kotlin
fun forceExitApp() {
    // 关闭所有 Activity
    ActivityCollector.finishAll()
    // 终止进程
    android.os.Process.killProcess(android.os.Process.myPid())
    System.exit(0)
}

关键细节说明

  1. 任务栈清理

    • Intent.FLAG_ACTIVITY_CLEAR_TASK:清空当前任务栈。
    • Intent.FLAG_ACTIVITY_NEW_TASK:在新任务栈中启动 Activity(避免残留历史记录)。
  2. 进程终止

    • killProcess()System.exit() 会强制终止进程,但可能导致后台服务或通知被意外关闭。
    • 通常只需关闭所有 Activity,系统会在需要时自动回收进程。
  3. 用户体验优化

    • 禁用跳转动画:overridePendingTransition(0, 0)
    • 在退出前保存必要数据(如用户偏好设置)。

完整流程图

text
[用户点击退出按钮]

[关闭所有 Activity(ActivityCollector.finishAll())]

[跳转到登录页/主页(清理任务栈)]

[可选:终止进程(仅限极端需求)]

最佳实践

  • 场景 1:退出到登录页
    使用 exitToActivity(this, LoginActivity::class.java),确保用户无法通过返回键回到之前的界面。

  • 场景 2:完全退出应用
    调用 exitApp(),适合在「设置」页提供「退出应用」按钮。

  • 避免直接杀进程:除非确定需要立即释放内存,否则让系统管理进程生命周期。


通过上述方案,可优雅实现「随时随地退出应用」,同时兼顾系统规范与用户体验。

启动Activity的最佳写法

在 Android 开发中,启动 Activity 的「最佳写法」需兼顾 代码简洁性类型安全可维护性。以下是基于 Kotlin 的现代实践方案:


1. 基础启动(显式 Intent)

标准写法

kotlin
// 启动目标 Activity
val intent = Intent(this, TargetActivity::class.java)
startActivity(intent)

优化:封装扩展函数

kotlin
// 为 Context 添加扩展函数
inline fun <reified T : Activity> Context.navigate(
    block: Intent.() -> Unit = {}
) {
    val intent = Intent(this, T::class.java).apply(block)
    startActivity(intent)
}

// 使用示例(在 Activity/Fragment 中)
navigate<TargetActivity>()

2. 传递参数

安全传参(使用 Bundle 或 Parcelable)

kotlin
// 发送方
navigate<TargetActivity> {
    putExtra("key_string", "Hello")
    putExtra("key_int", 100)
    putExtra("user", User("Alice", 25)) // User 需实现 Parcelable
}

// 接收方(在 TargetActivity 中)
private fun parseIntent() {
    val stringValue = intent.getStringExtra("key_string") ?: ""
    val intValue = intent.getIntExtra("key_int", 0)
    val user = intent.getParcelableExtra<User>("user")
}

推荐:使用 SafeArgsBundle 工具类

kotlin
// 定义参数常量
object Args {
    const val KEY_STRING = "key_string"
    const val KEY_INT = "key_int"
    const val KEY_USER = "key_user"
}

// 发送方
navigate<TargetActivity> {
    putExtra(Args.KEY_STRING, "Hello")
}

// 接收方
val stringValue = intent.getStringExtra(Args.KEY_STRING) ?: ""

3. 处理返回结果

旧方案:startActivityForResult(已弃用)

kotlin
// 启动 Activity 并等待结果
val intent = Intent(this, TargetActivity::class.java)
startActivityForResult(intent, REQUEST_CODE)

// 处理结果
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
        val result = data?.getStringExtra("result_key")
    }
}

新方案:Activity Result API(推荐)

kotlin
// 定义 Activity Result Launcher
private val resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    if (result.resultCode == RESULT_OK) {
        val data = result.data?.getStringExtra("result_key")
    }
}

// 启动 Activity
val intent = Intent(this, TargetActivity::class.java)
resultLauncher.launch(intent)

4. 高级场景

清空任务栈跳转(如退出到登录页)

kotlin
navigate<LoginActivity> {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}

带共享元素动画

kotlin
// 发送方
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
    this,
    imageView, // 共享的 View
    "transition_name" // 与目标 Activity 中 View 的 transitionName 一致
).toBundle()

navigate<DetailActivity>(options = options)

// 接收方(在 DetailActivity 的布局中)
<ImageView
    android:transitionName="transition_name" />

5. 最佳实践总结

场景写法
普通跳转使用 navigate<TargetActivity>() 扩展函数
传参通过 putExtra + 常量 Key,或使用 SafeArgs
接收结果优先使用 Activity Result API
任务栈管理合理使用 Intent Flags(如 FLAG_ACTIVITY_CLEAR_TOP
动画使用 ActivityOptionsCompat 实现平滑过渡

完整工具类封装

kotlin
object NavigationUtils {

    /**
     * 安全跳转到目标 Activity
     * @param context 上下文
     * @param target 目标 Activity 类
     * @param extras 参数构建器(可选)
     * @param flags Intent 标志(可选)
     * @param options 动画选项(可选)
     */
    inline fun <reified T : Activity> navigate(
        context: Context,
        extras: Intent.() -> Unit = {},
        flags: Int = 0,
        options: Bundle? = null
    ) {
        val intent = Intent(context, T::class.java).apply {
            this.flags = flags
            extras()
        }
        if (intent.resolveActivity(context.packageManager) != null) {
            ContextCompat.startActivity(context, intent, options)
        } else {
            Log.e("Navigation", "Target activity not found: ${T::class.java.name}")
        }
    }
}

// 使用示例
NavigationUtils.navigate<DetailActivity>(
    context = this,
    extras = { putExtra("key_data", "Hello") },
    flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
)

注意事项

  1. 避免内存泄漏:在 Fragment 或 View 中启动 Activity 时,确保使用 Activity 作为 Context。
  2. 数据大小限制:传递的 Bundle 数据不宜超过 1MB。
  3. 类型安全:使用 Parcelable 替代 Serializable 提升性能。
  4. 兼容性:检查隐式 Intent 的目标是否存在(resolveActivity)。

通过以上写法,可显著提升代码的可读性和健壮性,同时适配现代 Android 开发规范。