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 的代码。

相关推荐
雨白8 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹9 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空11 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭11 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日12 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安12 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑12 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟17 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡18 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0018 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体