Android开发实践:自定义带消息循环(Looper)的工作线程

上一篇文章提到了Android系统的UI线程是一种带消息循环(Looper)机制的线程,同时Android也提供了封装有消息循环(Looper)的HandlerThread类,这种线程,可以绑定Handler()对象,并通过Handler的sendMessage()函数向线程发送消息,通过handleMessage()函数,处理线程接收到的消息。这么说比较抽象,那么,本文就利用基础的Java类库,实现一个带消息循环(Looper)的线程,以帮助初学者理解这样一个Looper到底是怎么工作的。

1. 首先,我们完成一个简单的线程框架。

public class LooperThread {

    private volatile boolean mIsLooperQuit = false;

    private Thread mThread;      
    
    public void start() {
        if( mThread != null ) {
            return;
        }
        mIsLooperQuit = false;
        mThread = new Thread(mLooperRunnable);
        mThread.start();
    }

    public void stop() {
        if( mThread == null ) {
            return;
        }
        mIsLooperQuit = true;
        mThread = null;
    }

    protected Runnable mLooperRunnable = new Runnable() {		

        @Override
        public void run() {
            while( !mIsLooperQuit ) {

            }
        }
    };
}

如上述代码所示,mLooperRunnable.run()循环执行线程任务,mIsLooperQuit则是线程退出循环的条件。下面,我们将添加消息的发送和处理代码。

2. 添加线程循环的消息发送和处理代码


(1) 定义消息结构体,创建消息队列


public class LooperThread {

    private Queue<Message> mMessageQueue = new LinkedList<Message>();
    
    public static class Message {
    	int what;
    }        
}

(2) 创建互斥锁和条件变量


public class LooperThread {

     private Lock mLock = new ReentrantLock();
     private Condition mCondition = mLock.newCondition();       
}

(3) 创建发送消息的函数


//发送消息,由外部其他模块调用,发送消息给线程
public void sendMessage( Message message ) {
    if( mThread == null ) {
        return;
    }
    mLock.lock();
    mMessageQueue.add(message); //添加消息到消息队列
    mCondition.signal();        //通知线程循环,有消息来了,请立即处理
    mLock.unlock();
}

(4) 创建处理消息的函数


//处理消息,由线程内部调用
public void handleMessage(Message message) {
    //这里可以通过一个Callback来回调监听者
}

(5) 在mLooperRunnable.run()循环中解析消息


protected Runnable mLooperRunnable = new Runnable() {		

    @Override
    public void run() {
        
        while( !mIsLooperQuit ) {
	    
            mLock.lock();
            Message message = null;
	    
            try {
                while( !mIsLooperQuit && mMessageQueue.isEmpty() ) {
                    mCondition.await(); //没有消息到来则休眠
                } 
                message = mMessageQueue.poll();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            finally {
                mLock.unlock();
            }
            
            handleMessage(message );
        }		            
    };
}

(6) 修改线程的Stop()函数,唤醒休眠的消息循环

public void stop() {		

    if( mThread == null ) {
        return;
    }		

    mIsLooperQuit = true;	

    mLock.lock();    
    mCondition.signal();
    mLock.unlock();
    
    mMessageQueue.clear();
    mThread = null;
}

到这里,一个基本的带有消息循环的线程类封装就完成了,相信大家应该从编写这段代码的过程中,理解了系统是如何实现消息循环的。完整的代码见博文最后的附件,有任何疑问欢迎留言或者来信[email protected]交流。

时间: 2025-01-01 21:00:44

Android开发实践:自定义带消息循环(Looper)的工作线程的相关文章

【转】Android开发实践:自定义带消息循环(Looper)的工作线程

http://ticktick.blog.51cto.com/823160/1565272 上一篇文章提到了Android系统的UI线程是一种带消息循环(Looper)机制的线程,同时Android也提供了封装有消息循环(Looper)的HandlerThread类,这种线程,可以绑定Handler()对象,并通过Handler的sendMessage()函数向线程发送消息,通过handleMessage()函数,处理线程接收到的消息.这么说比较抽象,那么,本文就利用基础的Java类库,实现一个

Android开发实践:由new Handler()说开去

最近面试一些Android开发的应聘者,除了基本的Activity生命周期等基础问题以外,我一般还会问如下两个问题: (1) Service与Thread有什么区别? (2) 在Activity里new Handler()和在自己创建的Thread中new Handler()有什么区别? 第一个问题其实是一个伪命令,因为Service是Android四大组件之一,而Thread只是Java提供的一个封装了线程管理的工具类,无论是Activity还是Service,都可以通过Thread来创建一个

Android开发实践:WIFI连接功能的封装

在上一篇文章<Android开发实践:WIFI扫描功能的封装>介绍了如何利用Andriod的API实现WIFI的扫描,本文则重点讲述一下如何连接WIFI吧,在此,也给出一个封装WIFI连接过程的类,提供简单的接口以供在各个代码工程中复用. 与WIFI扫描类似,WIFI的连接同样是一个耗时的过程,所以需要放到线程中执行,通过回调来通知调用者连接结果.该回调接口的定义如下: public interface WifiConnectListener { public void OnWifiConne

Android开发之自定义TabHost文字及背景(源代码分享)

使用TabHost 可以在一个屏幕间进行不同版面的切换,而系统自带的tabhost界面较为朴素,我们应该如何进行自定义修改优化呢 MainActivity的源代码 package com.dream.ledong; import android.app.TabActivity; import android.content.Intent; import android.graphics.Color; import android.os.Bundle; import android.view.Gr

Android开发实践:为什么要继承onMeasure()

Android开发中偶尔会用到自定义View,一般情况下,自定义View都需要继承View类的onMeasure方法,那么,为什么要继承onMeasure()函数呢?什么情况下要继承onMeasure()?系统默认的onMeasure()函数行为是怎样的 ?本文就探究探究这些问题. 首先,我们写一个自定义View,直接调用系统默认的onMeasure函数,看看会是怎样的现象: package com.titcktick.customview; import android.content.Con

Android开发实践:以“专业”的态度处理多线程

刚开始学一门编程语言的时候,我总是会有一种困惑,怎样让自己的代码看起来更"专业"?很多时候,我们可以照着教材实现一些基本的功能,比如用Socket发送/接收几个字符,写一个线程完成某个异步任务,但是在实际的项目中,往往不那么简单,比如需要设计Socket通信协议,需要处理Socket的连接异常断开,需要考虑在线程阻塞的情况下如何正常退出和释放资源等等,关于这些"实战经验",前面的文章也有所涉及,以后有空准备再开个专题跟大家分享探讨一下,今天先简单地说说怎样更&quo

Chromium on Android: Android系统上Chromium主消息循环的实现分析

摘要:刚一开始接触Chromium on Android时,就很好奇Chromium的主消息循环是怎么整合到Android应用程序中的.对于Android程序来说,一旦启动,主线程就会有一个Java层的消息循环处理用户输入事件等系统事件,而对Chromium来说,它有自己另一套消息循环的实现,这个实现有哪些特点,又将如何无缝整合到Android Java层的消息循环中去,正是本文所要讨论的话题. 原创文章系列,转载请注明原始出处为http://blog.csdn.net/hongbomin/ar

Android开发之自定义Spinner样式的效果实现(源代码实现)

android系统自带的Spinner样式是远远满足不了我们实际开发过程中对Spinner UI风格的要求,因此我们肯定需要为了切合整个应用的风格,修改我们的Spinner样式.系统给我们提供了两种常见的修改方式,一个是用XML方式静态,另一个就是Java代码动态来修改啦,我们这篇文章呢主要就是介绍如何动态修改Spinner的样式.我的实现方法呢,是自己构造一个SpinnerAdapter,继承来自ArrayAdapter,重写getDropDownView(),getView()这两个方法就好

Android开发实践:Android交叉编译工具链的使用

前面2篇文章分别介绍了Android NDK编译的命令行参数,以及如何在任意目录使用Android.mk来编译本地c/c++代码,Andriod.mk和ndk-build只不过是Android官方提供了一套封装过的Android交叉编译环境而已,其实,你可以不用它,而直接通过传统的Makefile文件来编译你的c/c++代码的,本文即介绍如何直接通过传统的Makefile文件来编译可用于Android平台的库文件. 经常搞嵌入式开发的朋友对于交叉编译环境应该并不陌生,说白了,就是一组运行在x86