Audio 和Looper的交集

我一直对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中的消息. 
        }
    }
  1. Looper的构成

此外Looper 类还提供了下面的方法:
Looper.myLooper()得到当前线程looper对象
getThread()得到looper对象所属线程
quit()方法结束looper循环

总结几点:
1.每个线程最多只能有一个Looper对象,它是一个ThreadLocald类型.

2.Looper内部有一个消息队列,loop()方法调用后线程开始不断从队列中取出消息执行

3.Looper使一个线程变成Looper线程。

public final class Looper {} 的定义如下:
开头有段说明和例子. 一个LooperThread 内部含有一个Looper 和自己的handler.

  1. Looper如何处理Message –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; } // 其他方法 }
  1. 由此可以看出,handler将关联当前线程looperthread 的 looper,并且把这个looper的MQ作为自己的MQ,
    这样在异步调用handler发送消息的时候就直接发送到自己关联的MQ上面去了.
  2. 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里面任务的过程.

Audio 和Looper的交集_第1张图片

  1. Looper 出去消息队列MQ里面的一个message,然后调取这个message 指定的Handler 进行消息处理.
  2. 举个audio的例子来说明:
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真是个伟大的设计,真越来越佩服谷歌工程师了. 能理解他们的思想真的很重要. 也是我们学习的一个方向, 向牛人学习,以后我们也会成为一个自以为豪的人吧.
加油吧.

你可能感兴趣的:(线程,audio)