一:Activity的定义
Activity是一个应用组件,它提供了一个用户界面,允许用户执行一个单一的、明确的操作,用户看的见的操作都是在activity中执行的。Activity的实现需要在manifest中进行定义,不让会造成程序报错。
1.1 Toast
Toast是Android系统提供的一种非常好的提醒方式,在程序中可以使用它将一些短小的信息通知给用户,这些信息会在一段时间后自动消失,并且不会占用任何屏幕空间。
Toast只能在UI线程
中进行定义并使用。
Toast.makeText(this, "You have used Toast", Toast.LENGTH_SHORT).show()
第一个参数是Context,也就是Toast要求的上下文
第二个参数是Toast显示的文本内容
第三个参数是Toast显示的时长,有两个内置常量可以选择:Toast.LENGTH_SHORT和Toast.LENGTH_LONG。
1.2 Menu菜单
在res -> menu文件夹下创建文件
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_item"
android:title="Add"/>
<item
android:id="@+id/remove_item"
android:title="Remove"/>
</menu>
创建了两个菜单项,其中标签用来创建具体的某一个菜单项,id为唯一的标识符,title为菜单项目的名称。
1.2.1 初始化menu
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.main, menu)
return true
}
1.2.2 menu的执行
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.add_item -> Toast.makeText(this, "You clicked Add",
Toast.LENGTH_SHORT).show()
R.id.remove_item -> Toast.makeText(this, "You clicked Remove",
Toast.LENGTH_SHORT).show()
}
return true
}
二、Intent的使用
2.1 显式Intent
指定具体的,需要跳转的Activity
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
Kotlin中SecondActivity::class.java的写法就相当于Java中SecondActivity.class的写法
2.2 隐式Intent
需要指定和,且与在manifest中定义的匹配才可进行跳转
不指定具体的activity,而是声明其action、category等属性
每个Intent中只能指定一个action,但能指定多个category。
button1.setOnClickListener {
val intent = Intent("com.example.activitytest.ACTION_START")
startActivity(intent)
}
android.intent.category.DEFAULT为默认的,可不用设置,如果设置未声明的category,会操作软件崩溃。
2.2.1 打开浏览器
button1.setOnClickListener {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://www.baidu.com")
startActivity(intent)
}
标签的设置和设置action标签层级一致,都在manifest中的activity进行设置。
标签中主要可以配置以下内容。
● android:scheme。用于指定数据的协议部分,如上例中的https部分。
● android:host。用于指定数据的主机名部分,如上例中的www.baidu.com部分。
● android:port。用于指定数据的端口部分,一般紧随在主机名之后。
● android:path。用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容。
● android:mimeType。用于指定可以处理的数据类型,允许使用通配符的方式进行指定。
只有当标签中指定的内容和Intent中携带的Data完全一致
时,当前Activity才能够响应该Intent。
在manifest中设置data标签,在标签中,我们通过android:scheme指定了数据的协议必须是https协议,才可以实现浏览器的效果。
2.2.2 拨打电话
除了https协议外,我们还可以指定很多其他协议,比如geo表示显示地理位置、tel表示拨打电话。
button1.setOnClickListener {
val intent = Intent(Intent.ACTION_DIAL)
intent.data = Uri.parse("tel:10086")
startActivity(intent)
}
2.3 携带数据
Intent从Activity_A携带数据给Activity_B,并返回数据给Activity_A
2.3.1 数据发送
button1.setOnClickListener {
val data = "Hello SecondActivity"
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("extra_data", data)
startActivity(intent)
}
putExtra()
方法接收两个参数,第一个参数是键,用于之后从Intent中取值,第二个参数才是真正要传递的数据。
数据接收
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.second_layout)
val extraData = intent.getStringExtra("extra_data")
Log.d("SecondActivity", "extra data is $extraData")
}
}
由于传递的是字符串,所以使用getStringExtra()方法来获取传递的数据;
如果传递的是整型数据,则使用getIntExtra()方法;
如果传递的是布尔型数据,则使用getBooleanExtra()方法,以此类推。
2.4 返回数据
Activity类中还有一个用于启动Activity的startActivityForResult()
方法,但它期望在Activity销毁的时候能够返回一个结果给上一个Activity。
在Activity_A中,启动:
button1.setOnClickListener {
val intent = Intent(this, SecondActivity::class.java)
startActivityForResult(intent, 1)
}
在Activity_B中定义个按钮进行数据传回:
button2.setOnClickListener {
val intent = Intent()
intent.putExtra("data_return", "Hello FirstActivity")
setResult(RESULT_OK, intent)
finish()
}
setResult()
方法接收两个参数:第一个参数用于向上一个Activity返回处理结果,一般只使用RESULT_OK或RESULT_CANCELED这两个值;第二个参数则把带有数据的Intent传递回去。
在activity_A中复写方法onActivityResult
,在方法中接收数据:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
1 -> if (resultCode == RESULT_OK) {
val returnedData = data?.getStringExtra("data_return")
Log.d("FirstActivity", "returned data is $returnedData")
}
}
}
Activity可以跳转至多个数据并返回数据,requestCode为防止混淆。
onActivityResult()
方法带有3个参数:第一个参数requestCode,即我们在启动Activity时传入的请求码;第二个参数resultCode,即我们在返回数据时传入的处理结果;第三个参数data,即携带着返回数据的Intent。
如果用户在SecondActivity中并不是通过点击按钮,而是通过按下Back键回到FirstActivity,需要重写一下onBackPressed方法,在方法中对返回的数据进行处理。
三、Activity的生命周期
- onCreate()
在Activity第一次被创建的时候调用 - onStart()
这个方法在Activity由不可见变为可见的时候调用 - onResume()
这个方法在Activity准备好和用户进行交互的时候调用。此时的Activity一定位于返回栈的栈顶,并且处于运行状态。 - onPause()
这个方法在系统准备去启动或者恢复另一个Activity的时候调用。我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶Activity的使 - onStop()
这个方法在Activity完全不可见的时候调用。它和onPause()方法的主要区别在于,如果启动的新Activity是一个对话框式的Activity,那么onPause()方法会得到执行,而onStop()方法并不会执行。 - onDestroy()
这个方法在Activity被销毁之前调用,之后Activity的状态将变为销毁状态。 - onRestart()
这个方法在Activity由停止状态变为运行状态之前调用,也就是Activity被重新启动了。
从onCreate到onDestroy表示Activity的一整个周期,从创建到销毁
onSaveInstanceState()方法,保存临时数据
如果在内存不足的情况,处于onStop状态的Activity会被回收,需要保存临时数据
Activity中提供了一个onSaveInstanceState()回调方法,这个方法可以保证在Activity被回收之前一定会被调用。
nSaveInstanceState()方法会携带一个Bundle类型的参数,Bundle提供了一系列的方法用于保存数据,比如可以使用putString()方法保存字符串,使用putInt()方法保存整型数据,以此类推。每个保存方法需要传入两个参数,第一个参数是键,用于后面从Bundle中取值,第二个参数是真正要保存的内容。
恢复:
在onCreate中进行恢复,利用onCreate中的Bundle参数
四、Activity的启动方式
4.1 standard
standard是Activity默认的启动模式,在不进行显式指定的情况下,所有Activity都会自动使用这种启动模式,这种启动模式,启动Activity就创建一个新的Actiivty,不考虑其之前是否存在。
4.2 singleTop
当Activity的启动模式指定为singleTop,在启动Activity时如果发现返回栈的栈顶已经是该Activity,则认为可以直接使用它,不会再创建新的Activity实例即在栈顶调用,否则创建。
4.3 singleTask
当Activity的启动模式指定为singleTask,每次启动该Activity时,系统首先会在返回栈中检查是否存在该Activity的实例,如果发现已经存在则直接使用该实例,并把在这个Activity之上的所有其他Activity统统出栈,如果没有发现就会创建一个新的Activity实例。检查任务栈中是否存在,不存在创建。
4.4 singleInstance
指定为singleInstance模式的Activity会启用一个新的返回栈来管理这个Activity(其实如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈)
Activity位于独立的任务栈中。
五、 Activity的便利使用
5.1 单例类管理Activity
创建单例类对Activity进行管理
object ActivityCollector {
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()
}
}
5.2 BaseActivity中实现
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)
}
}
杀掉进程的代码
android.os.Process.killProcess(android.os.Process.myPid())
killProcess()
方法用于杀掉一个进程,它接收一个进程id参数,我们可以通过myPid()方法来获得当前程序的进程id。需要注意的是,killProcess()方法只能用于杀掉当前程序的进程,不能用于杀掉其他程序。
5.3 启动Activity的最佳方法:
class SecondActivity : BaseActivity() {
...
companion object {
fun actionStart(context: Context, data1: String, data2: String) {
val intent = Intent(context, SecondActivity::class.java)
intent.putExtra("param1", data1)
intent.putExtra("param2", data2)
context.startActivity(intent)
}
}
}
在这里我们使用了一个新的语法结构companion object
,并在companion object中定义了一个actionStart()方法。
启动代码
button1.setOnClickListener {
SecondActivity.actionStart(this, "data1", "data2")
}