我一直对Looper和loopthread 感兴趣,看到audio中也有looper的身影. 不觉得就写点什么.
首先我们看AudioService 里面的 一个looperthread的生成.
1.如何生成LooperThread
class **SoundPoolListenerThread** extends Thread {
public SoundPoolListenerThread() {
super("SoundPoolListenerThread");
}
@Override
public void run() {
// 通过下面2行代码就把一个普通的thread 转化成了looper 线程,
looperthread的特点是内部有一个Looper对象,它维护了一个消息队列MQ .
**Looper.prepare();
mSoundPoolLooper = Looper.myLooper();**
synchronized (mSoundEffectsLock) {
if (mSoundPool != null) {
mSoundPoolCallBack = new SoundPoolCallback();
mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
}
mSoundEffectsLock.notify();
}
Looper.loop(); .// 调用这个方法, Looper线程开始工作. 不断从自己的消息队列MQ中取出消息执行.
}
}
还比如AudioService 中的AudioSystemThread 就是个LooperThread, 并有自己的looper对象和Handler对象.
看下面代码.
private class extends Thread {
AudioSystemThread() {
super("AudioService");
}
@Override
public void run() {
// Set this thread up so the handler will work on it
Looper.prepare();// 创建looper对象,转化当前thread为looperthread.
synchronized(AudioService.this) {
mAudioHandler = new **AudioHandler**(); // 建立自己的Handler对象.
// Notify that the handler has been created
AudioService.this.notify();
}
// Listen for volume change requests that are set by VolumePanel
Looper.loop(); // 启动looper循环,处理MQ中的消息.
}
}
此外Looper 类还提供了下面的方法:
Looper.myLooper()得到当前线程looper对象
getThread()得到looper对象所属线程
quit()方法结束looper循环
总结几点:
1.每个线程最多只能有一个Looper对象,它是一个ThreadLocald类型.
2.Looper内部有一个消息队列,loop()方法调用后线程开始不断从队列中取出消息执行
3.Looper使一个线程变成Looper线程。
public final class Looper {} 的定义如下:
开头有段说明和例子. 一个LooperThread 内部含有一个Looper 和自己的handler.
public class handler { final MessageQueue mQueue; // 关联的MQ final Looper mLooper; // 关联的looper final Callback mCallback; // 其他属性 public Handler() { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } // 默认将关联当前线程的looper mLooper = Looper.myLooper(); // looper不能为空,即该默认的构造方法只能在looper线程中使用 if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } // 直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上 mQueue = mLooper.mQueue; mCallback = null; } // 其他方法 }
Handler提供下面的几个方法:
post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long),
sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long)和 sendMessageDelayed(Message, long)这些方法向MQ上发送消息了。
光看这些API你可能会觉得handler能发两种消息,一种是Runnable对象,一种是message对象,这是直观的理解,但其实post发出的Runnable对象最后都被封装成message对象.
借用网友的一个图片解析执行MQ里面任务的过程.
private void makeA2dpDeviceAvailable(String address) {
// enable A2DP before notifying A2DP connection to avoid unecessary processing in
// audio policy manager
VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
setBluetoothA2dpOnInt(true);
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_AVAILABLE,
address);
// Reset A2DP suspend state each time a new sink is connected
AudioSystem.setParameters("A2dpSuspended=false");
mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
address);
}
看sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
函数原型 :
private static void sendMsg(Handler handler, int msg,
int existingMsgPolicy, int arg1, int arg2, Object obj, int delay)
我们看这个sendMsg 方法第一个元素,mAudioHandler 这个就在发送message时指定了处理该message的handler. 当looper 取出这个message 执行处理的时候,就调用这个handler大哥进行合作.
到这里我们知道了,looper是个不断循环的程序,体现在它维护自己内部的MQ,还有MQ中的输入操作是Handler完成. 输出后处理的操作也会是Handler 完成.
所以来看下Audio中Handler的定义. 代码太长, 我就先截取部分看消息处理. Handler 中的handleMessage方法,
对Message的类型进行判断后分别进行处理工作.
private class AudioHandler extends Handler {
...
... 略
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SET_DEVICE_VOLUME:
setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
break;
case MSG_SET_ALL_VOLUMES:
setAllVolumes((VolumeStreamState) msg.obj);
break;
----- 略-----
目前我们基本上就讲完了整个Looper的工作原理. 再总结一下:
1.首先我们建立一个Thread的并转化成LooperThread, 这个LooperThread 内部有自己的looper ,并维护了一个消息队列MQ,它会把消息取出来,并调用消息绑定的Handler进行消息中任务的处理工作. 消息队列MQ的输入是有Handler的异步调用进行的.
// Post a persist volume msg
sendMsg(mAudioHandler,
MSG_PERSIST_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
PERSIST_DELAY);
sendMsg 在发送时调用第一个元素 mAudioHandler 进行Message的发送,Handler 会把Message发送到自己关联的MQ上面去, 以便让Looper 取出后执行.
根据我的理解,looper真是个伟大的设计,真越来越佩服谷歌工程师了. 能理解他们的思想真的很重要. 也是我们学习的一个方向, 向牛人学习,以后我们也会成为一个自以为豪的人吧.
加油吧.