Activity 是与用户交互的接口
Android 系统通过 Activity 栈的形式管理 Activity
Activity 4 种形态
- Active 运行状态:Activity 处于栈顶,可见,可以和用户进行交互
- Paused 暂停状态:不处于栈顶,可见但不可交互,失去焦点被非全屏 Acitivty 挡住
- Stopped 停止状态:不处于栈顶并且完全不可见,被另一个 Activity 完全覆盖
- Killed 销毁状态:从返回栈中移除,系统回收掉
Activity 生命周期
以下是 Activity A 启动 Activity B 时的操作发生顺序:
- Activity A 的
onPause() 方法执行。
- Activity B 的
onCreate()、onStart() 和 onResume() 方法依次执行(Activity B 现在具有用户焦点)。
- 然后
- 如果 Activity A 在屏幕上不再显示,其
onStop() 方法执行。
- 如果 Activity B 为对话框或者透明窗口,并且局部覆盖了 Activity A,其
onStop() 方法不会执行
当 Activity 开始停止时,系统会调用 onSaveInstanceState() 方法,将状态信息保存到实例状态 Bundle 中。
当用户显式关闭 Activity 时,或者在其他情况下调用 finish() 时,系统不会调用 onSaveInstanceState()。
异常状态下的状态更改
如果系统因系统限制(例如配置变更或内存压力)而销毁 Activity,系统会记住它曾经存在过。如果用户尝试回退到该 Activity,系统将使用一组描述 Activity 销毁时状态的已保存数据新建该 Activity 的实例。
配置发生更改:最显著的例子或许是横屏和竖屏之间的屏幕方向变化。其他情况,如语言或输入设备的改变等,也可能导致配置更改。
重建先前被销毁的 Activity 后,可以从系统传递给 Activity 的 Bundle 中恢复保存的实例状态。onCreate() 和 onRestoreInstanceState() 回调方法均会收到包含实例状态信息的相同 Bundle。
onRestoreInstanceState() 方法会在 onStart() 之后调用,onCreate() 中的 Bundle 可能为 null,onRestoreInstanceState() 方法中的 Bundle 不为 null。
Activity 之间通信
ActivityResult
FirstActivity.ktclass FirstActivity : AppCompatActivity() {
private val requestDataLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { val data = result.data?.getStringExtra("data") } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_first) val firstButton = findViewById<Button>(R.id.first_button) firstButton.setOnClickListener { val intent = Intent(this, SecondActivity::class.java) requestDataLauncher.launch(intent) } }
}
|
SecondActivity.ktclass SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_second) val secondButton = findViewById<Button>(R.id.second_button) secondButton.setOnClickListener { val intent = Intent() intent.putExtra("data", "data from SecondActivity") setResult(RESULT_OK, intent) finish() } }
}
|
- Intent/Bundle
- 类静态变量
- 全局变量
- EventBus
- 广播
Activity 与 Fragment 通信
Activity 将数据传递给 Fragment
Bundle
FragmentActivity.ktclass FragmentActivity : AppCompatActivity() {
val productId = ""
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val bundle = Bundle() bundle.putString("params", productId) val fragment1 = Fragment() fragment1.arguments = bundle } }
|
Fragment1.ktclass Fragment1 : Fragment() { var productId = ""
override fun onStart() { super.onStart() if (isAdded) { productId = arguments?.getString("params", "") ?: "" } } }
|
在 Activity 中定义方法
FragmentActivity2.ktclass FragmentActivity2 : AppCompatActivity() {
val productId = ""
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) }
fun getTitles() = "getTitle" }
|
Fragment1.ktclass Fragment2 : Fragment() {
var titles=""
override fun onAttach(activity: Activity) { super.onAttach(activity) titles = (activity as FragmentActivity).getTitles() } }
|
Fragment 将数据传递给 Activity
- 在 Fragment 中定义一个内部回调接口,在 Activity 中实现接口
- Fragment 的方法
onAttach(),检查 Activity 是否实现对应接口
- 调用
onDetach() 方法,将传递进来的 Activity 对象释放掉
代码示例
Fragment.ktclass Fragment : Fragment(), View.OnClickListener {
var listener: FragmentListener? = null
interface FragmentListener { fun process(str: String) }
override fun onAttach(activity: Activity) { super.onAttach(activity)
if (activity is FragmentListener) { listener = activity } }
override fun onClick(v: View?) { listener?.process("我是接口") }
override fun onDetach() { super.onDetach() listener = null }
}
|
FragmentActivity.ktclass FragmentActivity : AppCompatActivity(), Fragment.FragmentListener {
override fun process(str: String) { TODO("Not yet implemented") } }
|
Activity 与 Service 数据通信
绑定服务,利用 ServiceConnection 类
在 Service 中创建一个 Bindler 对象:
class MyService : Service() {
private val mBinder = DownloadBinder()
class DownloadBinder : Binder() { fun startDownload() { Log.d("MyService", "startDownload: ") }
fun getProgress(): Int { Log.d("MyService", "getProgress: ") return 0 } }
override fun onBind(intent: Intent): IBinder { return mBinder } ... }
|
新建一个 DownloadBinder 类并继承自 Binder,在其内部提供方法。接着在 MyService 中创建 DownloadBinder 的实例,然后在 onBind() 方法中返回这个实例。
class MainActivity : AppCompatActivity() {
lateinit var downloadBinder: MyService.DownloadBinder
private val connection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { downloadBinder = service as MyService.DownloadBinder downloadBinder.startDownload() downloadBinder.getProgress() }
override fun onServiceDisconnected(name: ComponentName?) {
}
}
override fun onCreate(savedInstanceState: Bundle?) { ... binding.bindServiceBtn.setOnClickListener { val intent = Intent(this, MyService::class.java) bindService(intent, connection, BIND_AUTO_CREATE) }
binding.unbindServiceBtn.setOnClickListener { unbindService(connection) } } }
|
先创建一个 ServiceConnection 的匿名类实现,并在里面重写了 onServiceConnected() 方法和 onServiceDisconnected() 方法。onServiceConnected() 方法会在 Activity 与 Service 成功绑定的时候调用,而 onServiceDisconnected() 方法只有在 Service 的创建进程崩溃或者被杀掉的时候才会调用,这个方法不太常用。那么在 onServiceConnected() 方法中,又通过向下转型得到了 DownloadBinder 的实例。可以在 Activity 中根据具体的场景来调用 DownloadBinder 中的任何 public 方法。
调用 bindService() 方法将 MainActivity 和 MyService 进行绑定。bindService() 方法接收 3 个参数,第一个参数就是刚刚构建出的 Intent 对象,第二个参数是前面创建出的 ServiceConnection 的实例,第三个参数则是一个标志位,这里传入 IND_AUTO_CREATE 表示在 Activity 和 Service 进行绑定后自动创建 Service。这会使得 MyService 中的 onCreate() 方法得到执行,但 onStartCommand() 方法不会执行。调用 unbindService() 方法可以解除绑定。
简单通信,利用 Intent 进行传值
只能传递简单数据,性能没有优势
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.d(TAG, "onStartCommand: ") data = intent?.getStringArrayExtra("data") return super.onStartCommand(intent, flags, startId) }
|
定义一个 callback 接口来监听服务中的进程的变化
在 Service 中添加接口,在 Binder 中定义返回 Service 对象的方法
在 onServiceConnected() 方法中利用 IBinder 对象实现 Service 中的接口,实现的方法是在子线程中,需要使用 handler 更新 UI。
Activity 启动模式
standard (默认模式)
- 在不指定启动模式的前提下,系统默认使用该模式启动 Activity
- 每次启动一个 Activity 都会重新创建一个新的实例
- 会依次调用
onCreate(),onStart(),onResume() 方法
singleTop (栈顶复用)
如果当前任务的顶部已存在 Activity 的实例,则系统会通过调用其 onNewIntent() 方法来将 intent 转送给该实例,而不是创建 Activity 的新实例。如果不在顶部则会在堆栈中添加新实例。
应用场景:IM 对话框、新闻客户端推送、接收通知启动的内容显示页面等
singleTask (栈内复用)
- 根据任务相关性
taskAffinity(默认为包名) 寻找是否存在一个对应名字的任务栈
- 如果不存在则会创建一个新的 Task
- 如果存在则得到该任务栈,查找该任务栈中是否存在该 Activity 实例
- 如果存在实例则将该实例上方所有 Activity 实例出栈,然后回调该实例中的
onNewIntent() 方法
- 如果不存在则创建一个新的 Activity 实例
应用场景:应用主界面
singleInstance
与 singleTask 相似,唯一不同的是系统不会将任何其他 Activity 启动到包含该实例的任务中。该 Activity 始终是其任务唯一的成员;由该 Activity 启动的任何 Activity 都会在其他的任务中打开。
应用场景:呼叫来电、闹钟响铃界面等