Skip to content

Commit 2da6380

Browse files
committed
update-readme
1 parent f1fb826 commit 2da6380

9 files changed

+358
-3
lines changed

Diff for: .DS_Store

0 Bytes
Binary file not shown.

Diff for: BackGroundTasks/.DS_Store

0 Bytes
Binary file not shown.

Diff for: BackGroundTasks/SendingOperationsToMultipleThreads/将操作发送到多个线程——与UI线程通信.md

-2
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
# 将操作发送到多个线程——与UI线程通信
2+
3+
前一篇文章[将操作发送到多个线程——在线程池中的线程中运行代码](./将操作发送到多个线程——在线程池中的线程中运行代码.md),向您展示如何在`ThreadPoolExecutor`管理的线程上启动任务。本文将向您展示如何将任务中的数据发送给在用户界面(`UI`)线程上运行的对象。这允许您的任务执行后台工作,然后将结果返回到`UI`元素(如`bitmap`)。
4+
5+
每个应用程序都有自己的特殊线程来运行`UI`对象(例如`View`对象),这个线程称为`UI`线程。只有在`UI`线程上运行的对象才能访问该线程上的其他对象。由于您在线程池中的线程中运行的任务未在`UI`线程上运行,因此它们无权访问`UI`中的对象。要将数据从后台线程发送到`UI`线程,请使用在`UI`线程上运行的`Handler`
6+
7+
## 在UI线程定义一个Handler
8+
9+
`Handler``Android`系统`Framework`层的一部分,其作用是管理线程。 `Handler`对象接收消息并运行代码来处理消息。通常,您为新线程创建一个`Handler`,但您也可以创建一个连接到现有线程的`Handler`。将`Handler`连接到`UI`线程时,处理消息的代码会在`UI`线程上运行。
10+
11+
在构造创建线程池的类的过程中实例化`Handler`对象,并将对象存储在全局变量中。通过使用`Handler(Looper)`构造函数将其实例化,将其连接到`UI`线程。此构造函数使用`Looper`对象,这是`Android`系统的线程管理框架的另一部分。当您基于特定的`Looper`实例实例化`Handler`时,`Handler`在与`Looper`相同的线程上运行。例如:
12+
13+
- kotlin
14+
15+
- ```kotlin
16+
object PhotoManager {
17+
...
18+
private val handler: Handler = Handler(Looper.getMainLooper())
19+
...
20+
}
21+
```
22+
23+
- java
24+
25+
- ```java
26+
private PhotoManager() {
27+
...
28+
// Defines a Handler object that's attached to the UI thread
29+
handler = new Handler(Looper.getMainLooper()) {
30+
...
31+
```
32+
33+
在`Handler`中,重写`handleMessage()`方法,`Android`系统会在接收到新`message`的时候调用`handleMessage()`方法,一个线程的所有`Handler`都会接收到相同的消息。比如:
34+
35+
- kotlin
36+
37+
- ```kotlin
38+
object PhotoManager {
39+
private val handler: Handler = object : Handler(Looper.getMainLooper()) {
40+
/*
41+
* handleMessage() defines the operations to perform when
42+
* the Handler receives a new Message to process.
43+
*/
44+
override fun handleMessage(inputMessage: Message) {
45+
// Gets the image task from the incoming Message object.
46+
val photoTask = inputMessage.obj as PhotoTask
47+
...
48+
}
49+
}
50+
...
51+
}
52+
```
53+
54+
- java
55+
56+
- ```java
57+
/*
58+
* handleMessage() defines the operations to perform when
59+
* the Handler receives a new Message to process.
60+
*/
61+
@Override
62+
public void handleMessage(Message inputMessage) {
63+
// Gets the image task from the incoming Message object.
64+
PhotoTask photoTask = (PhotoTask) inputMessage.obj;
65+
...
66+
}
67+
...
68+
}
69+
}
70+
```
71+
72+
下一节将介绍如何通知`Handler`移动数据。
73+
74+
## 从task中将数据移动到UI线程
75+
76+
要把运行在后台线程的任务对象中的数据移动到`UI`线程上的对象中,请首先在数据和任务对象中存储`UI`对象。接下来,将任务对象和状态代码传递给实例化`Handler`的对象。在此对象中,将包含状态和任务对象的`Message`发送到处理程序。因为`Handler``UI`线程上运行,所以它可以将数据移动到UI对象。
77+
78+
### 在任务对象中存储数据
79+
80+
例如,这是一个在后台线程上运行的`Runnable`,它解码`Bitmap`并将其存储在其父对象`PhotoTask`中, `Runnable`还存储状态代码`DECODE_STATE_COMPLETED`
81+
82+
- kotlin
83+
84+
- ```kotlin
85+
const val DECODE_STATE_COMPLETED: Int = ...
86+
87+
// A class that decodes photo files into Bitmaps
88+
class PhotoDecodeRunnable(
89+
private val photoTask: PhotoTask,
90+
// Gets the downloaded byte array
91+
private var imageBuffer: ByteArray = photoTask.getByteBuffer()
92+
) : Runnable {
93+
...
94+
// Runs the code for this task
95+
override fun run() {
96+
...
97+
// Tries to decode the image buffer
98+
BitmapFactory.decodeByteArray(
99+
imageBuffer,
100+
0,
101+
imageBuffer.size,
102+
bitmapOptions
103+
)?.also { returnBitmap ->
104+
...
105+
// Sets the ImageView Bitmap
106+
photoTask.image = returnBitmap
107+
}
108+
// Reports a status of "completed"
109+
photoTask.handleDecodeState(DECODE_STATE_COMPLETED)
110+
...
111+
}
112+
...
113+
}
114+
```
115+
116+
- java
117+
118+
- ```java
119+
// A class that decodes photo files into Bitmaps
120+
class PhotoDecodeRunnable implements Runnable {
121+
...
122+
PhotoDecodeRunnable(PhotoTask downloadTask) {
123+
photoTask = downloadTask;
124+
}
125+
...
126+
// Gets the downloaded byte array
127+
byte[] imageBuffer = photoTask.getByteBuffer();
128+
...
129+
// Runs the code for this task
130+
public void run() {
131+
...
132+
// Tries to decode the image buffer
133+
returnBitmap = BitmapFactory.decodeByteArray(
134+
imageBuffer,
135+
0,
136+
imageBuffer.length,
137+
bitmapOptions
138+
);
139+
...
140+
// Sets the ImageView Bitmap
141+
photoTask.setImage(returnBitmap);
142+
// Reports a status of "completed"
143+
photoTask.handleDecodeState(DECODE_STATE_COMPLETED);
144+
...
145+
}
146+
...
147+
}
148+
...
149+
```
150+
151+
`PhotoTask`还包含一个显示`Bitmap``ImageView`的句柄。即使`Bitmap``ImageView`的引用位于同一对象中,也无法将`Bitmap`分配给`ImageView`,因为您当前没有在`UI`线程上运行。
152+
153+
所以,下一步是将此状态发送到`PhotoTask`对象。
154+
155+
### 将状态发送到对象层
156+
157+
`PhotoTask`是层次结构中的下一个更高级的对象。它维护对已解码数据的引用以及显示数据的`View`对象。它从`PhotoDecodeRunnable`接收状态代码并将其传递给维护线程池的对象并实例化`Handler`
158+
159+
- kotlin
160+
161+
- ```kotlin
162+
// Gets a handle to the object that creates the thread pools
163+
class PhotoTask() {
164+
...
165+
private val photoManager: PhotoManager = PhotoManager.getInstance()
166+
...
167+
fun handleDecodeState(state: Int) {
168+
// Converts the decode state to the overall state.
169+
val outState: Int = when(state) {
170+
PhotoDecodeRunnable.DECODE_STATE_COMPLETED -> PhotoManager.TASK_COMPLETE
171+
...
172+
}
173+
...
174+
// Calls the generalized state method
175+
handleState(outState)
176+
}
177+
...
178+
// Passes the state to PhotoManager
179+
private fun handleState(state: Int) {
180+
/*
181+
* Passes a handle to this task and the
182+
* current state to the class that created
183+
* the thread pools
184+
*/
185+
PhotoManager.handleState(this, state)
186+
}
187+
...
188+
}
189+
```
190+
191+
- java
192+
193+
- ```java
194+
public class PhotoTask {
195+
...
196+
// Gets a handle to the object that creates the thread pools
197+
photoManager = PhotoManager.getInstance();
198+
...
199+
public void handleDecodeState(int state) {
200+
int outState;
201+
// Converts the decode state to the overall state.
202+
switch(state) {
203+
case PhotoDecodeRunnable.DECODE_STATE_COMPLETED:
204+
outState = PhotoManager.TASK_COMPLETE;
205+
break;
206+
...
207+
}
208+
...
209+
// Calls the generalized state method
210+
handleState(outState);
211+
}
212+
...
213+
// Passes the state to PhotoManager
214+
void handleState(int state) {
215+
/*
216+
* Passes a handle to this task and the
217+
* current state to the class that created
218+
* the thread pools
219+
*/
220+
photoManager.handleState(this, state);
221+
}
222+
...
223+
}
224+
```
225+
226+
### 将数据移动到UI
227+
228+
`PhotoManager`对象从`PhotoTask`对象接收状态代码和`PhotoTask`对象的句柄。由于状态为`TASK_COMPLETE`,因此创建一个包含状态和任务对象的`Message`,并将其发送给`Handler`
229+
230+
- kotlin
231+
232+
- ```kotlin
233+
object PhotoManager {
234+
...
235+
// Handle status messages from tasks
236+
fun handleState(photoTask: PhotoTask, state: Int) {
237+
when(state) {
238+
...
239+
TASK_COMPLETE -> { // The task finished downloading and decoding the image
240+
/*
241+
* Creates a message for the Handler
242+
* with the state and the task object
243+
*/
244+
handler.obtainMessage(state, photoTask)?.apply {
245+
sendToTarget()
246+
}
247+
}
248+
...
249+
}
250+
...
251+
}
252+
```
253+
254+
- java
255+
256+
- ```java
257+
public class PhotoManager {
258+
...
259+
// Handle status messages from tasks
260+
public void handleState(PhotoTask photoTask, int state) {
261+
switch (state) {
262+
...
263+
// The task finished downloading and decoding the image
264+
case TASK_COMPLETE:
265+
/*
266+
* Creates a message for the Handler
267+
* with the state and the task object
268+
*/
269+
Message completeMessage =
270+
handler.obtainMessage(state, photoTask);
271+
completeMessage.sendToTarget();
272+
break;
273+
...
274+
}
275+
...
276+
}
277+
```
278+
279+
最后,`Handler.handleMessage()`检查每个传入消息的状态代码。如果状态代码为`TASK_COMPLETE`,则任务结束,`Message`中的`PhotoTask`对象包含`Bitmap`和`ImageView`。因为`Handler.handleMessage()`在`UI`线程上运行,所以它可以安全地将`Bitmap`移动到`ImageView`:
280+
281+
- kotlin
282+
283+
- ```kotlin
284+
object PhotoManager {
285+
...
286+
private val handler: Handler = object : Handler(Looper.getMainLooper()) {
287+
288+
override fun handleMessage(inputMessage: Message) {
289+
// Gets the image task from the incoming Message object.
290+
val photoTask = inputMessage.obj as PhotoTask
291+
// Gets the ImageView for this task
292+
val localView: PhotoView = photoTask.getPhotoView()
293+
...
294+
when (inputMessage.what) {
295+
...
296+
TASK_COMPLETE -> localView.setImageBitmap(photoTask.image)
297+
...
298+
else -> super.handleMessage(inputMessage)
299+
}
300+
...
301+
}
302+
...
303+
}
304+
...
305+
...
306+
}
307+
...
308+
}
309+
```
310+
311+
- java
312+
313+
- ```java
314+
private PhotoManager() {
315+
...
316+
handler = new Handler(Looper.getMainLooper()) {
317+
@Override
318+
public void handleMessage(Message inputMessage) {
319+
// Gets the task from the incoming Message object.
320+
PhotoTask photoTask = (PhotoTask) inputMessage.obj;
321+
// Gets the ImageView for this task
322+
PhotoView localView = photoTask.getPhotoView();
323+
...
324+
switch (inputMessage.what) {
325+
...
326+
// The decoding is done
327+
case TASK_COMPLETE:
328+
/*
329+
* Moves the Bitmap from the task
330+
* to the View
331+
*/
332+
localView.setImageBitmap(photoTask.getImage());
333+
break;
334+
...
335+
default:
336+
/*
337+
* Pass along other messages from the UI
338+
*/
339+
super.handleMessage(inputMessage);
340+
}
341+
...
342+
}
343+
...
344+
}
345+
...
346+
}
347+
...
348+
}
349+
```
350+
351+
## 更多信息
352+
353+
关于多线程的更多内容,请参阅[进程和线程——概述](…/BestPractices/Performance/进程和线程——概述.md)

Diff for: README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,11 @@ Android Developer Guide翻译项目,主要翻译[Android Developer Guide官方
6868

6969
- [Sending Operations To Multiple Threads(将操作发送到多个线程)](./BackGroundTasks/SendingOperationsToMultipleThreads)
7070

71-
- [OverView(概述)](./BackGroundTasks/SendingOperationsToMultipleThreads/将操作发送到多个线程——概述.md)
71+
- [OverView(概述)](./BackGroundTasks/SendingOperationsToMultipleThreads/将操作发送到多个线程——(1)概述.md)
72+
- [Specify the code to run on a thread(指定线程中运行的代码)](./BackGroundTasks/SendingOperationsToMultipleThreads/将操作发送到多个线程——(2)指定线程中运行的代码.md)
73+
- [Create a manager for multiple threads(为多线程创建管理者)](./BackGroundTasks/SendingOperationsToMultipleThreads/将操作发送到多个线程——(3)为多线程创建管理者(manager).md)
74+
- [Run code on a thread pool thread(在线程池中运行代码)](./BackGroundTasks/SendingOperationsToMultipleThreads/将操作发送到多个线程——(4)在线程池中的线程中运行代码.md)
75+
- [Communicate with the UI thread(与UI线程进行通信)](./BackGroundTasks/SendingOperationsToMultipleThreads/将操作发送到多个线程——(5)与UI线程通信.md)
7276

7377

7478

0 commit comments

Comments
 (0)