Android的handler详解
来源:互联网 发布:access 导入sqlserver 编辑:程序博客网 时间:2024/05/21 17:00
handler
handler是什么?
handler是android给我们提供用来更新UI的一套机制,也是一套消息处理的机制,我们可以发送消息,也可以通过它处理消息。
handler两个主要用途:
安排消息或runnable对象在未来某个时间点执行。
安排动作在不同于自己的线程执行。
为什么要去使用handler
android在设计的时候,就封装了一套消息创建,传递,处理机制,如果不遵循这样的机制,就没办法更新UI信息,就会有异常。(子线程中更新UI是不安全的,多个线程去更新它会造成UI错乱)
如何使用handler
handler会绑定到创建它的线程中,线程中管理着一个Looper,Looper管理着MessageQueue,handler可以给MessageQueue发送Message,Looper轮询,等到处理这个Message时候调用message.target.dispatchMessage(msg)方法,target就是handler自己.
post(Runnbale) 直接调用runnable中的run,可以操作UI。
postDelayed(Runnable,long) 延迟第二个参数(毫秒)执行。
removeCallbacks(myRunnable) 移除handler的回调方法。
sendMessage(Message) 把message发送给handler,重写handler的handleMessage(Message)方法。
private Handler handler = new Handler(new Handler.Callback() { //这里构造方法里填一个callback,用来截获message。 //假如这个callback里的handleMessage return true 下面的将不会执行,反之则执行。 //一般用于截获符合它条件的message @Override, public boolean handleMessage(Message message) { Toast.makeText(getApplicationContext(),""+1,Toast.LENGTH_SHORT).show(); return true; } }){ @Override public void handleMessage(Message msg) { Toast.makeText(getApplicationContext(),""+2,Toast.LENGTH_SHORT).show(); } };
为什么要设计只能通过handler机制来更新UI
最根本的目的就是解决多线程并发的问题(),假设在一个activity中,有多个线程去更新UI,并且都没有加锁机制,就会导致更新界面错乱.
如果对更新UI的操作都进行加锁处理又会怎么样? 会导致性能下降.
处于以上的考虑,android给我们提供一套更新UI的机制,而不用过多考虑并发的问题.所有的更新UI操作,都在主线程的消息队列中去处理.
handler的原理是什么?
Handler封装了消息的发送(主要是包括消息发送给谁,target) //发送给自己???
Looper内部包含一个消息队列(MessageQueue),所有的handler发送的消息都走向这个消息队列.
Looper.loop 方法,就是一个死循环,不断的从MessageQueue取消息,有消息就处理消息,没有消息就阻塞.
MessageQueue就是一个消息队列,可以添加消息,并处理消息.
Handler内部会跟Looper进行关联,也就是在Handler内部可以找到Looper,也就找到了MessageQueue,在Handler中发送消息,其实就是向MessageQueue队列中发送消息.
总结:Handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给handler自己,MessageQueue就是一个存储消息的容器.
handler解析
在构造方法中
通过 mLooper = Looper.myLooper();
拿到当前线程的Looper对象.
public static @Nullable Looper myLooper() { //UI线程在创建的时候会set一个Looper对象进去. return sThreadLocal.get(); //取当前线程的Looper对象.}
拿Looper对象是为了拿它的MessageQueue,即mQueue = mLooper.mQueue;方便发Message给MessageQueue.
handler处理消息的方法 post postAtTime postDelayed sendMessage sendEmptyMessage sendEmptyMessageDelayed sendEmptyMessageAtTime sendMessageDelayed 基本都是return另一个方法. 追踪到最后都是调用sendMessageAtTime方法.函数间转化,会经常用到getPostMessage
把post方法里面的runnable参数转成message
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; //回调方法设置为r return m; }
sendMessageAtTime的实现 取出消息队列,为空抛异常,不为空就调用enqueueMessage(queue, msg, uptimeMillis);
enqueueMessage的实现
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);//把消息放到消息队列中去}
消息队列一直处于loop状态,for死循环,从队列中取消息,没消息就会退出.有消息就执行msg.target.dispatchMessage(msg);target默认是handler自己,
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); }}
// handler的obtainMessage()方法,调用message.obtain()方法,并把message的target设置为此handler,其它重载的大同小异
// message最好是调用Message.obtain().防止资源浪费,减少内存的开销.
/** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }**/
//threadlocal用于在线程中保存变量,set get
//message的what变量 方便接收者辨识这消息是关于什么的.
//默认应用程序通过ActivityThread进行创建,并回调各种方法,它默认有个线程:main. 默认又有一个Looper,Looper中又会有一个MessageQueue.
自定义与线程相关的handler
class MyThread extends Thread{ public Handler handler; @Override public void run() { Looper.prepare(); handler = new Handler(){ @Override public void handleMessage(Message msg) { Log.e("current thread:",Thread.currentThread().getName()); } }; Looper.loop(); } } private MyThread thread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); TextView textView = (TextView) findViewById(R.id.text1); textView.setText("hello handler"); thread = new MyThread(); thread.start(); try { //Log.e("current thread:",Thread.currentThread().getName()); Thread.sleep(500); //Log.e("current thread:",Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } thread.handler.sendEmptyMessage(1); }
HandlerThread的使用
多线程并发的时候,用到的looper对象可能没有创建,则会抛出空指针异常.使用handlerThread时候,调用getLooper方法会等待至Looper创建,不会出现Looper异常的现象.
主线程和子线程之间的通信
在主线程和子线程各定义一个handler,主线程可以通过子线程的handler向子线程发消息,同样子线程可以通过主线程的handler向主线程发消息.
几种更新UI的方法
主线程定义handler对象,子线程利用handler对象向主线程发送消息,如果多个类直接相互调用,不是非常方便,需要传递handler对象.(或者接口)
handler.post(Runnable);
handler.sendMessage();
activity的runOnUiThread(Runnable),需要传递activity对象.
runOnUiThread(Runnable action); 具体如下:
public final void runOnUiThread(Runnable action) {if (Thread.currentThread() != mUiThread) { mHandler.post(action);} else { action.run();}}
view的post方法,需要传递view的对象过去.
view.post(runnable)
attachInfo用来判断view的所属窗口.
public boolean post(Runnable action) {final AttachInfo attachInfo = mAttachInfo;if (attachInfo != null) {return attachInfo.mHandler.post(action);}// Assume that post will succeed laterViewRootImpl.getRunQueue().post(action);return true;}
- Asynctask.
适用的场景
如果是后台任务,像是下载任务等,就需要使用AsyncTask。
如果需要传递状态值等信息,像是蓝牙编程中的socket连接,就需要利用状态值来提示连接状态以及做相应的处理,就需要使用Handler + Thread的方式;(短信验证码提取)
需要另开线程处理数据以免阻塞UI线程,像是IO操作或者是循环,可以使用Activity.runOnUiThread();
如果只是单纯的想要更新UI而不涉及到多线程的话,使用View.post()就可以了;
非UI线程真的不能更新UI吗?
在oncreate方法里new一个Thread在它的run里面直接更新UI有时候是可以的,但是先让线程休眠2秒后就会报错. 更新UI时候会调用invalidate方法,里面有个ViewParent.invalidateChild(this, damage),判断是否是UI线程. viewRootImp初始化,在activity的onresume方法里.
handler使用时候的问题
在子线程中创建handler,没有关联looper,调用Looper.prepare(),抛出
Can’t create handler inside thread that has not called Looper.prepare()
这个异常.默认创建子线程是没有looper的.
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
- Android的handler详解
- Android的handler详解
- android的Handler详解(2)
- 关于Android-Handler的详解
- 详解Android Handler的使用
- android Handler的机制详解
- 详解Android Handler的使用-别说你不懂handler
- Android中Handler机制的详解
- Android中的Handler的post方法详解
- Android中有关Handler的使用详解
- Android中的Handler的post方法详解
- Android--Handler的post方法详解
- Android中的Handler的post方法详解
- Android中的Handler的post方法详解
- Android中的Handler的post方法详解
- Android的消息机制Handler详解
- Android开发:详解Handler的内存泄露
- 详解Android中Handler的实现原理
- android 代码获取版本信息
- 邮件服务器小结
- 获取结构体字节数简单的方法
- ViewHolder的二次封装
- 安装和使用CocoaPods
- Android的handler详解
- UVA 1153 - Keep the Customer Satisfied(贪心)
- jquery ajax 请求函数封装
- 全能型开源远程终端:MobaXterm
- innodb表最大列数限制
- window.prompt()输入对话框
- POJ1789——最小生成树
- POI 对excel表格基本操作Demo
- pom.xml中的java.home变量(eclipse默认的java.home变量)&& pom.xml详解&&maven常用配置的变量