android高手进阶教程(一)之--android中的消息机制
2015-09-08 17:51
615 查看
1.1 异步神器Handler
Handler允许我们在一个线程的消息队列(
MessageQueue)里面发送、处理
Message和
Runnable,每一个
Handler只能在一个线程和一个消息队列(
MessageQueue),当我们创建
Handler时,这个
Handler与当前线程和当前线程里面的消息队列(
MessageQueue)关联,当线程执行操作结束后,
Handler可以将消息分发出去。
Handler中我们使用频率较高的是
post(Runnable r)和
sendMessage(Message msg),通过源码我们可以看到都调用了将当前
Message加入消息队列,然后当前线程的
Looper通过获取当前的
MessageQueue获取消息再发送个
Handler,由
Handler分发给拥有这个
Handler的线程(必须是拥有
Handler的线程)。
/** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is * attached. * * @param r The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } /** * Pushes a message onto the end of the message queue after all pending messages * before the current time. It will be received in {@link #handleMessage}, * in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } /** * Enqueue a message into the message queue after all pending messages * before the absolute time (in milliseconds) <var>uptimeMillis</var>. * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> * Time spent in deep sleep will add an additional delay to execution. * You will receive it in {@link #handleMessage}, in the thread attached * to this handler. * */ public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }
1.2 Handler 使用实例
public class MainActivity extends Activity { private ImageView image; private Handler mHandler = new Handler(){ /** * 获取子线程中消息队列发送的Message * @param msg */ @Override public void handleMessage(Message msg) { super.handleMessage(msg); Bitmap bm = (Bitmap) msg.obj; image.setImageBitmap(bm); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); image = (ImageView) findViewById(R.id.image); new MyThread(mHandler).start(); } private class MyThread extends Thread{ private Handler mHandler; public MyThread(Handler handler){ this.mHandler = handler; } @Override public void run() { //1.耗时操作,比如请求网络 try { HttpURLConnection connection = (HttpURLConnection) new URL("http://h.hiphotos.baidu.com/image/pic/item/e7cd7b899e510fb300679675da33c895d0430cd1.jpg").openConnection(); connection.setConnectTimeout(5000); connection.setReadTimeout(20000); InputStream is = connection.getInputStream(); Bitmap bm = BitmapFactory.decodeStream(is); //2.结果包装到Message Message msg = new Message(); msg.obj = bm; //3.handler将消息发送给主线程(一般式UI线程) mHandler.sendMessage(msg); } catch (IOException e) { e.printStackTrace(); } } } }
1.3 HandlerThread
HandlerThread是一个拥有looper的线程,这个looper可以用来创建handler,启动这个线程需要调用start().public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = android.os.Process.THREAD_PRIORITY_DEFAULT; } /** * 构造方法 * @param name thread的name * @param priority 优先级 */ public HandlerThread(String name, int priority) { super(name); mPriority = priority; } /** * 回调方法,可以被复写 */ protected void onLooperPrepared() { } @Override public void run() { //获取线程id mTid = Process.myTid(); //将当前线程初始化为Looper线程 Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); //开始循环处理消息队列 Looper.loop(); mTid = -1; } /** * 这个方法返回和此线程相关的Looper,如果这个线程没有启动或者isAlive()返回false,Looper将返回null, * 如果这个线程已经启动,这个方法将会阻塞,一直到looper实例化后。 * @return The looper. */ public Looper getLooper() { if (!isAlive()) { return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; } public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } /** * 停止 * @return */ public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; } /** * 获取线程id */ public int getThreadId() { return mTid; } }
2.1 单曲循环Looper
Looper的字面意思就是“循环者”,一个普通线程通过它可以变成一个循环线程,上文中的HandlerThread就是典型的例子,在平时开发中,我们经常需要一个循环线程,一旦有新任务则执行,执行完毕后必须等待下一个任务,这就是Looper线程。使用Looper创建线程也很简单。class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // 处理消息 } }; Looper.loop(); } }
2.2 Looper源码解析
public class Looper { // 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象 private static final ThreadLocal sThreadLocal = new ThreadLocal(); // Looper内的消息队列 final MessageQueue mQueue; // 当前线程 Thread mThread; //其他属性 // 每个Looper对象中有它的消息队列,和它所属的线程 private Looper() { mQueue = new MessageQueue(); mRun = true; mThread = Thread.currentThread(); } // 我们调用该方法会在调用线程的TLS中创建Looper对象 public static final void prepare() { if (sThreadLocal.get() != null) { // 试图在有Looper的线程中再次创建Looper将抛出异常 throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); } public static final void loop() { Looper me = myLooper(); //得到当前线程Looper MessageQueue queue = me.mQueue; //得到当前looper的MQ // 保证拥有此Looper的线程是本地线程 Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); // 开始循环 while (true) { Message msg = queue.next(); // 取出message if (msg != null) { if (msg.target == null) { // message没有target为结束信号,退出循环 return; } // 日志 if (me.mLogging!= null) me.mLogging.println( ">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what ); // 将Message分发给target-->Handler msg.target.dispatchMessage(msg); // 还是日志。。。 if (me.mLogging!= null) me.mLogging.println( "<<<<< Finished to " + msg.target + " " + msg.callback); final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf("Looper", "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } // 回收message资源 msg.recycle(); } } } }
相关文章推荐
- Android: Looper, Handler, HandlerThread. Part II
- 解决在android平台上apk的覆盖安装so文件不覆盖问题
- Android: Looper, Handler, HandlerThread. Part I
- android下拉刷新android-Ultra-Pull-To-Refresh使用
- 最近开发中的一些坑#1
- 【Android Studio简易教程】断点调试及相关技巧
- Android中Context的理解与使用技巧
- Android客户端与服务器端通过DES加密认证
- 在百度地图的基础上增加了实时定位和轨迹
- android序列化Serializable、Parcelable(一)
- Android 动态添加每条输入的内容
- Android下拉刷新SwipeRefreshLayout
- Android笔记:20150823
- Android笔记:20150824(this关键字的使用)
- Android笔记:20150820
- 【第四篇章-android平台MediaCodec】根据编码类型MIME_TYPE获取MediaCodecInfo
- Android笔记:20150408
- Android笔记:20150414
- Android客户端写Cookie和内嵌的网页实现登录状态的同步
- Android笔记:20150406