在我们开发当中很多时候都会遇到:从网络上获取数据的操作或大量的IO数据操作时,会耗费很长时间,为了使用户的体验效果更好,现在大多数开发者都会使用异步的方式去处理这些的操作,异步的方式有好多种,在此我汇总了以下两种:
1.Handler + Thread的方式
2.AsyncTask异步更新UI界面
这两种方式各自有各自的优缺点,这里先介绍一下第一种方式
1.Hanlder介绍:
官方文档:
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
一个处理程序允许你发送和处理消息或者Runnable对象关联到的一个线程的MessageQueue。每个处理程序的实例相关联着一个单个线程和一个线程的消息队列。当你创建一个新的处理程序,它被绑定到线程/消息队列的线程时创建它——从那时起,它将提供消息和runnables给消息队列和执行他们出来的消息队列。
Handler主要方法:
常用方法 | 解释 |
Message obtainMessage(int what, Object obj) | 获取一个Message对象,包含了一个标识和value |
boolean post(Runnable r) | 将Runnable r添加到消息队列,之后会被UI线程执行 |
boolean postDelayed(Runnable r, long delayMillis) | 延迟多少毫秒之后,再将该线程加入到消息队列中 |
boolean sendEmptyMessage(int what) | 发送一个只有标识的消息 |
boolean sendMessage(Message msg) | 添加一条消息到消息队列的末尾 |
void handleMessage(Message msg) | 用于处理接收到的消息 |
简单的说Android采用UI单线程模型,所以只能在主线程中对UI元素进行操作。如果在非UI线程直接对UI进行了操作,就会报错,当然为了提高效率,Android为我们提供了消息循环的机制,我们可以利用这个机制来实现线程间的通信,在非UI线程发送消息到UI线程,最终让Ui线程来进行ui的操作
2.在非UI线程中发送消息通知UI线程更新界面:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
import
java.io.InputStream;
import
java.net.HttpURLConnection;
import
java.net.URL;
import
android.os.Bundle;
import
android.os.Handler;
import
android.os.Message;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.Button;
import
android.widget.ImageView;
import
android.widget.Toast;
import
android.app.Activity;
import
android.graphics.Bitmap;
import
android.graphics.BitmapFactory;
/**
* Handler + Thread 实现异步加载图片
* @author ZHF
*
*/
public
class
MainActivity
extends
Activity {
private
static
final
int
MSG_SUCCESS =
0
;
//成功获取图片
private
static
final
int
MSG_FAILURE =
1
;
//获取图片失败
public
static
final
String IMG_URL =
"http://images.51cto.com/images/index/Images/Logo.gi"
;
Button btn_handler;
ImageView imageView;
private
DownloadImgThread downloadImgThread;
private
Handler mHandler =
new
Handler(){
public
void
handleMessage(Message msg) {
//该方法是在UI主线程中执行
switch
(msg.what) {
case
MSG_SUCCESS:
imageView.setImageBitmap((Bitmap)msg.obj);
//显示图片
break
;
case
MSG_FAILURE:
Toast.makeText(MainActivity.
this
,
"获取图片失败"
, Toast.LENGTH_LONG);
break
;
}
};
};
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView)
this
.findViewById(R.id.imageView);
btn_handler = (Button)
this
.findViewById(R.id.btn_handler);
btn_handler.setOnClickListener(
new
OnClickListener() {
@Override
public
void
onClick(View v) {
//开启一个非UI线程,用于下载图片
downloadImgThread =
new
DownloadImgThread();
downloadImgThread.start();
}
});
}
/**图片下载线程**/
private
class
DownloadImgThread
extends
Thread{
HttpURLConnection conn;
InputStream inputStream;
Bitmap imgBitmap;
@Override
public
void
run() {
try
{
URL url =
new
URL(IMG_URL);
if
(url !=
null
) {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(
2000
);
connection.setDoInput(
true
);
connection.setRequestMethod(
"GET"
);
int
code = connection.getResponseCode();
if
(
200
== code) {
inputStream = connection.getInputStream();
imgBitmap = BitmapFactory.decodeStream(inputStream);
//获取图片成功,向ui线程发送MSG_SUCCESS标识和bitmap对象
mHandler.obtainMessage(MSG_SUCCESS,imgBitmap).sendToTarget();
}
else
{
//获取图片失败,向ui线程发送MSG_FAILURE
mHandler.obtainMessage(MSG_FAILURE).sendToTarget();
}
}
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
}
|
在自己的线程中获取到imgBitmap,不能直接imageView.setImageBitmap(imgBitmap),会报错的哦! 通过Message中obj将其存储起来,传递到UI线程中再对其操作。
权限:
1
|
<
uses-permission
android:name
=
"android.permission.INTERNET"
/>
|
2.View的post(Runnable r)方法
在获取到imgBitmap之后,可以通过下面代码实现UI界面的更新哦:
1
2
3
4
5
6
7
|
//另外一种更简洁的发送消息给ui线程的方法。
mImageView.post(
new
Runnable() {
@Override
public
void
run() {
//run()方法会在ui线程执行
mImageView.setImageBitmap(bm);
}
});
|
这是为什么那?
因为Android框架为每个应用的主线程创建了一个隐式的handler,使用post方法的原理就是给这个隐式的handler发送一个Runnable对象,然后隐式的handler会在ui线程执行Runnable对象的run()方法。
下一篇(AsyncTask):http://smallwoniu.blog.51cto.com/3911954/1252156
附件:http://down.51cto.com/data/2363167
本文转自zhf651555765 51CTO博客,原文链接:http://blog.51cto.com/smallwoniu/1252081,如需转载请自行联系原作者