您的当前位置:首页正文

android java handler机制,自己写个C++版本Handler来理解Android的Handler机制

2024-11-11 来源:个人技术集锦

由于日常工作不需要经常写android上层应用,对Android的Handler机制一直处于模模糊糊的状态。使用Handler之后,回去写c++代码时,时刻怀念Android里面的Handler,希望有一个c++版本的Handler。为了能自己实现c++版本的Handler,今天准备去梳理一下这Android中的Handler。

理解Android中的Handler

Handler的适用场景

只要写多线程程序,必不可少要碰到线程通信的问题。其中一个办法就是在工作线程中开辟一个消息队列,别的线程往消息队列发消息,即可完成与本线程的通信。工作线程顺序的从消息队列中读取消息并逐一处理。这种模型的好处是:

消息可以缓存

工作线程中消息是顺序处理的,所以不需要加锁。

Handler适用的就是这种场景:多个线程往一个工作线程发消息,工作线程顺序挨个处理。

Android中的Handler

google设计Handler最初的原因

在安卓应用中,多个线程去处理UI的刷新,而UI操作不是线程安全的,如果要实现多线程对UI的操作,就需要在每一个要进行UI操作的地方进行加锁。

加锁操作引入的问题

锁的管理复杂,开发者容易忘记加锁,解锁,或者乱加锁造成死锁

加锁是有性能消耗的

Android选用java作为开发语言就是看中其开发效率,引入锁加大开发难度了!

因此UI操作就该由一个单一线程进行处理,在Android中,UI线程就是应用进程的第一个线程–主线程。所以每一个android应用的开发者都会被告诫:不要在主线程里搞事情阻塞UI处理。

为了简化操作,google设计了Handler机制,开发者只需要创建一个Handler,然后在别的线程利用主线程的handler发送消息即可完成与主线程的通信。

Handler, Looper, Thread ,Message之间的关系

Looper: 用来管理消息队列的,它提供一个loop()接口,不停的从消息队列中取消息来处理。

Thread: 是Looper运行的载体,一个Thread有且只有一个Looper。

Handler: 是用来往运行与Thread里的Looper的消息队列发消息用的,同时Handler里有一个消息处理函数,Thread会用Looper取出消息,然后在Thread里执行这个函数来处理消息。

Message: 消息内容的封装,里边包含消息的处理函数,用户可以在发消息的时候动态指定其执行的处理函数

Android中Handler的使用

下面以实际代码简单看下如何用Handler与主线程的通信的:

class MainActivity extends Activity {

Handler mHandler = new Handler(){

//主线程Looper收到消息后,会当没有指定具体回调函数,会回调这个函数处理消息。

//也就说下面的函数将会在主线程内执行

@Override

public void handleMessage(Message msg) {

switch(msg.what){

case 1:

break;

default:

break;

}

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

//onCreate这里是主线程中调用的,

//使用Handler重要的一点就是要明白代码在哪个线程里执行

//下面,我们在子线程里边给主线程发消息

// 方式1:

new Thread(){

@Override

public void run(){

//往主线程消息队列发消息

//这种方式最终会在主线程中执行 mHandler.handleMessage(msg)

mHandler.sendEmptyMessage(1);

}

}.start();

// 方式2:

new Thread(){

@Override

public void run(){

//我觉得这种方式才是Handler的精髓,用户在代码里随处都可以写处理UI操作

//的代码

mHandler.post(new Runnable() {

@Override

public void run() {

//这里的代码将会被在主线程中执行!真是太方便了

}

});

}

}.start();

}

}

主线程里边的Looper是自动创建的吗?

初次使用Handler,都会有一个疑问:以上的代码,没有创建Looper,Looper是自动创建的吗?

实际上,不会自动创建,只是在执行到Activity的onCreate之前,系统已经帮忙创建Looper了。

framework/base/core/java/android/app/ActivityThread.java

public static void main(String[] args) {

//这里创建main线程的Looper

Looper.prepareMainLooper();

//...

//死循环处理消息,知道为什么不能阻塞主线程了吧!

//主线程就是取消息然后以阻塞的方式一个个顺序执行

//你在主线程中搞耗时的东西,你的UI就要卡在!!!

Looper.loop();

}

Handler怎么关联上Looper的?

前面说的每一个线程里面有且仅有一个Looper,在创建Handler时,会去获取当前线程的Looper,并赋值给Handler对象。

请看Handler类的构造函数

frameworks/base/core/java/android/os/Handler.java

public Handler() {

//就是这个Looper.myLooper();

mLooper = Looper.myLooper();

//这里就是如果工作线程没有创建looper前,创建Handler会失败的原因

if (mLooper == null) {

throw new RuntimeException(

"Can't create handler inside thread that has not called Looper.prepare()");

}

}

//myLooper利用的就是linux提供的线程局部存储实现的,每个线程都有独立的一个。

public static final Looper myLooper() {

return (Looper)sThreadLocal.get();

}

还有另一个带参数的构造函数

public Handler(Looper looper) {

...

//最终执行mLooper = looper;

}

可见:Handler从创建开始就要指定其Looper, 默认构造函数就是使用当前线程的Looper。

自定义的工作线程怎么创建Looper和使用Handler?

如果我们要在自己的线程中使用Handler机制,则需要执行创建Looper对象。

创建Looper的方法很简单,就是执行Looper.prepair()即可。

class MyThread extends Thread {

private Handler myHandler = null;

private boolean mPrepaired = false;

public Handler getMyHandler(){

//没有创建Looper,并loop前,handler发消息没人去处理

if (mPrepaired)

return null;

return myHandler;

}

@Override

public void run() {

//第一步:创建当前线程对应的Looper

Looper.prepare();

//第二步:创建handler,会自己匹配到当前线程的Looper

//如果没有执行第一步,这里就会报异常

myHandler = new Handler();

mPrepaired = true;

//第三步:让Looper跑起来,开始消息的读取和消息处理

//没有执行loop操作,handler发的消息是没人处理的

Looper.loop();

}

}

HandlerThread介绍

google封装了一个HandlerThread类,进一步简化自定义线程消息处理,就不用那么麻烦的处理Looper的创建和启动了。HandlerThread的使用类似下面这样:

class MyHandler extends Handler {

//这种方式,使用的创建Handler所在线程的Looper

public MyHandler(){

}

//为了与自定义的线程关联,需要指定对应线程的looper。

public MyHandler(Looper looper){

super(looper);

}

@Override

public void handleMessage(Message msg){

}

}

HandlerThread t = new HandlerThread("mythread");

t.start();

//注意那个t.getLooper()

Handler h = new MyHandler(t.getLooper());

//注意那个t.getLooper(),其实内部是阻塞等到线程执行完Looper.prepair()才返回的

frameworks/base/core/java/android/os/HandlerThread.java

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 {

//这里等looper创建完毕

wait();

} catch (InterruptedException e) {

}

}

}

return mLooper;

}

如何实现c++版本的Handler呢?

用了Handler后,回去写c++代码,没有这种东西,但是我们基本了解Handler的实现原理了,实现一个就行。

如何确保线程里有且仅有一个消息队列?

linux的pthread库提供在线程内创建私有变量的接口:

#include

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));

int pthread_setspecific(pthread_key_t key,const void *pointer));

void *pthread_getspecific(pthread_key_t key);

如何实现android中java的handler.post(Runnable)类型的接口?

java里有匿名函数,使用很方便,其实在c++11里也支持这种写法了。//这里搞一个匿名函数,输入参数为空

handler->post([](){

});

伪代码实现

typedef void (*MessageCallback)();

class Message {

public:

int what;

int arg1;

//void* obj;

Message* obtain();

MessageCallback callback;

private:

vector mMsgPool;

};

class Handler {

public:

virtual ~Handler();

void sendMessage(Message* msg) {

mLooper->enQueue(msg);

}

void setLooper(Looper* Looper);

//可以像java,post(new Runagle())那样用

void post(MessageCallback callback);

virtual void handleMessage(Message* msg){}

private:

Looper* mLooper;

};

class Looper{

public:

static void prepair();

static void loop();

//提供一个接口用来获取当前线程的Looper

static Looper* getThreadLocalLooper();

void enQueue(Message* msg){

mMsgQ.enQueue(msg);

}

Message* deQueue(){

return mMsgQ.deQueue();

}

private:

MessageQueue mMsgQ;

};

class MessageQueue {

public:

void enQueue(Message* msg);

Message* deQueue();

};

void threadfunc(Handler* handler) {

Message* msg = Message::obtain();

handler->sendMessage(msg );

}

int main(int argc, char** argv) {

Looper::prepair();

Handler *handler = new Handler();

//开个线程来往主线程发消息

std::thread t(threadfun,handler);

t.detach();

Looper::loop();

return 0;

}

class MyThread {

public:

MyThread() {

mThread = NULL;

mPrepaired = false;

}

Looper* getLooper(){

while(!mPrepaired ){

sleep(1);

}

return Looper::getThreadLocalLooper();

}

void start() {

if (NULL == mThread) {

mThread = new thread(threadfunc, this);

}

}

private:

static void threadfunc(MyThread* t) {

Looper::prepair();

Looper::loop();

}

bool mPrepaired;

thread* mThread;

};

//非主线程测试

int main2(int argc, char** argv) {

//创建自定义线程

MyThread t;

//在线程内构造自己的Looper

t.start();

//Handler *handler = new XXXHandler();

Handler *handler = new Handler();

handler->setLooper(t.getLooper());

//主线程向自定义线程的消息队列发消息

while ( true ) {

Message* msg = Message::obtain();

t.getHandler()->sendMessage(msg);

/*也可以像java那样,直接指定消息的回调处理

t.getHandler()->post([](){

cout << "haha" << endl;

});*/

sleep(1);

}

return 0;

}

结束语

经过梳理过后,自己再实现一遍,对Handler才有更深的认识。实现个c++版本的Handler,以后用到的时候拿来用会很方便。上面是伪代码实现,具体的代码请关注我的公众号。回复"myhandler"获取完整代码。

Top