-
1. 什么是Handler:
Handler 网络释义“操纵者,管理者的”意思,在Android里面用于管理多线程对UI的操作;
2. 为什么会出现Handler:
在Android的设计机制里面,只允许主线程(一个程序第一次启动时所移动的线程,因为此线程主要是完成对UI相关事件的处理,所以也称UI线程)
对UI进行修改等操作,这是一种规则的简化,之所以这样简化是因为Android的UI操作时线程不安全的,为了避免多个线程同时操作UI造成线程安全
问题,才出现了这个简化的规则。
由此以来,问题就出现了,因为只允许主线程修改UI,那么如果新线程的操作需要修改原来的UI该如何进行的?举个常见的例子就是:如果新线程的操作是更新UI中TextView
的值,那么该如何操作?
这时候就需要Handler在新线程和主线程(UI线程)之间传递休息;
3. Handler的功能:
主要就是两个:
1)在新启动的线程中发送消息;
2)在主线程中获取,处理消息;
看似简单,但是如何处理同步问题却是一个难题,即如何把握新线程发送消息的时机和主线程处理消息的时机。这个问题的解决方案是:
在主线程和新线程之间使用一个叫做MessageQueue的队列,新启动的线程发送消息时将消息先发送到与之关联的MessageQueue,然后主线程的Handler方法会被调用
从MessageQueue中去取相应的消息进行处理。
4. Handler的实现机制
Handler的实现主要是依靠下面的几个方法:
读取消息使用到的方法是;
void handleMessage(Message msg) ,进程通过重写这个方法来处理消息。
final boolean hasMessage(int what), 检查消息队列中是否包含what属性为指定值的消息。
final boolean hasMessage(int what,Object object),减产队列中是否有指定值和指定对象的消息。
Message obtainMessage(): 获取消息,课被多种方式重载。
发送消息用到的方法有:
sendEmptyMessage(int what): 发送空消息;
final boolean sendEmptyMessageDelayed(int what, long delayMillis):指定多少毫秒之后发送空消息
final boolean sendMessage(Message msg):立即发送消息
final boolean sendMessageDelayed(Message msg, long delayMillis)指定多少毫秒之后发送空消息
01.
public
class
HandlerTest
extends
Activity
02.
{
03.
ImageView show;
04.
// 代表从网络下载得到的图片
05.
Bitmap bitmap;
06.
Handler handler =
new
Handler()
07.
{
08.
@Override
09.
<span style=
"color:#ff0000;"
>
public
void
handleMessage(Message msg)</span>
10.
{
11.
if
(msg.what ==
0x123
)
//如果该消息是本程序发的
12.
{
13.
// 使用ImageView显示该图片
14.
show.setImageBitmap(bitmap);
15.
}
16.
}
17.
};
18.
@Override
19.
public
void
onCreate(Bundle savedInstanceState)
20.
{
21.
super
.onCreate(savedInstanceState);
22.
setContentView(R.layout.main);
23.
show = (ImageView) findViewById(R.id.show);
24.
<span style=
"color:#ff0000;"
>
new
Thread()</span>
25.
{
26.
public
void
run()
27.
{
28.
try
29.
{
30.
// 定义一个URL对象
31.
URL url =
new
URL(
"http://img001.21cnimg.com/photos"
+
32.
<span style=
"white-space:pre"
> </span>
"/album/20140626/o/C164BDB0B24F59929C2113C0A9910636.jpeg"
);
33.
// 打开该URL对应的资源的输入流
34.
InputStream is = url.openStream();
35.
// 从InputStream中解析出图片
36.
bitmap = BitmapFactory.decodeStream(is);
37.
// 发送消息、通知UI组件显示该图片
38.
<span style=
"color:#ff0000;"
>handler.sendEmptyMessage(
0x123
);</span>
39.
is.close();
40.
}
41.
catch
(Exception e)
42.
{
43.
e.printStackTrace();
44.
}
45.
}
46.
}.start();
47.
}
48.
}
新的进程在将图片从网上解析下来之后向主进程发送空消息,之后主线程中handleMessage()的方法会被自动调用,更新UI。
5. 深入理解Handler的工作机制
上面我们看到了一个简单的Handler的工作过程,其中Handler是在主线程中定义的。如果Handler是在子线程中定义的那么可以更深入的理解他的工作原理。
因为有的时候我们需要将主线程中的消息传递给子线程,让子线程去处理一些计算量比较大的任务,因为应用程序应尽量避免在UI线程中执行耗时操作,否则会
导致ANR异常(Application Not Responding)。这样的话,我们上面所讲的 主线程和新线程的角色就发生了颠倒,主线程需要向新线程发送消息,然后新线程
进行消息的处理。在这种情况下,Handler需要定义在新线程中,在这种情况下需要做一些额外的工作。
我们先来解释一下配合Handler的其它组件:
Looper: 每个线程对应一个looper,它负责管理MessageQueue,将消息从队列中取出交给Handler进行处理;
MessageQueue:负责管理Message,接收Handler发送过来的message;
下图是整个工作的流程:
下面我们具体阐述一下工作的过程:
在创建一个Handler之前需要先创建Looper,创建的方式是Looper.prepare();
在创建Looper的同时会自动创建MessageQueue;
下面 创建一个Handler的对象
然后调用Looper的loop()方法
下面的这段代码是一个实例,摘自 疯狂android讲义;主进程将上限发送给子线程计算2-上限之间的素数
01.
public
class
CalPrime
extends
Activity
02.
{
03.
static
final
String UPPER_NUM =
"upper"
;
04.
EditText etNum;
05.
CalThread calThread;
06.
// 定义一个线程类
07.
class
CalThread
extends
Thread
08.
{
09.
<span style=
"color:#cc0000;"
>
public
Handler mHandler;</span>
10.
11.
public
void
run()
12.
{
13.
<span style=
"color:#ff0000;"
>Looper.prepare();</span>
14.
<span style=
"color:#ff0000;"
>mHandler =
new
Handler()</span>
15.
{
16.
// 定义处理消息的方法
17.
@Override
18.
public
void
handleMessage(Message msg)
19.
{
20.
if
(msg.what ==
0x123
)
21.
{
22.
int
upper = msg.getData().getInt(UPPER_NUM);
23.
List<Integer> nums =
new
ArrayList<Integer>();
24.
// 计算从2开始、到upper的所有质数
25.
outer:
26.
for
(
int
i =
2
; i <= upper ; i++)
27.
{
28.
// 用i处于从2开始、到i的平方根的所有数
29.
for
(
int
j =
2
; j <= Math.sqrt(i) ; j++)
30.
{
31.
// 如果可以整除,表明这个数不是质数
32.
if
(i !=
2
&& i % j ==
0
)
33.
{
34.
continue
outer;
35.
}
36.
}
37.
nums.add(i);
38.
}
39.
// 使用Toast显示统计出来的所有质数
40.
Toast.makeText(CalPrime.
this
, nums.toString()
41.
, Toast.LENGTH_LONG).show();
42.
}
43.
}
44.
};
45.
<span style=
"color:#ff0000;"
>Looper.loop();</span>
46.
}
47.
}
48.
@Override
49.
public
void
onCreate(Bundle savedInstanceState)
50.
{
51.
super
.onCreate(savedInstanceState);
52.
setContentView(R.layout.main);
53.
etNum = (EditText)findViewById(R.id.etNum);
54.
<span style=
"color:#ff0000;"
>calThread =
new
CalThread();</span>
55.
// 启动新线程
56.
<span style=
"color:#ff0000;"
>calThread.start();</span>
57.
}
58.
// 为按钮的点击事件提供事件处理函数
59.
public
void
cal(View source)
60.
{
61.
// 创建消息
62.
<span style=
"color:#ff0000;"
>Message msg =
new
Message();</span>
63.
msg.what =
0x123
;
64.
Bundle bundle =
new
Bundle();
65.
bundle.putInt(UPPER_NUM ,
66.
Integer.parseInt(etNum.getText().toString()));
67.
<span style=
"color:#ff0000;"
>msg.setData(bundle);</span>
68.
// 向新线程中的Handler发送消息
69.
<span style=
"color:#ff0000;"
>calThread.mHandler.sendMessage(msg);</span>
70.
}
71.
}
解析Android的消息传递机制Handler
最新推荐文章于 2022-05-27 09:20:44 发布