Android HandlerThread与IntentService

记录一下开发中遇到的这些东西,讲解的不多,毕竟这些都是陈芝麻烂谷子的东西了,就是把源码堆在这里加了一些注释.

ThreadLocal

如果每个线程都想有自己的共享变量就得使用ThreadLocal,这个类解决了每个线程绑定自己的值,可以将这个类比喻成为全局存放数据的盒子,盒子中可以存储每个线程的私有数据.保证每个线程变量的隔离性.

Looper源码

public final class Looper {
    
    private static final String TAG = "Looper";

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class

    final MessageQueue mQueue;
    final Thread mThread;

    private Printer mLogging;
    private long mTraceTag;

    
    private long mSlowDispatchThresholdMs;

    
    private long mSlowDeliveryThresholdMs;

    //无参构造,默认调用true,表示Looper允许退出
    public static void prepare() {
        prepare(true);
    }
	//这个方法在每个线程只允许执行一次,它会创建Looper对象,将Looper对象保存到当前线程TLS。
    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));
    }

    
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

    
    public static void loop() {
    //获取Looper对象
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        //获取消息
        final MessageQueue queue = me.mQueue;

        确保此线程的标识是本地进程的标识,并标记。
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;
		//开始循环
        for (;;) {
            Message msg = queue.next(); // 可能会阻塞
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
            //用于分发消息
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "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);
            }
			//回收消息
            msg.recycleUnchecked();
        }
    }
    //返回与当前线程关联的Looper对象。 如果调用线程未与Looper关联,则返回null。
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

    //返回与当前线程关联的{@link MessageQueue}对象。 而且必须从运行中的Looper线程调用它,否则将抛出NullPointerException。
    public static @NonNull MessageQueue myQueue() {
        return myLooper().mQueue;
    }
	//这里创建了MessageQueue对象,而且获取了前正在执行的线程对象的引用。
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
	//如果当前线程是Looper线程,则返回true。
    public boolean isCurrentThread() {
        return Thread.currentThread() == mThread;
    }
    public void setMessageLogging(@Nullable Printer printer) {
        mLogging = printer;
    }

    /** {@hide} */
    public void setTraceTag(long traceTag) {
        mTraceTag = traceTag;
    }

    /**
     * Set a thresholds for slow dispatch/delivery log.
     * {@hide}
     */
    public void setSlowLogThresholdMs(long slowDispatchThresholdMs, long slowDeliveryThresholdMs) {
        mSlowDispatchThresholdMs = slowDispatchThresholdMs;
        mSlowDeliveryThresholdMs = slowDeliveryThresholdMs;
    }

    //把消息移除,直接移除所以的消息
    public void quit() {
        mQueue.quit(false);
    }

    //安全的将消息移除,只移除没有触发的所有消息,对于正在触发的消息不移除;
    public void quitSafely() {
        mQueue.quit(true);
    }

    
    public @NonNull Thread getThread() {
        return mThread;
    }

    
    public @NonNull MessageQueue getQueue() {
        return mQueue;
    }
    }

Android给出一个小例子,为什么要这样做就清楚了:

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();
        }
解读

在主线程的MessageQueue没有消息时,便阻塞在loop的 queue.next()
中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。
所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。(引用Gityuan的原话)

Handler

public class Handler {
    public interface Callback {
        public boolean handleMessage(Message msg);
    }
    public void handleMessage(Message msg) {
    }
    //分发消息
    public void dispatchMessage(Message msg) {
    //当Message存在回调方法,回调msg.callback.run()方法;
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
         //当Handler存在Callback成员变量时,回调方法handleMessage();
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //或者覆写了这个方法那就回调这个
            handleMessage(msg);
        }
    }

	//调用默认构造函数将与当前线程里面的Looper关联
    // 如果此线程没有looper,则此处理程序将无法接收消息,因此会引发异常。
	public Handler() {
        this(null, false);
    }
    //可以设置回调接口Callback
	public Handler(Callback callback) {
        this(callback, false);
    }
    //可以设置Looper
    public Handler(Looper looper) {
        this(looper, null, false);
    }
    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }
    public Handler(boolean async) {
        this(null, async);
    }
    public Handler(Callback callback, boolean async) {
    //静态警告
        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();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        //获取队列
        mQueue = mLooper.mQueue;
        //回调
        mCallback = callback;
        //设置消息的同步或异步
        mAsynchronous = async;
    }
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    //发送消息
	public final boolean sendEmptyMessage(int what) {
    return sendEmptyMessageDelayed(what, 0);
	}
	......
	//所有的消息最终都是调用这个方法
	private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    //把消息放入队列中处理
    return queue.enqueueMessage(msg, uptimeMillis);
}
}

MessageQueue很复杂这里就不说了.
但是我们要知道MessageQueue是按照Message触发时间的先后顺序排列的,队头的消息是将要最早触发的消息。当有消息需要加入消息队列时,会从队列头开始遍历,直到找到消息应该插入的合适位置,以保证所有消息的时间顺序。(引用Gityuan的原话)

MessageQueue的主要方法 next();enqueueMessage(); 处理了消息的取出与加入


系统使用Handler实例

HandlerThread

// 创建HandlerThread线程包含Looper
HandlerThread handlerThread = new HandlerThread("gityuan.com");
handlerThread.start();
// 创建Handler
Handler handler = new Handler(handlerThread.getLooper());
// 发送消息
handler.post(new Runnable() {
        @Override
        public void run() {
            System.out.println("to do something");
    });

//源码//
    public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        //默认进程等级
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
  
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
 
    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
    	//tid
        mTid = Process.myTid();
        //new 一个Looper
        Looper.prepare();
        synchronized (this) {
        //获取Looper
            mLooper = Looper.myLooper();
            //唤醒等待的全部线程
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        //循环之前做点什么,空方法,可以覆写
        onLooperPrepared();
        //循环
        Looper.loop();
        mTid = -1;
    }
    
 	//获取Looper
    public Looper getLooper() {
    //线程没有启动,返回null
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.等待Looper不为null
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

 
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    public int getThreadId() {
        return mTid;
    }
}

这样就可以实现线程间的通信了.

IntentService

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;
	//消息回调
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
        	//调用onHandleIntent
            onHandleIntent((Intent)msg.obj);
            //最终调用mActivityManager.stopServiceToken
            stopSelf(msg.arg1);
        }
    }

    /**
     * 创建一个IntentService。 由子类的构造函数调用。
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }

    /**
     * 重新传递intent参数选项
     */
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //创建HandlerThread
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
		//获取Looper
        mServiceLooper = thread.getLooper();
        //创建Handler
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
    //处理收到的intent任务
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

   /**
    *您不应该为IntentService重写此方法。我们需要重写的onHandleIntent,这个方法是系统在IntentService收到启动请求时调用。
    */
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
    //移除任务
        mServiceLooper.quit();
    }

    
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }
	//工作线程,耗时操作在这里面执行,一次只能处理一个Intent,处理完所有请求后,IntentService会自行停止.
	//所以最好不要调用stopService,即使你调用了服务停止了.任务也会继续执行完.
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}
  • START_NOT_STICKY
    如果onStartCommand() 执行完毕后,系统意外关闭服务,系统不会重启服务。

  • START_STICKY
    如果onStartCommand() 执行完毕后,系统意外关闭服务,会重新创建服务并调用onStartCommand() 方法,但是不会重新发送intent,而是给onStartCommand() 一个null的intent。

  • START_REDELIVER_INTENT
    如果onStartCommand() 执行完毕后,系统意外关闭服务,会重新创建服务并调用onStartCommand() 方法,但是不会重新发送intent,而是给onStartCommand() 一个最后发送的intent。

最后通过源码我们发现IntentService不可以直接和UI做交互,工作任务队列是顺序执行的,如果一个任务正在IntentService中执行,此时你再发送一个新的任务请求,这个新的任务会一直等待直到前面一个任务执行完毕才开始执行,而且正在执行的任务无法打断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值