赞
踩
一、前期知识储备
(1)上官方文档:参见Handler类中的描述
首先,post和postDelay都是Handler的方法,用以在子线程中发送Runnable对象的方法;
其次,Android中post()方法可以直接在非UI线程中更新UI,不同与Handelr的Send类方法,需要进行切换;
最后,两个方法在实现UI线程事件的时间上有所区别,postDelayed()方法用以延期执行,post则是立即执行;
(2)Handler类的post类方法和send类方法联系与区别
①post类方法,以匿名内部类的形式发送Runnable对象,在Runnable对象重写的run()方法中直接对UI进行更新;
new Thread(new Runnable() {
@Override
public void run() {
/**
耗时操作
*/
handler.post(new Runnable() {
@Override
public void run() {
/**
更新UI
*/
}
});
}
}).start();
三种切回主线程的实例:
final Handler handler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
// 素描算法处理 耗时操作
final Bitmap bitmap1 = SketchUtil.testGaussBlur(finalBitmap,1,1);
final Bitmap bitmap2 = SketchUtil.testGaussBlur(finalBitmap,10,10);
final Bitmap bitmap3 = SketchUtil.testGaussBlur(finalBitmap,20,20);
// 三种切回主线程更新UI的方法
imageView.post(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap1); // 素描图
}
});
runOnUiThread(new Runnable() {
@Override
public void run() {
orignView.setImageBitmap(bitmap2); // 素描图
}
});
handler.post(new Runnable() {
@Override
public void run() {
threeView.setImageBitmap(bitmap3); // 素描图
}
});
}
}).start();
注意:使用handler方法切回主线程时,注意handler的实例化要放在主线程中,而不能在新开的子线程中,否则报错:
RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
这是因为,Handler在哪里创建,就获得哪里的Looper。主线程创建的Handler,即默认使用主线程的Looper。
常见常用的post()类方法汇总:
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
②send类方法,比如sendMessage()方法,使用该方法发送构造好的Message,然后用Handler的handleMessage()方法接收发送出来的消息,在方法中对UI进行更新;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) { //判断标志位
case 1:
/**
获取数据,更新UI
*/
break;
}
}
};
public class WorkThread extends Thread {
@Override
public void run() {
super.run();
/**
耗时操作
*/
//从全局池中返回一个message实例,避免多次创建message(如new Message)
Message msg =Message.obtain();
msg.obj = data;
msg.what=1; //标志消息的标志
handler.sendMessage(msg);
}
}
常见常用的send类方法汇总:
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
分析:谷歌为Android系统提供了一系列的post类方法用以发送Runnable对象,又提供了一系列的send类方法用以发送Message对象,其实二者并不矛盾也不重复,打开post类方法的源码,就会发现最终发送的Runnable对象也会转变成Message对象进行发送。谷歌提供两类方法应该是分别处理不同的场景,发送的消息较为复杂时,且每种消息对应一种UI的更新时选择使用send类方法;而当子线程中只发出一种消息时,则直接使用post方法发送消息,且直接在post方法的内部实现UI的更新。
(3)Message的构造
public final class Message implements Parcelable {
public int what;
public int arg1;
public int arg2;
public Object obj;
...
}
Message类中有这几个成员变量描述消息,其中what是我们定义的消息码,为了让接收者能知道消息是关于什么的。arg1和arg2用于发送一些integer类型的值。obj用于传输任意类型的值。
(4)Handler接收消息的方法-handleMessage()方法
Handler是Android系统为处理异步消息机制所提供的类,我们在实际开发中最常使用handler的场景即是在子线程中处理耗时操作后利用Handler的post类方法或者send类方法来发送消息;而当使用的是send类方法时,需要使用Handler来接收消息,同时使用Handler的handleMessage()方法来处理消息。
private static class MyHandler extends Handler{
//对Activity的弱引用
private final WeakReference<HandlerActivity> mActivity;
public MyHandler(HandlerActivity activity){
mActivity = new WeakReference<HandlerActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
HandlerActivity activity = mActivity.get();
if(activity==null){
super.handleMessage(msg);
return;
}
switch (msg.what) {
case DOWNLOAD_FAILED:
Toast.makeText(activity, "下载失败", Toast.LENGTH_SHORT).show();
break;
case DOWNLOAD_SUCCESS:
Toast.makeText(activity, "下载成功", Toast.LENGTH_SHORT).show();
Bitmap bitmap = (Bitmap) msg.obj;
activity.imageView.setVisibility(View.VISIBLE);
activity.imageView.setImageBitmap(bitmap);
break;
default:
super.handleMessage(msg);
break;
}
}
}
这里为避免出现内存泄漏,使用了静态内部类和弱引用结合的方式来实现。
二、上代码,看具体实现
view.post(new Runnable() {
@Override
public void run() {
view.performClick();//需要处理是事件,Android开发中常见的是UI操作
}});
注:post的方法意在main主线程执行完后立即调用。
view.postDelayed(new Runnable() {
@Override
public void run() {
view.performClick();//需要处理是事件,Android开发中常见的是UI操作
}},3000);//延迟3秒注:postDelayed的方法意在延迟执行,在main主线程执行完后延迟3秒后开始调用。
三、和Handler结合使用—开发中常见
实际开发中,最常见的就是和Handler结合使用,开启异步任务。
下面实现从网络中加载一张图片,并且显示在UI界面上
(1)在 Activity 中创建 handler 对象,调用工作线程执行;
public class MainActivity extends AppCompatActivity {
ImageView threadIv;
ImageView runnableIv;
SendThread sendThread;
PostRunnable postRunnable;
private final MyHandler handler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
threadIv = (ImageView) findViewById(R.id.thread_iv);
runnableIv = (ImageView) findViewById(R.id.runnable_iv);
sendThread = new SendThread(handler);
sendThread.start();
postRunnable = new PostRunnable(handler);
postRunnable.setRefreshUI(new PostRunnable.RefreshUI() {
@Override
public void setImage(byte[] data) {
runnableIv.setImageBitmap(getBitmap(data));
}
});
new Thread(postRunnable).start();
}
/**
为避免handler造成的内存泄漏
1、使用静态的handler,对外部类不保持对象的引用
2、但Handler需要与Activity通信,所以需要增加一个对Activity的弱引用
*/
private static class MyHandler extends Handler {
private final WeakReference<Activity> mActivityReference;
MyHandler(Activity activity) {
this.mActivityReference = new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MainActivity activity = (MainActivity) mActivityReference.get(); //获取弱引用队列中的activity
switch (msg.what) { //获取消息,更新UI
case 1:
byte[] data = (byte[]) msg.obj;
activity.threadIv.setImageBitmap(activity.getBitmap(data));
break;
}
}
}
private Bitmap getBitmap(byte[] data) {
return BitmapFactory.decodeByteArray(data, 0, data.length);
}
@Override
protected void onDestroy() {
super.onDestroy();
//避免activity销毁时,messageQueue中的消息未处理完;故此时应把对应的message给清除出队列
handler.removeCallbacks(postRunnable); //清除runnable对应的message
//handler.removeMessage(what) 清除what对应的message
}
}
(2)实现 runnable 接口,通过 post(Runnable)通信,并通过给定的回调接口通知 Activity 更新
public class PostRunnable implements Runnable {
private Handler handler;
private RefreshUI refreshUI;
byte[] data = null;
public PostRunnable(Handler handler) {
this.handler = handler;
}
@Override
public void run() {
/**
* 耗时操作
*/
final Bitmap bitmap = null;
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet("http://i3.17173cdn.com/2fhnvk/YWxqaGBf/cms3/FNsPLfbkmwgBgpl.jpg");
HttpResponse httpResponse = null;
try {
httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
data = EntityUtils.toByteArray(httpResponse.getEntity());
}
} catch (IOException e) {
e.printStackTrace();
}
//返回结果给UI线程
handler.post(new Runnable() {
@Override
public void run() {
refreshUI.setImage(data);
}
});
}
public interface RefreshUI {
public void setImage(byte[] data);
}
public void setRefreshUI(RefreshUI refreshUI) {
this.refreshUI = refreshUI;
}
}
文章后期更改过,将文章主旨内容从post()方法和postDelayed()方法的联系与区别转到Android中使用Handler进行异步消息的处理,以几段代码为例,分析了Handler的发送消息的方法:①post类方法;②send类方法;及Handler类接收消息和处理消息的方法handleMessage();最后模拟了从网上下载图片进而在UI界面中进行更新。
提供一些其他Android消息机制分析,帮助理解读者理解:
①Handler是Android消息机制的上层接口,通过它可以轻松地将一个任务切换到Handler所在的线程中去执行,该线程既可以是主线程,也可以是子线程,要看构造Handler时使用的构造方法中传入的Looper位于哪里;
②Handler的运行需要底层的MessageQueue和Looper的支撑,Handler创建的时候会采用当前线程的Looper来构造消息循环系统,而线程默认是没有Looper的,如果需要使用Handler就必须为线程创建Looper;
③上述代码中的第一个Handler-mainHandler,实例化的时候,直接在onCreate()方法中new出了实例,其实是其已经在主线程中了,主线程-ActivityThread,ActivityThread被创建时就会初始化Looper,这就是主线程中默认可以直接使用Handler的原因;
④上述代码中的第二个Handler-workHandler,它在实例化的时候,参数传入了 mHandlerThread.getLooper() ,注意,这个Handler使用的就不是主线程的Looper了,而是子线程的Looper,HandlerThread在调用start()方法之后,就可以获取到子线程的Looper,然后将其传入workHandler的构造方法中,那么此时的workHandler就会运行在子线程中,用于处理耗时操作。
⑤Handler的工作原理:Handler创建时会采用当前线程的Looper来构建内部消息循环系统,如果当前线程没有Looper,那么就会报错“Can`t create handler inside thread that has not called Looper.prepare()”解决方法有两个:为当前线程创建Looper即可,像上述代码中workHandler,或者在一个有Looper的线程中创建Handler也行,就像上述代码中的mainHandler一样;
⑥调用Handler的post方法会将一个Runnable投递到Handler内部的Looper中去处理,也可以通过Handler的send方法来发送一个消息,这个消息同样会在Looper中去处理。其实post方法最终也是通过send方法来完成的。每当Looper发现有新消息到来时,就会处理这个消息,最终消息中的Runnable的run方法或者Handler的handleMessage方法就会被调用。注意Looper是运行在创建Handler所在的线程中的,这样一来Handler中的业务逻辑就被切换到创建Handler所在的线程中去执行了;
⑦Looper的工作原理:Looper在Android的消息机制中扮演着消息循环的角色,具体来说就是它会不停地从MessageQueue中查看是否有新消息,如果有新消息就会立刻处理,否则就一直阻塞在那里。注意关注一些重要的Looper的方法:
⑧ActivityThread主线程通过ApplicationThread和AMS进行进程间通信
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。