三、Android-探究Activity

140 阅读6分钟

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。此类具有两个字段:一个是名为 nameTextView,另一个是名为 buttonButton。该布局中的 ImageView 没有 ID,因此绑定类中不存在对它的引用。

每个绑定类还包含一个 getRoot() 方法,用于为相应布局文件的根视图提供直接引用。在此示例中,ResultProfileBinding 类中的 getRoot() 方法会返回 LinearLayout 根视图。

3.4 在 Activity 中使用视图绑定

如需设置绑定类的实例以供 Activity 使用,请在 ActivityonCreate() 方法中执行以下步骤:

  1. 调用生成的绑定类中包含的静态 inflate() 方法。此操作会创建该绑定类的实例以供 Activity 使用。
  2. 通过调用 getRoot() 方法或使用 Kotlin 属性语法获取对根视图的引用。
  3. 将根视图传递到 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 使用,请在 FragmentonCreateView() 方法中执行以下步骤:

  1. 调用生成的绑定类中包含的静态 inflate() 方法。此操作会创建该绑定类的实例以供 Fragment 使用。
  2. 通过调用 getRoot() 方法或使用 Kotlin 属性语法获取对根视图的引用。
  3. 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的四种状态

  1. 运行状态:处于栈顶时,Activity处于栈顶状态。
  2. 暂停状态:不再处于栈顶,但仍然可见,Activity就处于暂停状态。
  3. 停止状态:不再处于栈顶,并且完全不可见。
  4. 销毁状态:从返回栈中移除后就成了销毁状态。

Activity生存期:

  1. onCreate():这个方法你已经看到过很多次了,我们在每个Activity中都重写了这个方法,它会在Activity第一次被创建的时候调用。你应该在这个方法中完成Activity的初始化操作,比如加载布局、绑定事件等。
  2. onStart():这个方法在Activity由不可见变为可见的时候调用。
  3. onResume():这个方法在Activity准备好和用户进行交互的时候调用。此时的Activity一定位于返回栈的栈顶,并且处于运行状态。
  4. onPause():这个方法在系统准备去启动或者恢复另一个Activity的时候调用。我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶Activity的使用。
  5. onStop():这个方法在Activity完全不可见的时候调用。它和onPause()方法的主要区别在于,如果启动的新Activity是一个对话框式的Activity,那么onPause()方法会得到执行,而onStop()方法并不会执行。
  6. onDestroy():这个方法在Activity被销毁之前调用,之后Activity的状态将变为销毁状态。
  7. onRestart():这个方法在Activity由停止状态变为运行状态之前调用,也就是Activity被重新启动了

3.12 Activvity的启动模式

有四种启动模式。standardsingleTopsingleTasksingleInstance,可以再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对象,相当于javagetClass()方法

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方式,在子页面提前定义好需要的参数,让前置页面方便调用。