快速定位当前Activity
在一个庞大且复杂的已有项目中,面对某个界面,你很难找到这个界面所对应的 Activity。而这个技巧,可以帮你解决这个问题。
假设当前项目有三个 Activity,分别是:FirstActivity
、SecondActivity
和 ThirdActivity
。前两个 Activity 的布局中都有一个按钮,分别可用于启动 SecondActivity
和 ThirdActivity
。
首先创建一个 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 的共同父类,也就是前面说的 BaseActivity
的 onCreate()
和 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 的代码。