1.概览
Looper更像是一个循环体,它需要附着到进/线程上,否者它是无法工作的。以Looper的命名也是非常的准确的。可以想象,用户将请求发送给Looper中,Looper孜孜不倦的处理用户发送而来的请求并给予返回。本章要讲解的Looper支持如下几种请求投递方式。
a)往被监的 file description中写入数据,触发Looper调用其对应的处理回调方法。例如配合socket pair实现端写如数据,另一端则处理数据,如果配合Android中binder传递fd的特性,则可以实现跨进程方式的数据传送了。
b)直接投递 Message ,对于 Message 的处理是支持延迟处理和立即处理的两种方式的,实际上前者是对后者的封装。
2. Looper的创建
main
//code 1
sp<Looper> myLooper = Looper::prepare(...);
//code 2
std::thread msgHandler( [looper = myLooper, &msgHandler]{
//code 2.1
Looper::setForThread(looper);
for (;;) {
//code 2.2
int pollResult = looper->pollAll(-1 /* timeout */);
}
});
本章旨在如何使用Looper,所以原理性的解释见下一章。下面给出简单的代码意图说明
code 1 用于获取一个Looper的实例,并且这个实例在每一个线程中智汇存在一个的。显然这里获取的Looper实例时来自于主线程的。
code 2 & code 2.1 将主线程中的Looper实例传入线程 msgHandler,让线程去执行来自主线程Looper中的循环体。所以后续的回调方法都是在线程 msgHandler 中处理的。
code 2.2 线程 msgHandler 则不断的轮询 被Looper所监听的fd,以期待处client发送而来的的事件。
3. fd(file descriptor) 方式的监听
3.1 BitTube
为了方便的使用Looper监听fd的功能,直接用 sensor lib 中提供的BitTube类。BitTube 内部封装了 socket pair,因此它的接收端和发送端分别对应一个fd。下面是对应的路径
//frameworks/native/libs/sensor/Android.bp
cc_library_shared {
name: "libsensor",
srcs: [
"BitTube.cpp",
...
],
export_include_dirs: ["include"],
}
下面是对应BitTube的类图,其中包含了内部的接口定义
下面是public接口的简单说明
initCheck
check state after construction.返回NO_ERROR代表初始化成功,否则不可用。
getFd
get receive file-descriptor.
getSendFd
get the send file-descriptor.
sendObjects
send objects (sized blobs). All objects are guaranteed to be written or the call fails.
recvObjects
receive objects (sized blobs). If the receiving buffer isn’t large enough,excess messages are silently discarded.
writeToParcel
parcels this BitTube.
3.2 监听BitTube接收端fd
main
...
sp<BitTube> myBitTube = new BitTube();
ret = myLooper->addFd(myBitTube->getFd(), 0x5/*indent*/,
android::Looper::EVENT_INPUT,
new FlagstaffLooperCallback(),
myBitTube.get());
addFd接口可以将给定的fd和对应fd数据产生时的callback注册到Looper中去,如此才能监听给定fd的状态,并调用对应的处理回调方法。
myBitTube->getFd()
就是BitTube的接收端口,在对其发送侧得fd写入数据后,通过读取接收端fd也能读到对应的数据。
0x5
不用关注,可以忽略。
EVENT_INPUT
The file descriptor is available for read operations.
FlagstaffLooperCallback
FlagstaffLooperCallback类继承自LooperCallback,在myBitTube->getFd()有事件EVENT_INPUT监听到的时候,其内部的接口handleEvent则会被回调,其中返回值含义见注释。
class FlagstaffLooperCallback : public android::LooperCallback{
public:
int handleEvent(int fd, int events, void* data) override {
...
/* Implementations should return 1 to continue receiving callbacks, or 0
* to have this file descriptor and callback unregistered from the looper.
*/
return 1;
}
};
myBitTube.get()
传入BitTube本身的指针,用于调用其内部接口对数据进行读取。
3.3 通过BitTube事件投递及处理
main
while(true){
BitTube::sendObjects<MyData>(myBitTube, new MyData(count), 1);
sleep(1);
}
通过接口sendObjects可以投递任意类型的数据,此处的 MyData 就是自定义的,类型如下
struct MyData{
int mCount;
MyData():mCount(0){}
MyData(int count):mCount(count){}
};
count在每次循环后则会自增1,所以可以根据count来区分不同的MyData。
3.3 BitTube 接收端的事件处理
对于此处 BitTube 实例的接收端fd,在3.3中事件投递过来后,BitTube.getFd对应的处理回调类会被回调,其实现如下
class FlagstaffLooperCallback : public android::LooperCallback{
public:
int handleEvent(int fd, int events, void* data) override {
//code 1
sp<BitTube> bitTube = reinterpret_cast<BitTube*>(data);
struct MyData myData;
//code 2
BitTube::recvObjects<MyData>(bitTube, &myData, 1);
LOG(INFO)<<__func__<<":[myData.mCount]"<<myData.mCount<<"[events]"<<events<<"[fd]"<<fd;
return 1;
}
};
处理也很简单,流程如下
code 1
此处的data就是在调用addFd时传入的myBitTube.get(),
main
sp<BitTube> myBitTube = new BitTube();
myBitTube.get()
code 2
接收一个由发送端发送而来的MyData实例,并打印
3.4 执行结果如下
board:/ # logcat -s FlagstaffLooperTest&
board:/ # flagstaffLooperTest
07-04 18:06:42.059 7415 7415 I FlagstaffLooperTest: main:start msgHandler thread...
07-04 18:06:42.064 7415 7416 I FlagstaffLooperTest: handleEvent:[myData.mCount]1[events]1[fd]7
07-04 18:06:43.065 7415 7416 I FlagstaffLooperTest: handleEvent:[myData.mCount]2[events]1[fd]7
07-04 18:06:44.066 7415 7416 I FlagstaffLooperTest: handleEvent:[myData.mCount]3[events]1[fd]7
4. 投递 Message
Message一般用来投递消息,而不类似上面通过BitTube可以投递任何类型的数据了。因为Message中只有一例 int 类型的what变量。其定义如下
//system\core\libutils\include\utils\Looper.h
/**
* A message that can be posted to a Looper.
*/
struct Message {
Message() : what(0) { }
Message(int w) : what(w) { }
/* The message type. (interpretation is left up to the handler) */
int what;
};
不过使用Message来投递则更简单,在投递的时候只要提供Message和其处理方法即可。
main
while(true){
myLooper->sendMessage(new FlagstaffMessageHandler(), android::Message(++count));
sleep(1);
}
对于通过sendMessage投递的消息处理接口则需要实现类MessageHandler中的handleMessage方法。下面则是 FlagstaffMessageHandler 类的实现
class FlagstaffMessageHandler:public android::MessageHandler{
public:
void handleMessage(const Message& message) override {
LOG(INFO) <<__func__<<":[message.what]"<<message.what;
}
};
实现非常的简单,仅仅只是打印what值。
4.1 执行结果
board:/ # logcat -s FlagstaffLooperTest&
board:/ # flagstaffLooperTest
07-04 18:06:42.059 7415 7415 I FlagstaffLooperTest: main:start msgHandler thread...
07-04 18:06:42.063 7415 7416 I FlagstaffLooperTest: handleMessage:[message.what]1
07-04 18:06:43.064 7415 7416 I FlagstaffLooperTest: handleMessage:[message.what]2
07-04 18:06:44.066 7415 7416 I FlagstaffLooperTest: handleMessage:[message.what]3
07-04 18:06:45.067 7415 7416 I FlagstaffLooperTest: handleMessage:[message.what]4
07-04 18:06:46.069 7415 7416 I FlagstaffLooperTest: handleMessage:[message.what]5
07-04 18:06:47.070 7415 7416 I FlagstaffLooperTest: handleMessage:[message.what]6
07-04 18:06:48.071 7415 7416 I FlagstaffLooperTest: handleMessage:[message.what]7
07-04 18:06:49.072 7415 7416 I FlagstaffLooperTest: handleMessage:[message.what]8
07-04 18:06:50.073 7415 7416 I FlagstaffLooperTest: handleMessage:[message.what]9
4.2 延迟消息推送
延迟消息推送则是支持两种模式的
a)定延迟事件(sendMessageDelayed)
b)定延迟到的时间点(sendMessageAtTime)
/**
* Enqueues a message to be processed by the specified handler after all pending messages
* after the specified delay.
*
* The time delay is specified in uptime nanoseconds.
* The handler must not be null.
* This method can be called on any thread.
*/
void sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
const Message& message);
/**
* Enqueues a message to be processed by the specified handler after all pending messages
* at the specified time.
*
* The time is specified in uptime nanoseconds.
* The handler must not be null.
* This method can be called on any thread.
*/
void sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
const Message& message);
使用上和 sendMessage 大同小异,则不再赘述。