标签:读取 thread img 执行计划 高级 重写 kms 经验 阻塞
从一开始开通博客就计划一周至少写两篇博客,把自己的以前记在本地下的知识点和经验,全部搬到自己的博客里,无论是复杂难易程度只要是自己想写的就搬到这里来,好好总结下形成自己的技术体系,因为有些东西不用就会一时之间想不起来了。ORZ…好了进入正题,对于Java开发来说Thread比较简单,直接匿名创建重写run方法,调用start方法执行即可。或者从Runnable接口继承,但对于Android来说在底层UI操作部分代码没有设计成为线程安全类型,所以需要引入一些同步的机制来实现线程间的通信使其刷新。Handler就是在这样的设计背景下应运而生。
Handler跟多线程,消息队列联系很紧密,其主要的功能就是发送和处理Message,也可以分发Runnable对象。 每个Handler实例,都会绑定到创建他的线程中(默认是位于主线程,但是我们可以通过Looper对象来指定到其他线程)。
package cmo.learn.mutiplethread;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class HandlerActivity extends Activity {
private Handler mainHandler1;
private Handler mainHandler2;
Button mBtn1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
// 在主线程中初始化Handler
mainHandler1 = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("HandlerTest", "主线程的Handler1对象接收到消息" + msg.what);
}
};
mainHandler2 = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("HandlerTest", "主线程的Handler2对象接收到消息" + msg.what);
}
};
}
public void testHandler(View view) {
switch (view.getId()) {
case R.id.btn_handler01:
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
i++;
}
//mainHandler1.sendEmptyMessage(1);
mainHandler2.sendEmptyMessage(1);
}
}).start();
break;
case R.id.btn_handler02:
break;
case R.id.btn_handler03:
break;
default:
break;
}
}
}
运行结果:
当使用mainHandler1.sendEmptyMessage(1)发送消息时,mainHandler1接收到消息并处理
当使用mainHandler2.sendEmptyMessage(1)发送消息时,mainHandler2接收到消息并处理
/*运行时报java.lang.RuntimeException: Can‘t create handler inside thread that has not called Looper.prepare()异常*/
new Thread(new Runnable(){
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
i++;
}
Handler handler=new Handler();//Handler放到当前新线程中
handler.sendEmptyMessage(3);
}
}).start();
private class MyHandlerThread extends HandlerThread{
public MyHandlerThread(String name) {
super(name);
}
@Override
protected void onLooperPrepared() {
super.onLooperPrepared();
for (int i = 0; i < 1000; i++) {
i++;
}
Looper loop=this.getLooper();
new Handler(loop){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("HandlerTest", Thread.currentThread().getName()+"线程的Handler对象接收到消息" + msg.what);
}
}.sendEmptyMessage(3);
}
}
public void testHandler(View view) {
switch (view.getId()) {
case R.id.btn_handler01:
//在新的线程中创建Handler和发送消息
new Thread(new Runnable(){
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
i++;
}
Handler handler=new Handler();//Handler放到当前新线程中
handler.sendEmptyMessage(3);
}
}).start();
break;
case R.id.btn_handler02:
MyHandlerThread myThread=new MyHandlerThread("子线程");//调用
myThread.start();
break;
default:
break;
}
}
运行结果
case R.id.btn_handler02:
/*MyHandlerThread myThread=new MyHandlerThread("子线程");
myThread.start();*/
//使用MainLooper来指定
new Thread(new Runnable(){
@Override
public void run() {
Handler handler;
handler=new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("HandlerTest", Thread.currentThread().getName()+"的Handler对象接收到消息" + msg.what);
}
};
handler.sendEmptyMessage(4);
}
}).start();
运行结果:
//使用Looper.prepare()和Looper.loop()来指定运行的线程
new Thread(new Runnable(){
@Override
public void run() {
Handler loophandler;
Looper.prepare();//必须执行
loophandler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("HandlerTest", Thread.currentThread().getName()+"的Handler对象接收到消息" + msg.what);
}
};
loophandler.sendEmptyMessage(5);
Looper.loop();
}
}).start();
运行结果:
通过以上两个小实验,我们可以知道,通过指定Looper对象,我们就可以控制Handler运行在指定的线程。
首先封装我们自己的一个Handler来处理两条消息
private class ProcessMessageHandler extends Handler{
public ProcessMessageHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("HandlerTest", "Start:ProcessMessageHandler对象接收到第一条消息" + msg.what);
try{
Thread.sleep(5000);//阻塞5秒,是为了避免UI被阻塞,把Handler放到了另外的线程
}catch(Exception e){
e.printStackTrace();
}
Log.d("HandlerTest", "End :ProcessMessageHandler对象接收到第二条消息" + msg.what);
}
}
模拟同时发送两条信息
HandlerThread threadProcess=new HandlerThread("Process");
threadProcess.start();//启动HandlerThread
Handler handlerProcess=new ProcessMessageHandler(threadProcess.getLooper());
handlerProcess.sendEmptyMessage(6);//发送两条消息,每条消息都执行6s
handlerProcess.sendEmptyMessage(7);
运行结果:
两条消息之间是不可能出现交替处理的,只有我们处理完一条消息之后,才会再从MessageQueue中读取下一条消息。
首先还是先启动一条HandlerThread
private Handler workMsgHandler;
HandlerThread workingMsgThread=new HandlerThread("WorkingMsg");
workingMsgThread.start();
workMsgHandler=new ProcessMessageHandler(workingMsgThread.getLooper());
发送消息
workMsgHandler.sendEmptyMessage(10);//发送消息
workMsgHandler.sendEmptyMessage(12);//发送消息
执行Remove:
workMsgHandler.removeMessages(12);//5S前移除消息what为12
运行结果对比:
未移除what为12的消息:
移除了what为12的消息:
首先还是先启动一条HandlerThread
private Handler workMsgHandler;
HandlerThread workingMsgThread=new HandlerThread("WorkingMsg");
workingMsgThread.start();
workMsgHandler=new ProcessMessageHandler(workingMsgThread.getLooper());
发送消息之后
workMsgHandler.sendEmptyMessage(10);//发送消息
马上执行移除消息
workMsgHandler.removeMessages(10);//5S前移除消息what为10
运行结果:
很明显无法Remove掉正在执行的Message,如果呗Remove掉的话“End……”就不会被打印
一旦Message已经被执行,在执行的过程中不会被Remove掉;能Remove的只有未被执行的Message即Remove只能移除消息队列中的Message。
虽然在Android中已经不推荐使用 WeakReference(防止内存泄漏,要保证内存被虚拟机回收,即弱引用关联的对象在JVM进行垃圾回收时总会被回收),甚至在高级版本中据说已经完全删除了弱引用,但是个人觉得若是用得恰当对自己开发的代码质量的提高有显著的效果。反之,则坑人坑己。any way,慎用为妙。
通过弱引用得到Activity的对象,进而在封装的Handler中使用Activity的方法交互
static class MyHandler extends Handler{
private final WeakReference<Activity> mAct;//声明弱引用
//声明构造方法供外部调用构MyHandler对象
public MyHandler(MainActivity act){
mAct=new WeakReference<Activity>(act);
}
@Ovrride
public void handleMessage(Message msg){
//在这里获取MainActivity的引用并强转,调用相关方法showMessage
((MainActivity)mAct.get()).showMessage();
}
}
使用自己封装的Handler发送消息
private MyHandler handler=new MyHandler();
Handler实例与消息处理是相关联的,发送和接收都要求匹配,只能依附在Handler线程或其子类中,所以Handler的所有操作都是在一个线程中。推荐一个GC在线源码阅读网站
Android进阶——强大的异步不可或缺的组件Handler详解(一)
标签:读取 thread img 执行计划 高级 重写 kms 经验 阻塞
原文地址:http://blog.csdn.net/crazymo_/article/details/50351025