Android Activity

Activity 是与用户交互的接口

Android 系统通过 Activity 栈的形式管理 Activity

Activity 4 种形态

  1. Active 运行状态:Activity 处于栈顶,可见,可以和用户进行交互
  2. Paused 暂停状态:不处于栈顶,可见但不可交互,失去焦点被非全屏 Acitivty 挡住
  3. Stopped 停止状态:不处于栈顶并且完全不可见,被另一个 Activity 完全覆盖
  4. Killed 销毁状态:从返回栈中移除,系统回收掉

Activity 生命周期

图 1.Activity 生命周期的简化图示

以下是 Activity A 启动 Activity B 时的操作发生顺序:

  1. Activity A 的 onPause() 方法执行。
  2. Activity B 的 onCreate()onStart()onResume() 方法依次执行(Activity B 现在具有用户焦点)。
  3. 然后
    • 如果 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.kt
class FirstActivity : AppCompatActivity() {

private val requestDataLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
val data = result.data?.getStringExtra("data")
// Handle data from SecondActivity
}
}

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.kt
class 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

  • LiveData

Bundle

FragmentActivity.kt
class 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.kt
class Fragment1 : Fragment() {
var productId = ""

override fun onStart() {
super.onStart()
// 判断Fragment已经依附Activity
if (isAdded) {
productId = arguments?.getString("params", "") ?: ""
}
}
}

在 Activity 中定义方法

FragmentActivity2.kt
class FragmentActivity2 : AppCompatActivity() {

val productId = ""

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}

fun getTitles() = "getTitle"
}
Fragment1.kt
class Fragment2 : Fragment() {

var titles=""

override fun onAttach(activity: Activity) {
super.onAttach(activity)
// 通过强转成宿主activity就可以获取到需要的数据
titles = (activity as FragmentActivity).getTitles()
}
}

Fragment 将数据传递给 Activity

  1. 在 Fragment 中定义一个内部回调接口,在 Activity 中实现接口
  2. Fragment 的方法 onAttach(),检查 Activity 是否实现对应接口
  3. 调用 onDetach() 方法,将传递进来的 Activity 对象释放掉

代码示例

Fragment.kt
class Fragment : Fragment(), View.OnClickListener {

// 2.1 定义用来与外部activity交互,获取到宿主activity的listener
var listener: FragmentListener? = null

// 1 定义了所有activity必须实现的接口方法
interface FragmentListener {
fun process(str: String)
}

override fun onAttach(activity: Activity) {
super.onAttach(activity)

if (activity is FragmentListener) {
// 2.2 获取到宿主activity并赋值
listener = activity
}
}

override fun onClick(v: View?) {
// 3.1 执行回调
listener?.process("我是接口")
}

// 把传递进来的activity对象释放掉
override fun onDetach() {
super.onDetach()
listener = null
}

}
FragmentActivity.kt
class 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) // 绑定Service
}

binding.unbindServiceBtn.setOnClickListener {
unbindService(connection) // 解绑Service
}
}
}

先创建一个 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 (默认模式)

    1. 在不指定启动模式的前提下,系统默认使用该模式启动 Activity
    2. 每次启动一个 Activity 都会重新创建一个新的实例
    3. 会依次调用 onCreate()onStart()onResume() 方法
  • singleTop (栈顶复用)
    如果当前任务的顶部已存在 Activity 的实例,则系统会通过调用其 onNewIntent() 方法来将 intent 转送给该实例,而不是创建 Activity 的新实例。如果不在顶部则会在堆栈中添加新实例。

    应用场景:IM 对话框、新闻客户端推送、接收通知启动的内容显示页面等

  • singleTask (栈内复用)

    1. 根据任务相关性 taskAffinity(默认为包名) 寻找是否存在一个对应名字的任务栈
    2. 如果不存在则会创建一个新的 Task
    3. 如果存在则得到该任务栈,查找该任务栈中是否存在该 Activity 实例
      • 如果存在实例则将该实例上方所有 Activity 实例出栈,然后回调该实例中的 onNewIntent() 方法
      • 如果不存在则创建一个新的 Activity 实例

    应用场景:应用主界面

  • singleInstance
    singleTask 相似,唯一不同的是系统不会将任何其他 Activity 启动到包含该实例的任务中。该 Activity 始终是其任务唯一的成员;由该 Activity 启动的任何 Activity 都会在其他的任务中打开。

    应用场景:呼叫来电、闹钟响铃界面等

可靠便捷的VPN服务 100 G 月流量,5台设备可用,一年仅需99元!
请我一杯咖啡吧!
八亩山啊 微信 微信
八亩山啊 支付宝 支付宝
八亩山啊 比特币 比特币
  • 本文作者: 八亩山啊
  • 本文链接: https://mumo.fun/posts/14/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!