Activity的三个实用技巧

快速定位当前Activity

在一个庞大且复杂的已有项目中,面对某个界面,你很难找到这个界面所对应的 Activity。而这个技巧,可以帮你解决这个问题。

假设当前项目有三个 Activity,分别是:FirstActivitySecondActivityThirdActivity。前两个 Activity 的布局中都有一个按钮,分别可用于启动 SecondActivityThirdActivity

首先创建一个 BaseActivity 类,然后继承自 AppCompatActivity。并重写 onCreate() 方法,在方法内部打印当前实例的类名:

注意:这里的 BaseActivity 类只是一个普通 Kotlin Class,不要创建 Activity。因为我们不需要它在 AndroidManifest.xml 清单文件中注册。

kotlin 复制代码
open class BaseActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("BaseActivity", "Current Activity: ${javaClass.simpleName}")
    }
}

Kotlin 中的 javaClass 用于获取当前实例的Class对象,相当于在 Java 中调用 this.getClass() 方法,simpleName 表示获取不带包名的类名。而 Kotlin 中的 BaseActivity::class.java 表示获取 BaseActivity 类本身的 Class 对象,相当于在 Java 中调用 BaseActivity.class

接下来让应用中所有的 Activity 类都继承自 BaseActivity。(BaseActivity 类的声明前已加上 open 关键字,表示这个类可被继承),当前应用中有三个Activity:FirstActivity, SecondActivity, ThirdActivity

kotlin 复制代码
class FirstActivity : BaseActivity() {
    ...
}

class SecondActivity : BaseActivity() {
    ...
}

class ThirdActivity : BaseActivity() {
    ...
}

现在,每当一个新的 Activity 被启动(onCreate() 方法被执行)时,它的类名就会被打印出来。

重新运行程序,在 FirstActivity 界面中点击按钮进入 SecondActivity,然后在 SecondActivity 界面中点击按钮进入 ThirdActivity,Logcat 日志打印信息如下:

ini 复制代码
D/BaseActivity: Current Activity: FirstActivity
D/BaseActivity: Current Activity: SecondActivity
D/BaseActivity: Current Activity: ThirdActivity

随时随地退出程序

正常来说我们退出程序,应用中有多少个 Activity 实例,就需要按下多少次返回键。(Home键只是挂起程序,并没有退出)

假如现在有一个需求:添加一个"退出应用"的功能,该怎么实现?

很简单,我们可以创建一个集合把所有的 Activity 实例统一管理起来。创建一个单例类 ActivityCollector

kotlin 复制代码
object ActivityCollector {
    private val activities = ArrayList<Activity>()

    // 新增 Activity 实例
    fun addActivity(activity: Activity) {
        activities.add(activity)
    }
    
    // 移除某个 Activity 实例
    fun removeActivity(activity: Activity) {
        activities.remove(activity)
    }
    
    // 一键销毁所有 Activity 实例
    fun finishAll() {
        for (activity in activities) {
            if (!activity.isFinishing) {
                activity.finish()
            }
        }
        activities.clear()
        Log.d("ActivityCollector", "All activities finished and cleared.")
    }
}

因为这个 Activity 集合需要全局唯一,所以在单例类中进行创建。

其中 finishAll() 方法,会将集合中所有的 Activity 销毁。注意:在销毁之前,需要通过 activity.isFinishing 判断 Activity 是否正在被销毁,因为 Activity 还可能通过按下返回键键等方式被销毁,正在销毁的话,就不通过它的 finish() 方法来销毁它。

有了这个集合,还需要进行管理:应用中,有新的 Activity 实例被创建时,需要将它添加到集合中;有 Activity 实例将要被销毁时,要从集合中移除。

为了自动完成这个操作,我们可以在所有 Activity 的共同父类,也就是前面说的 BaseActivityonCreate()onDestroy() 方法中,分别将当前正在创建的 Activity 添加到集合,从集合中移除将要被销毁的 Activity。

修改 BaseActivity 中的代码:

kotlin 复制代码
open class BaseActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("BaseActivity", javaClass.simpleName)
        ActivityCollector.addActivity(this)
    }

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

然后,当你需要退出整个程序时,只需调用 ActivityCollector.finishAll() 方法就可以了。

比如我在 ThirdActivity 的界面中点击按钮,需要退出程序,我可以这样做:

kotlin 复制代码
binding.button3.setOnClickListener {
    // 销毁所有 Activity
    ActivityCollector.finishAll()
}

应用的进程会由 Android 系统自动回收。

启动Activity的最佳实践

我相信你已经知道如何启动 Activity 了,只需通过 Intent 构建出"意图",然后通过 startActivity()ActivityResultLauncher.launch() 方法启动 Activity 即可。但如何让这个过程更规范、更不容易出错呢?

比如一个 Activity 启动时需要特定参数时,调用方如果直接构造 Intent 对象,并通过 putExtra() 方法传递数据,很容易出现参数遗漏、类型错误、键名拼写错误等问题。

这时,只需在目标 Activity 中提供一个静态方法,封装Intent的创建和参数传递逻辑即可。像这样:

kotlin 复制代码
class SecondActivity : BaseActivity() {

    private lateinit var binding: SecondLayoutBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 使用视图绑定
        binding = SecondLayoutBinding.inflate(layoutInflater)
        val linearLayout = binding.root
        setContentView(linearLayout)

        // 获取传递过来的数据
        val param1 = intent.getStringExtra(EXTRA_PARAM1)
        val param2 = intent.getStringExtra(EXTRA_PARAM2)
        Log.d("SecondActivity", "Received: param1=$param1, param2=$param2")
    }
    
    
    companion object {
        // 定义键常量,使用包名作为前缀避免冲突
        private const val EXTRA_PARAM1 = "com.example.PARAM1"
        private const val EXTRA_PARAM2 = "com.example.PARAM2"

        /**
         * 创建启动 SecondActivity 的 Intent 对象
         * 这种方式更灵活,调用者可以决定如何使用这个Intent(因为有多种启动 Intent 对象的方式)
         */
        fun newIntent(context: Context, data1: String, data2: String): Intent {
            return Intent(context, SecondActivity::class.java).apply {
                putExtra(EXTRA_PARAM1, data1)
                putExtra(EXTRA_PARAM2, data2)
            }
        }

        /**
         * 直接启动 SecondActivity 的方法
         */
        fun actionStart(context: Context, data1: String, data2: String) {
            val intent = newIntent(context, data1, data2)
            context.startActivity(intent)
        }
    }
}

companion object 是一个语法结构,在其中定义的方法和属性类似 Java 中的静态成员。

其中 newIntent() 方法会构建一个携带启动当前 Activity 所需参数的 Intent 对象并返回。在 actionStart() 方法中,我们调用了 newIntent() 方法来创建 Intent 对象,然后通过 startActivity() 方法启动了当前 Activity,也就是 SecondActivity

从其他 Activity 中启动 SecondActivity

kotlin 复制代码
// 方式一
SecondActivity.actionStart(this, "Hello", "World")

// 方式二
val intent: Intent = SecondActivity.newIntent(
    context = this,
    data1 = "This is ",
    data2 = "FirstActivity"
)
activityResultLauncher.launch(intent)

这样写,你可以通过方法签名很清楚地告知调用者启动 SecondActivity,需要传递哪些数据,以及分别是什么类型。另外,简化了启动 Activity 的代码。

相关推荐
每次的天空1 小时前
Android第十一次面试补充篇
android·面试·职场和发展
FindYou.6 小时前
Android之ListView
android
CYRUS_STUDIO10 小时前
攻防 FART 脱壳:特征检测识别 + 对抗绕过全解析
android·安全·逆向
aningxiaoxixi10 小时前
android 媒体框架之MediaCodec
android·网络·媒体
二流小码农11 小时前
鸿蒙开发:应用内如何做更新
android·ios·harmonyos
兰琛12 小时前
Compose仿微信底部导航栏NavigationBar :底部导航控制滑动并移动
android·android jetpack
wzj_what_why_how12 小时前
Kotlin JVM 注解详解
android·kotlin
雨白12 小时前
Android UI入门:XML与常用控件的使用
android
试行13 小时前
Android获取设备信息
android
monkey_slh13 小时前
JS逆向案例—喜马拉雅xm-sign详情页爬取
android·开发语言·javascript