一、前言
学习课程时,对于自己不懂的点的记录。
二、内容
学习(十二)结合Compose实现Handler机制处理多线程的通信。
效果图:
学习片段一:
这段代码是使用 Kotlin 编写的 Android Handler 的一个示例。下面是对代码的详细介绍:
val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (msg.what == 0x123) {
// 接受数据,并修改状态值
imageState.value = msg.arg1
}
}
}
1、定义Handler对象
关键部分说明
-
Handler:
Handler
是 Android 中用于处理消息和执行操作的工具。它可以用来在特定的线程中执行代码,通常是主线程(UI线程)。
-
Looper.getMainLooper():
Looper
是一个消息循环的类,getMainLooper()
返回主线程的消息循环。创建Handler
时传入这个 Looper,可以确保handleMessage
方法在主线程中执行。
-
重写
handleMessage
方法:handleMessage
方法用于接收和处理发送到该Handler
的消息。- 使用
super.handleMessage(msg)
调用父类的实现,确保父类的处理逻辑也能执行。
-
消息处理:
- 代码中检查
msg.what
是否等于0x123
,这是一个自定义的消息标识符。 - 如果条件满足,代码将
msg.arg1
的值赋给imageState.value
,这通常用于更新 UI 状态或数据。
- 代码中检查
用途
这种模式常用于在后台线程(例如网络请求或长时间运行的任务)完成后,向主线程发送消息以更新 UI。例如,当下载图片或获取数据时,可以使用此 Handler
来更新显示状态。
总结
这段代码展示了如何在 Android 开发中使用 Handler
来处理消息和更新状态,确保这些操作在主线程中执行,以避免潜在的线程安全问题。
2、msg: Message 这里的Message是什么?
在 Android 中,Message
是 android.os.Message
类的一个实例,用于在 Handler
和其他组件之间传递数据。它通常用于异步通信,允许不同线程之间进行消息传递。
Message
的主要特性
-
消息标识:
- 每个
Message
有一个what
字段,通常用于标识消息类型或类别。开发者可以自定义此字段以便于识别和处理不同类型的消息。
- 每个
-
附加数据:
Message
还包含一些额外的字段,如:arg1
和arg2
: 这两个字段通常用于存储整数数据,可以用于传递额外的信息或状态。obj
: 这个字段可以存储一个任意的对象,允许在消息中传递更复杂的数据。data
: 这是一个Bundle
对象,可以用于传递键值对形式的额外数据。
-
发送和处理:
Message
可以通过Handler
的sendMessage
方法发送。在目标Handler
的handleMessage
方法中,可以接收并处理这些消息。
使用示例
以下是一个简单的示例,展示如何创建和发送 Message
:
val message = Message.obtain()
message.what = 0x123
message.arg1 = 42 // 传递一个整数
handler.sendMessage(message)
在上面的代码中,创建了一个新的 Message
实例,设置了 what
和 arg1
字段,然后通过 handler.sendMessage(message)
发送到关联的 Handler
,在对应的 handleMessage
方法中将会处理这个消息。
总结
Message
类在 Android 中是一个强大的工具,允许你在不同线程之间异步传递信息,非常适合用于 UI 更新或后台任务的结果处理。
3、定义图片仓库
val imageRepository = ImageRepository(handler)
学习片段二
提供的 requestImage
函数中,有几个关键部分相互关联,主要是关于如何在后台线程中处理图像请求并通过 Handler
将结果发送回主线程。以下是对这段代码的详细解析:
fun requestImage(imageId: MutableState<Int>) {
thread {
// 定义工作线程
while (imageId.value in 0 until imageList.size) {
Thread.sleep(1000)
var message = Message.obtain()
message.what = 0x123
message.arg1 = imageList[imageId.value]
imageId.value = imageId.value + 1
// 发送数据
handler.sendMessage(message)
}
}
}
关键部分分析
-
后台线程:
thread { ... }
创建了一个新的线程来执行其中的代码。这是为了确保耗时的操作(如图像请求)不会阻塞主线程(UI线程)。
-
循环处理:
while (imageId.value in 0 until imageList.size)
这个循环会持续运行,直到imageId.value
超过imageList
的大小。这样可以确保只处理有效的图像 ID。
-
延迟处理:
Thread.sleep(1000)
让线程暂停 1 秒,模拟一个下载或处理图像的过程。这种方式常用于测试或模拟延迟。
-
创建和填充
Message
:Message.obtain()
创建一个新的Message
实例。message.what = 0x123
设置消息的类型,通常用于识别消息。message.arg1 = imageList[imageId.value]
将当前图像的 ID 或数据存储在arg1
字段中。
-
更新
imageId
:imageId.value = imageId.value + 1
增加imageId
的值,以便在下一个循环中处理下一个图像。
-
发送消息:
handler.sendMessage(message)
将创建的Message
发送到与Handler
相关联的线程(通常是主线程)。这使得可以在主线程中处理图像数据并更新 UI。
联系和作用
-
Handler
的作用:Handler
在这里的作用是接收来自后台线程的消息并在主线程中处理这些消息。这种设计模式确保了 UI 更新是线程安全的,因为 Android 的 UI 操作只能在主线程中执行。 -
MutableState<Int>
的作用:imageId
是一个可变状态,通常用于在 Compose 等框架中跟踪状态变化。它的值会在每次循环中更新,以便指向当前处理的图像。
总结
在这段代码中,requestImage
函数的设计通过使用 Handler
和后台线程,成功地将耗时的图像请求与 UI 更新逻辑分离。Handler
负责将处理结果发送回主线程,而 MutableState<Int>
用于跟踪当前正在处理的图像 ID,使得整个过程既高效又线程安全。
4、painterResource
Image(painter=painterResource(imageState.value),contentDescription="image")
中,painter参数介绍,还有painterResource解释介绍。
1. painter
参数
-
定义:
painter
是Image
组件的一个参数,类型为Painter
。它用于定义如何绘制图像。
-
作用:
painter
可以是从不同来源创建的,例如从资源文件、网络、内存缓存等。它抽象了图像的绘制逻辑,使得在 Compose 中使用图像变得简单而灵活。
2. painterResource
函数
-
定义:
painterResource
是一个用于加载图像资源的函数。它接受一个资源 ID,并返回一个Painter
对象,以便在Image
组件中使用。
-
用法:
- 你可以通过
painterResource
从 drawable 资源中加载图像。例如:
val painter = painterResource(id = R.drawable.my_image)
- 你可以通过
-
完整代码示例:
@Composable fun MyImageComponent(imageResId: Int) { Image( painter = painterResource(imageResId), contentDescription = "image" ) }
结合使用
在你的代码中,Image(painter = painterResource(imageState.value), contentDescription = "image")
的含义如下:
imageState.value
应该是一个包含图像资源 ID 的状态值(例如R.drawable.my_image
)。painterResource(imageState.value)
通过传入图像的资源 ID,加载相应的图像,并返回一个Painter
对象。Image
组件使用这个Painter
来绘制图像,并通过contentDescription
提供图像的描述,提升可访问性。
总结
painter
是Image
组件的一个参数,用于指定图像的绘制方式。painterResource
是一个函数,用于从资源中加载图像返回一个Painter
对象,以便可以在 Compose 中使用。通过这种方式,你可以轻松地将资源图像显示在 UI 中。
5、 MutableState<Int>
类型
在 Jetpack Compose 中,currentSelected
是一个 MutableState<Int>
类型的状态对象。它用于管理和观察与 UI 相关的状态变化。理解何时使用 .value
以及何时直接传递参数的关键在于状态的处理方式。
1. MutableState
的结构
MutableState<Int>
:currentSelected
是一个可变状态,它的值可以被修改并且可以在 UI 中观察。currentSelected.value
是获取这个状态的实际整数值。
2. 使用 .value
的情况
-
获取状态值:
-
当你需要使用
currentSelected
的实际整数值时,需要通过.value
来访问。例如,在RadioButton
的selected
属性中:selected = currentSelected.value - 1 == i
-
在这里,
.value
用于获取当前选择的索引,以便与循环中的i
进行比较。
-
-
设置状态值:
-
当你需要更新
currentSelected
的值时,也需要通过.value
来进行赋值。例如,在onClick
事件中:onClick = { currentSelected.value = i }
-
这里,
.value
被用来将currentSelected
的值更新为i
。
-
3. 直接传参的情况
- 直接传递
MutableState
对象:-
在某些情况下,如果函数的参数能够接受
MutableState
对象,你可以直接传递该对象,而不需要访问.value
。例如,在调用imageRepository.requestImage
方法时,如果该方法的参数是MutableState<Int>
类型:Button(onClick = { imageRepository.requestImage(currentSelected) })
-
在这个例子中,
requestImage
方法可能需要整个MutableState
对象,以便在其内部访问和修改值。你可以直接传递currentSelected
,而不需要使用.value
。
-
总结
- 使用
.value
是在需要获取或设置MutableState
的实际值时。 - 当你直接传递
MutableState
对象本身时,不需要使用.value
,因为函数可以直接处理状态对象。 - 理解这两者之间的区别可以帮助你更有效地管理 Compose 中的状态。
6、附上源代码
(为了简便放一个txt文件里了,加上图片也是可以运行的)
通过百度网盘分享的文件:cy(csdn十二)handler多线程.zip
链接:https://pan.baidu.com/s/1uA6qPHRDrT303SLKJjOCxw?pwd=wune
提取码:wune
--来自百度网盘超级会员V1的分享