Android -- Looper.prepare()和Looper.loop() —深度版
Android中的Looper类,是用来封装消息循环和消息队列的一个类,用于在android线程中进行消息处理。handler事实上能够看做是一个工具类。用来向消息队列中插入消息的。
(1) Looper类用来为一个线程开启一个消息循环。
默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自己主动为其创建Looper对象,开启消息循环。) Looper对象通过MessageQueue来存放消息和事件。
一个线程仅仅能有一个Looper。相应一个MessageQueue。
(2) 一般是通过Handler对象来与Looper进行交互的。
Handler可看做是Looper的一个接口。用来向指定的Looper发送消息及定义处理方法。 默认情况下Handler会与其被定义时所在线程的Looper绑定,比方,Handler在主线程中定义。那么它是与主线程的Looper绑定。
mainHandler = new Handler() 等价于new Handler(Looper.myLooper()). Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。
(3) 在非主线程中直接new Handler() 会报例如以下的错误: E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception E/AndroidRuntime(
6173): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 原因是非主线程中默认没有创建Looper对象,须要先调用Looper.prepare()启用Looper。
(4) Looper.loop(); 让Looper開始工作,从消息队列里取消息,处理消息。
注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后。loop才会中止,其后的代码才干得以执行。
(5) 基于以上知识,可实现主线程给子线程(非主线程)发送消息。
把以下样例中的mHandler声明成类成员,在主线程通过mHandler发送消息就可以。
Android官方文档中Looper的介绍: Class used to run a message loop for a thread. Threads by default do not have a message loop
associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
Most interaction with a message loop is through the Handler class.
This is a typical example of the implementation of a Looper thread, using the separation of prepare() and loop() to create an initial Handler
to communicate with the Looper.
class LooperThread extends Thread
{
public Handler mHandler;
public void run()
{
Looper.prepare();
mHandler = new Handler()
{
public void handleMessage(Message msg)
{
// process incoming messages here
}
};
Looper.loop();
}
假设线程中使用Looper.prepare()和Looper.loop()创建了消息队列就能够让消息处理在该线程中完毕。
android HandlerThread使用小例
之前研究过handler 和 looper 消息队列。只是android里的handler不是另外开启线程来运行的。还是在主UI线程中,假设想另启线程的话须要用到HandlerThread来实现。在使用HandlerThread的时候须要实现CallBack接口以重写handlerMessage方法。在handlerMessage方法中来处理自己的逻辑。
下来给出一个小样例程序。
layout文件非常easy,就一个button来启动HanlderTread线程
<?xml version="1.0" encoding="utf-8"? >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" > <TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" /> <Button
android:id="@+id/handlerThreadBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="startHandlerThread" /> </LinearLayout>
Activity代码例如以下:
package com.tayue; import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.HandlerThread;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/**
*
* @author xionglei
*
*/
public class TestHandlerActivity extends Activity implements OnClickListener{ public Button handlerThreadBTN;
MyHandlerThread handlerThread;
Handler handler; /** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//打印UI线程的名称
System.out.println("onCreate CurrentThread = " + Thread.currentThread().getName()); setContentView(R.layout.main); handlerThreadBTN = (Button) findViewById(R.id.handlerThreadBtn);
handlerThreadBTN.setOnClickListener(this); handlerThread = new MyHandlerThread("myHanler");
handlerThread.start();
//注意: 这里必须用到handler的这个构造器,由于须要把callback传进去,从而使自己的HandlerThread的handlerMessage来替换掉Handler原生的handlerThread
handler = new Handler(handlerThread.getLooper(), handlerThread);
} @Override
public void onClick(View v) {
//点击button后来开启线程
handler.sendEmptyMessage(1);
} private class MyHandlerThread extends HandlerThread implements Callback { public MyHandlerThread(String name) {
super(name);
} @Override
public boolean handleMessage(Message msg) {
//打印线程的名称
System.out.println(" handleMessage CurrentThread = " + Thread.currentThread().getName());
return true;
}
}
}
点击button。打印的日志例如以下(这里点击了3次) 07-06 09:32:48.776: I/System.out(780): onCreate CurrentThread = main 07-06 09:32:55.076: I/System.out(780): handleMessage CurrentThread = myHanler 07-06 09:32:58.669: I/System.out(780): handleMessage CurrentThread = myHanler 07-06 09:33:03.476:
I/System.out(780): handleMessage CurrentThread = myHanler
HandlerThread就这么简单。
当然 android自己也有异步线程的handler,就是AsyncTask。这个类就是封装了HandlerThread 和handler来实现异步多线程的操作的。
相同能够这样使用:
private boolean iscancel = false; //用户手动取消登录的标志位
handlerThread = new HandlerThread("myHandlerThread");
handlerThread.start();
handler = new MyHandler(handlerThread.getLooper());
// 将要运行的线程对象加入到线程队列中
handler.post(new Runnable() {
@Override
public void run() {
Message message = handler.obtainMessage();
UserBean user = Bbs.getInstance().Login(username, password);//耗时任务
Bundle b = new Bundle();
b.putSerializable("user", user);
message.setData(b);
message.sendToTarget(); //或使用 handler.sendMessage(message);
}
});
class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
if(iscancel == false){
// 操作UI线程的代码
Bundle b = msg.getData();
UserBean user = (UserBean)b.get("user");
......
}
}
}
Android -- Looper.prepare()和Looper.loop() —深度版的更多相关文章
- Android -- Looper.prepare()和Looper.loop() —深入版
Android中的Looper类,是用来封装消息循环和消息队列的一个类,用于在android线程中进行消息处理.handler其实可以看做是一个工具类,用来向消息队列中插入消息的. (1) Loope ...
- 【转】Android -- Looper.prepare()和Looper.loop()
Looper.prepare()和Looper.loop() 原文地址:http://blog.csdn.net/heng615975867/article/details/9194219 Andro ...
- Looper.prepare()和Looper.loop()
什么时候需要 Looper Looper用于封装了android线程中的消息循环,默认情况下一个线程是不存在消息循环(message loop)的,需要调用Looper.prepare()来给线程创建 ...
- Android 线程 Looper.prepare()、Looper.loop() 使用
优化项目过程中发现了一个非常Low的问题,整理一下.备忘: 说问题之前先看下HandlerThread的定义 一个封装了looper的线程: Looper用于封装了android线程中的消息循环. ...
- Android handler 报错处理Can't create handler inside thread that has not called Looper.prepare()
问题: 写了一个sdk给其他人用,提供一个回调函数,函数使用了handler处理消息 // handler监听网络请求,完成后操作回调函数 final Handler trigerGfHandler ...
- Android进阶(十六)子线程调用Toast报Can't create handler inside thread that has not called Looper.prepare() 错误
原子线程调用Toast报Can't create handler inside thread that has not called Looper.prepare() 错误 今天用子线程调Toast报 ...
- ThreadLocal ——android消息机制handler在非主线程创建not called Looper.prepare() 错误的原因
引用自:https://www.jianshu.com/p/a8fa72e708d3 引出: 使用Handler的时候,其必须要跟一个Looper绑定.在UI线程可直接初始化Handler来使用.但是 ...
- android 37 线程通信Looper
安卓程序的主线程也叫UI线程. 工作线程和主线程的差别:安卓主线程已经调用了Looper.prepare()方法了,已经有一个MessageQueue对象了,所以才可以在工作线程用Handler发消息 ...
- 「Android」消息驱动Looper和Handler类分析
Android系统中的消息驱动工作原理: 1.有一个消息队列,可以往这个消息队列中投递消息; 2.有一个消息循环,不断的从消息队列中取得消息,然后处理. 工作流程: 1.事件源将待处理的消息加入到消息 ...
随机推荐
- Android Studio Gradle 添加.so 支持文件
近期发展Android Wear 关注商品.官员Demo所有gradle 工程. 当然,我也用eclipse配置一个可行的环境. 问题来了,eclipse,android studio 开发 andr ...
- JavaScript实战
JavaScript之单例实战 一.概述 所谓单例模式,顾名思义即一个类只有一个实例. 所以,当我们创建一个实例时,就必须判断其是否已经存在了这个实例,如果已经存在了这个实例,那么就返回这个已经存在的 ...
- VMware中linux与window目录共享
在虚拟机下来实如今windows下共享一个目录: (前提已安装完毕vmtools:http://blog.csdn.net/pipisorry/article/details/21318931) 打开 ...
- XML语法规范
1: 怎样声明一个xml文件 答:由2部分组成 声明部分,声明xml的版本号与编码(版本号仅仅有1.0) <? xml version="1.0" encoding=&quo ...
- 使用CSVDE批量导入命令/出口AD用户
使用CSVDE批量导入命令/出口AD用户 CSVDE命令行工具可以与真实的用户信息CSV文件.批量导入/出口AD在. 导入的基本的语法命令是这种: csvde -i -f c:\fil ...
- 如何在cocos2d项目中enable ARC
如何在cocos2d项目中enable ARC 基本思想就是不支持ARC的代码用和支持ARC的分开,通过xcode中设置编译选项,让支持和不支持ARC的代码共存. cocos2d是ios app开发中 ...
- poj2236(并查集)
题目连接 题意:一张图上分布着n台坏了的电脑,并知道它们的坐标.两台修好的电脑如果距离<=d就可以联网,也可以通过其他修好的电脑间接相连.给出操作“O x”表示修好x,给出操作“S x y”,请 ...
- C++内存管理学习笔记(7)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- MySQL 模拟Oracle邻接模型树形处理
数据库对层次结构的处理模型有好多种,能够依据自己的需求来设计模型.当然最简单的也是最easy设计的模型就是所谓的邻接模型.在这方面,其它数据库比方Oracle 提供了现成的分析方法 connect b ...
- SWT的TableVierer的使用一
1,简单显示,表格的式样见注释中的内容 import org.eclipse.jface.viewers.TableViewer;import org.eclipse.swt.SWT;import o ...