Activity的相关实践
1 当前是哪一个Activity
首先需要新建一个BaseActivity 类。New —> Kotlin File/Class ,在弹出的窗口中输入BaseActivity ,创建类型选择Class 。注意,这里的BaseActivity 和普通Activity 的创建方式并不一样,因为不需要让BaseActivity 在AndroidManifest.xml 中注册,所以选择创建一个普通的Kotlin 类就可以 了。然后让BaseActivity 继承自AppCompatActivity ,并重写onCreate() 方法,如下所示:
open class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.e("CAH", javaClass.simpleName)
}
}
在onCreate() 方法中加了一行日志,用于打印当前实例的类名。**Kotlin 中的javaClass 表示获取当前实例的Class 对象,相当于在Java 中调用getClass() 方法;而Kotlin 中的BaseActivity::class.java 表示获取BaseActivity 类的Class 对象,相当于在Java 中调用BaseActivity.class 。**在上述代码中,先是获取了当前实例的Class 对象,然后再调用simpleName 获取当前实例的类名。
接下来需要让BaseActivity 成为项目中所有Activity 的父类,为了使BaseActivity 可以被继承,已经提前在类名的前面加上了open 关键字。 然后修改FirstActivity 、SecondActivity 和ThirdActivity 的继承结构,让它们不再继承自AppCompatActivity ,而是继承自BaseActivity 。而由于BaseActivity 又是继承自AppCompatActivity 的,所以项目中所有Activity 的现有功能并不受影响,它们仍然继承了Activity 中的所有特性。
现在重新运行程序,然后通过点击按钮分别进入FirstActivity 、SecondActivity 和ThirdActivity 的界面,这时观察Logcat 中的打印信息,如图所示:
现在每当进入一个Activity 的界面,该Activity 的类名就会被打印出来,这样就可以时刻知晓当前界面对应的是哪一个Activity 了。
2 随时退出程序
如果目前界面还停留在ThirdActivity ,会发现当前想退出程序是非常不方便的,需要连按3 次Back 键才行。按Home 键只是把程序挂起,并没有退出程序。如果程序需要注销或者退出的功能该怎么办呢?
这时需要用一个专门的集合对所有的Activity 进行管理就可以了。新建一个单例类ActivityCollector 作为Activity 的集合,代码如下所示:
object ActivityController {
private val activities = ArrayList<Activity>()
fun addActivity(activity: Activity) {
activities.add(activity)
}
fun removeActivity(activity: Activity) {
activities.remove(activity)
}
fun finishAll() {
for (activity in activities) {
if (!activity.isFinishing) {
activity.finish()
}
}
activities.clear()
}
}
这里使用了单例类,是因为全局只需要一个Activity 集合。在集合中,通过一个ArrayList 来暂存Activity ,然后提供了一个addActivity() 方法,用于向ArrayList 中添加Activity ;提供了一个removeActivity() 方法,用于从ArrayList 中移除Activity ;最后提供了一个finishAll() 方法,用于将ArrayList 中存储的Activity 全部销毁。注意在销毁Activity 之前,需要先调用activity.isFinishing 来判断Activity 是否正在销毁中,因为Activity 还可能通过按下Back 键等方式被销毁,如果该Activity 没有正在销毁中,再去调用它的finish() 方法来销毁它。
接下来修改BaseActivity 中的代码,如下所示:
open class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.e("CAH", "BaseActivity: ${javaClass.simpleName}")
ActivityController.addActivity(this)
}
override fun onDestroy() {
super.onDestroy()
ActivityController.removeActivity(this)
}
}
在BaseActivity.onCreate() 方法中调用了ActivityCollector.addActivity() 方 法,表明将当前正在创建的Activity 添加到集合里。然后在BaseActivity 中重写onDestroy() 方法,并调用了ActivityCollector.removeActivity() 方法,表明从集合里移除一个马上要销毁的Activity 。
从此以后,不管你想在什么地方退出程序,只需要调用ActivityCollector.finishAll() 方法就可以了。例如在ThirdActivity 界面想通过点击按钮直接退出程序,只需将代码改成如下形式:
class ThirdActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_third)
button.setOnClickListener {
ActivityController.finishAll()
}
}
}
当然还可以在销毁所有Activity 的代码后面再加上杀掉当前进程的代码,以保证程序完全退出,杀掉进程的代码如下所示:
android.os.Process.killProcess(android.os.Process.myPid())
killProcess() 方法用于杀掉一个进程,它接收一个进程id 参数,可以通过myPid() 方法来获得当前程序的进程id 。需要注意的是,killProcess() 方法只能用于杀掉当前程序的进程,不能用于杀掉其他程序。
3 启动Activity 的最佳写法
启动Activity 的方法是首先通过Intent 构建出当前的“意图”,然后调用startActivity() 或startActivityForResult() 方法将Activity 启动起来,如果有数据需要在Activity 之间传递,也可以借助Intent 来完成。
假设SecondActivity 中需要用到两个非常重要的字符串参数,在启动SecondActivity 的时候必须传递过来,那么很容易会写出如下代码:
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("param1", "data1")
intent.putExtra("param2", "data2")
startActivity(intent)
虽然这样写是完全正确的,但是在真正的项目开发中经常会出现对接的问题。比如SecondActivity 并不是由你开发的,但现在你负责开发的部分需要启动SecondActivity ,而你却不清楚启动SecondActivity 需要传递哪些数据。这时无非就有两个办法:一个是你自己去阅读SecondActivity 中的代码,另一个是询问负责编写SecondActivity 的同事。这样会比较麻烦,其实只需要换一种写法,就可以轻松解决上面的窘境。
修改SecondActivity 中的代码,如下所示:
class SecondActivity : BaseActivity() {
companion object {
fun actionStart(context: Context, data1: String, data2: String) {
val intent = Intent(context, NormalActivity::class.java)
intent.putExtra("param1", data1)
intent.putExtra("param2", data2)
context.startActivity(intent)
}
}
....
}
在这里使用了一个新的语法结构companion object ,并在companion object 中定义 了一个actionStart() 方法。之所以要这样写,是因为Kotlin 规定,所有定义在companion object 中的方法都可以使用类似于Java 静态方法的形式调用。
在actionStart() 方法,在这个方法中完成了Intent 的构建,另外所有SecondActivity 中需要的数据都是通过actionStart() 方法的参数传递过来的,然后把它们存储到Intent 中,最后调用startActivity() 方法启动SecondActivity 。
这样写的好处是SecondActivity 所需要的数据在方法参数中全部体现出来了,这样即使不用阅读SecondActivity 中的代码,不去询问负责编写SecondActivity 的同事,也可以非常清晰地知道启动SecondActivity 需要传递哪些数据。另外,这样写还简化了启动Activity 的代码,现在只需要一行代码就可以启动SecondActivity , 如下所示:
button.setOnClickListener {
NormalActivity.actionStart(this, "data1", "data2")
}
|