3. 探究Activity
3.1 Activity加载一个布局
setContentView()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.first_layout)
}
3.2 主Activity
<activity
android:name=".FirstActivity"
android:exported="true"
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
3.3 视图绑定
视图绑定功能可按模块启用。要在某个模块中启用视图绑定,请将 viewBinding 元素添加到其 build.gradle 文件中,如下例所示:
android {
...
viewBinding {
enabled = true
}
}
如果您希望在生成绑定类时忽略某个布局文件,请将 tools:viewBindingIgnore="true" 属性添加到相应布局文件的根视图中:
<LinearLayout
...
tools:viewBindingIgnore="true" >
...
</LinearLayout>
为某个模块启用视图绑定功能后,系统会为该模块中包含的每个 XML 布局文件生成一个绑定类。每个绑定类均包含对根视图以及具有 ID 的所有视图的引用。系统会通过以下方式生成绑定类的名称:将 XML 文件的名称转换为驼峰式大小写,并在末尾添加Binding一词。
例如,假设某个布局文件的名称为 result_profile.xml:
<LinearLayout ... >
<TextView android:id="@+id/name" />
<ImageView android:cropToPadding="true" />
<Button android:id="@+id/button"
android:background="@drawable/rounded_button" />
</LinearLayout>
所生成的绑定类的名称就为 ResultProfileBinding。此类具有两个字段:一个是名为 name 的 TextView,另一个是名为 button 的 Button。该布局中的 ImageView 没有 ID,因此绑定类中不存在对它的引用。
每个绑定类还包含一个 getRoot() 方法,用于为相应布局文件的根视图提供直接引用。在此示例中,ResultProfileBinding 类中的 getRoot() 方法会返回 LinearLayout 根视图。
3.4 在 Activity 中使用视图绑定
如需设置绑定类的实例以供 Activity 使用,请在 Activity 的 onCreate() 方法中执行以下步骤:
- 调用生成的绑定类中包含的静态
inflate()方法。此操作会创建该绑定类的实例以供 Activity 使用。 - 通过调用
getRoot()方法或使用 Kotlin 属性语法获取对根视图的引用。 - 将根视图传递到
setContentView(),使其成为屏幕上的活动视图。
private lateinit var binding: ResultProfileBinding
override fun onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
binding = ResultProfileBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
您现在即可使用该绑定类的实例来引用任何视图:
binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }
3.5 在 Fragment 中使用视图绑定
如需设置绑定类的实例以供 Fragment 使用,请在 Fragment 的 onCreateView() 方法中执行以下步骤:
- 调用生成的绑定类中包含的静态
inflate()方法。此操作会创建该绑定类的实例以供 Fragment 使用。 - 通过调用
getRoot()方法或使用 Kotlin 属性语法获取对根视图的引用。 - 从
onCreateView()方法返回根视图,使其成为屏幕上的活动视图。
private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = ResultProfileBinding.inflate(inflater, container, false)
val view = binding.root
return view
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
您现在即可使用该绑定类的实例来引用任何视图:
binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }
3.6 在Activity中使用Menu
在res目录下新建一个 menu 文件夹,在 menu 文件夹下创建一个 main 的菜单文件(Menu resource file)。
在main.xml中添加如下代码:
<?xml version="1.0" encoding="utf-8"?>
<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>
创建了2个菜单。
到FirstActivity中重写onCreateOptionsMenu()方法,重写方法可以使用Control + O快捷键。
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.main, menu)
return true
}
重写点击响应方法
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
}
3.7 销毁一个Activity
finish()
3.8 使用Intent在Activity之间跳转
显示Intent
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
隐式Intent
AndroidMainfest.xml中
<activity
android:name=".SecondActivity"
android:exported="false" >
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.activitytest.MY_CATEGORY" />
</intent-filter>
</activity>
kt中
val intent = Intent("com.example.activitytest.ACTION_START")
intent.addCategory("com.example.activitytest.MY_CATEGORY")
startActivity(intent)
打开其他程序的Activity
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://www.baidu.com")
startActivity(intent)
3.9 Activity传递数据
传递数据
val data = "Hello Second"
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("extra_data", data)
startActivity(intent)
获取数据
val extraData = intent.getStringExtra("extra_data")
println(extraData)
3.10 返回数据给上一个Activity
FirstActivity中
// 跳转的时候
val data = "Hello Second"
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("extra_data", data)
startActivityForResult(intent, 1)
重写onActivityResult方法
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
1 -> {
if (resultCode == RESULT_OK) {
val returnData = data?.getStringExtra("data_return")
println("FirstActivity return data: $returnData")
}
}
}
}
SecondActivity中
binding.button2.setOnClickListener {
val intent = Intent()
intent.putExtra("data_return", "Hello FirstActivity")
setResult(RESULT_OK, intent)
finish()
}
目前onActivityResult已经废弃了,现在使用Activity Result API来监听回传数据
private val resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
val returnData = it.data?.getStringExtra("data_return")
println("FirstActivity launch return data: $returnData")
}
}
val data = "Hello Second"
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("extra_data", data)
resultLauncher.launch(intent)
3.11 Activity的生命周期
Activity的四种状态:
- 运行状态:处于栈顶时,
Activity处于栈顶状态。 - 暂停状态:不再处于栈顶,但仍然可见,
Activity就处于暂停状态。 - 停止状态:不再处于栈顶,并且完全不可见。
- 销毁状态:从返回栈中移除后就成了销毁状态。
Activity生存期:
onCreate():这个方法你已经看到过很多次了,我们在每个Activity中都重写了这个方法,它会在Activity第一次被创建的时候调用。你应该在这个方法中完成Activity的初始化操作,比如加载布局、绑定事件等。onStart():这个方法在Activity由不可见变为可见的时候调用。onResume():这个方法在Activity准备好和用户进行交互的时候调用。此时的Activity一定位于返回栈的栈顶,并且处于运行状态。onPause():这个方法在系统准备去启动或者恢复另一个Activity的时候调用。我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶Activity的使用。onStop():这个方法在Activity完全不可见的时候调用。它和onPause()方法的主要区别在于,如果启动的新Activity是一个对话框式的Activity,那么onPause()方法会得到执行,而onStop()方法并不会执行。onDestroy():这个方法在Activity被销毁之前调用,之后Activity的状态将变为销毁状态。onRestart():这个方法在Activity由停止状态变为运行状态之前调用,也就是Activity被重新启动了
3.12 Activvity的启动模式
有四种启动模式。standard、singleTop、singleTask、singleInstance,可以再AndroidManifest.xml中通过<activity>标签指定android:launchMode属性来选择启动模式。
- standard
默认启动模式,standard模式下,每当启动一个新的Activity,它就会在栈顶入栈,并处于栈顶位置。
- singleTop
启动Activity时,如果发现返回栈的栈顶已经是该Activity,则认为可以直接使用它,不会创建新的Activity实例。如果不在栈顶,则会创建新的Activity。
- singleTask
启动Activity时,系统首先会在返回栈中检查是否存在该Activity的实例,如果存在则直接使用,并把这个Activity之上的所有其他Activity统统出栈,如果没有,则会创建新的Activity。
- singleInstance
启动一个新的返回栈来管理这个Activity。
3.13. 杀掉应用程序
javaClass 获取当前实例的Class对象,相当于java的getClass()方法
BaseActivity::class.java 表示BaseActivity类的Class对象,相当于java中的BaseActivity.class
直接退出APP-杀掉进程
android.os.Process.killProcess(android.os.Process.myPid())
3.14 Activity中使用companion object
所有定义在companion object中的方法,都可以使用静态方式调用
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)
}
}
}
调用
SecondActivity.actionStart(this, "Value1", "Value2")
使用companion object方式,在子页面提前定义好需要的参数,让前置页面方便调用。