第五种方法:AsyncTask
这里说说Handler机制:
一.基本概念:
1. 消息类:Message类
android.os.Message的主要功能是进行消息的封装,同时可以指定消息的操作形式
2. 消息通道:Looper
在使用Handler处理Message时,需要Looper(通道)来完成。在一个Activity中,系统会自动帮用户启动Looper对象,而在一个用户自定义的类中,则需要用户手工调用Looper类中的方法,然后才可以正常启动Looper对象。Looper的字面意思是“循环者”,它被设计用来使一个普通线程变成Looper线程。所谓Looper线程就是循环工作的线程。
3. 消息操作类:Handler类
Message对象封装了所有的消息,而这些消息的操作需要android.os.Handler类完成。handler起到了处理M消息的作用(只处理由自己发出的消息),它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。
如图:
Handle的四大核心机制是:Message,Handle,Looper,target
是怎样的一个过程?
1一个线程可以有多个hander,每个hander都有自己标识的target
2.一个线程只有一个looper(只负责从队列中按顺序循环取出消息)
然后每个handler把looper循环出的消息根据target标识来处理自己的消息。
二.常见问题:
问题1.Handle导致内存泄露及解决方案?
由target和ThreadLocal解决。
ThreadLocal是什么?
JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序,ThreadLocal并不是一个Thread,而是Thread的局部变量。具体请参照博客:http://lavasoft.blog.51cto.com/62575/51926/
简单来说:它就是线程真正保存线程自己本地变量的容器。每一个线程都有自己的单独的一个空间,致使不同线程调用同个数据是不会发生混乱。
问题2:handler为什么阻塞?
1。在handler队列中,没有handler存在的情况,Looper就不发生阻塞,不会再从
消息队列中获取message
2。如果handle创建的时间小于message队列中一些message的放入时间。
那么Looper就不会去轮询这些message了,产生阻塞。因为,Looper是先要看handle的脸色后再去轮询消息的。
问题3:内存泄露问题?
如图:如果开启线程向服务器加载图片,但加载不来。每个类里面都存有其他的对象的应用
,这个线程不会销毁,一直请求。这种强引用不会自动中断,就会内存溢出。
解决方案:中断引用
Handler.removeMessage()
Handler.romoveCallbacks
问题4:如果handler创建在子线程,如何更新接受到消息后更新ui?
先看下面方法:
Looper.myLooper()【当前Activity的线程,不可更新UI】
Looper.prepare();
Looper.loop();
new Thread(){//创建一个子线程 public void run() { Looper.prepare(); Handler hander=new Handler(Looper.myLooper()){ public void dispatchMessage(android.os.Message msg) { //可以接受到消息,但不能在这个子线程中更新UI }; }; Looper.loop(); }; }.start();如果找到主线程的Looper就可以了。
new Thread(){//创建一个子线程 public void run() { Handler hander=new Handler(Looper.getMainLooper()){ public void dispatchMessage(android.os.Message msg) { //通过接受的消息,在子线程中更新UI }; }; }; }.start();原因:这个looper是主Activity初始化时,就创建的,既然是主线程当然可以更新UI。
下篇博客讲下:第五种方法:AsyncTask