概述:
ALooper 会创建一个线程,在线程处理函数中循环调用注册给自己的 AHandler 的 onMessageReceived 消息;
AHandler 当且仅当做父类使用,子类通过继承父类并实现其 onMessageReceived 虚函数的方式定义自己的消息处理逻辑,每个AHandler都必须指定一个ALooper;
AMessage 是消息的载体,AMessage必须和AHandler一起使用,如果构造AMessage的时候没有指定AHandler,那么就必须通过setTarget来手动指定一个处理本AMessage的AHandler,同时由于每个AHandler都会绑定一个ALooper,这也就变相地实现了三位一体的绑定。
换句话说,AMessage可以作为独立对象随意传递和使用,因为他已经和一个处理此AMessage的AHandler进行了绑定。不论在什么地方调用AMessage的post方法,对应的AHandler里的onMessageReceived都会收到并处理这个AMessage。
ALooper 和 AMessage 都有post方法,AMessage的post方法内部会最终调用ALooper的post方法。
一般可以认为ALooper是一个线程实例,继承AHandler的类的onMessageReceived是线程函数。ALooper和AHandler不是一定要在同一个类里,可以一个类里包含ALooper,另一个类继承AHandler并实现onMessageReceived,然后在包含ALooper的类中通过ALooper->registerHandler(AHandler*) 来注册并完成绑定关联关系。
为什么AMessage也有post方法?
有些应用场景中,可以预先创建一个AMessage,然后把指向自己的指针写入AMessage里面,最后把这个AMessage作为Notifier传递给其成员变量,这样成员变量就可以通过使用这个Notifier的post方法向上传递信息。
同时,这种方法可以指定AMessage的类型,这样的好处是上级可以给每个成员变量指定不同的AMessage类型,然后在自己的MessageReceived函数里面进行很好地分类。
Android的AMessage机制更像是一种 IOC(inter object communication) 机制,提供一种方法让对象之间互相通讯,这种通讯可以是 同步的,也可以是异步的。而函数返回的通讯方法只能是同步的。
用这种方法,可以避免函数返回方式完成 IOC 带来的逻辑复杂度。可以在任何时候和任何地点将需要通知到任何对象的运算结果通知给指定的对象,避免了一层层函数调用和一层层函数返回带来的逻辑复杂度。
AMessage:
struct AMessage : public RefBase {
AMessage();
AMessage(uint32_t what, const sp<const AHandler> &handler);
#if !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
// Construct an AMessage from a parcel.
// nestingAllowed determines how many levels AMessage can be nested inside
// AMessage. The default value here is arbitrarily set to 255.
// FromParcel() returns NULL on error, which occurs when the input parcel
// contains
// - an AMessage nested deeper than maxNestingLevel; or
// - an item whose type is not recognized by this function.
// Types currently recognized by this function are:
// Item types set/find function suffixes
// ==========================================
// int32_t Int32
// int64_t Int64
// size_t Size
// float Float
// double Double
// AString String
// AMessage Message
static sp<AMessage> FromParcel(const Parcel &parcel,
size_t maxNestingLevel = 255);
// Write this AMessage to a parcel.
// All items in the AMessage must have types that are recognized by
// FromParcel(); otherwise, TRESPASS error will occur.
void writeToParcel(Parcel *parcel) const;
#endif // !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
void setWhat(uint32_t what);
uint32_t what() const;
void setTarget(const sp<const AHandler> &handler);
// removes all items
void clear();
void setInt32(const char *name, int32_t value);
void setInt64(const char *name, int64_t value);
void setSize(const char *name, size_t value);
void setFloat(const char *name, float value);
void setDouble(const char *name, double value);
void setPointer(const char *name, void *value);
void setString(const char *name, const char *s, ssize_t len = -1);
void setString(const char *name, const AString &s);
void setObject(const char *name, const sp<RefBase> &obj);
void setBuffer(const char *name, const sp<ABuffer> &buffer);
void setMessage(const char *name, const sp<AMessage> &obj);
void setRect(
const char *name,
int32_t left, int32_t top, int32_t right, int32_t bottom);
bool contains(const char *name) const;
bool findInt32(const char *name, int32_t *value) const;
bool findInt64(const char *name, int64_t *value) const;
bool findSize(const char *name, size_t *value) const;
bool findFloat(const char *name, float *value) const;
bool findDouble(const char *name, double *value) const;
bool findPointer(const char *name, void **value) const;
bool findString(const char *name, AString *value) const;
bool findObject(const char *name, sp<RefBase> *obj) const;
bool findBuffer(const char *name, sp<ABuffer> *buffer) const;
bool findMessage(const char *name, sp<AMessage> *obj) const;
// finds signed integer types cast to int64_t
bool findAsInt64(const char *name, int64_t *value) const;
// finds any numeric type cast to a float
bool findAsFloat(const char *name, float *value) const;
bool findRect(
const char *name,
int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const;
// [brief] : post一个消息。
status_t post(int64_t delayUs = 0);
// Posts the message to its target and waits for a response (or error)
// before returning.
// [brief] : post并等待应答,亦即会阻塞等待。
status_t postAndAwaitResponse(sp<AMessage> *response);
// If this returns true, the sender of this message is synchronously
// awaiting a response and the reply token is consumed from the message
// and stored into replyID. The reply token must be used to send the response
// using "postReply" below.
// [brief] : 检查发送者是否在等待应答。
bool senderAwaitsResponse(sp<AReplyToken> *replyID);
// Posts the message as a response to a reply token. A reply token can
// only be used once. Returns OK if the response could be posted; otherwise,
// an error.
// [brief] : 对replayID对应的消息给与replay,每个消息都有一个replayid用来告诉接收者
// 自己的身份,接收者可以对replayid进行postreply来达到应答的目的。
status_t postReply(const sp<AReplyToken> &replyID);
// Performs a deep-copy of "this", contained messages are in turn "dup'ed".
// Warning: RefBase items, i.e. "objects" are _not_ copied but only have
// their refcount incremented.
sp<AMessage> dup() const;
// Adds all items from other into this.
void extend(const sp<AMessage> &other);
// Performs a shallow or deep comparison of |this| and |other| and returns
// an AMessage with the differences.
// Warning: RefBase items, i.e. "objects" are _not_ copied but only have
// their refcount incremented.
// This is true for AMessages that have no corresponding AMessage equivalent in |other|.
// (E.g. there is no such key or the type is different.) On the other hand, changes in
// the AMessage (or AMessages if deep is |false|) are returned in new objects.
sp<AMessage> changesFrom(const sp<const AMessage> &other, bool deep = false) const;
AString debugString(int32_t indent = 0) const;
enum Type {
kTypeInt32,
kTypeInt64,
kTypeSize,
kTypeFloat,
kTypeDouble,
kTypePointer,
kTypeString,
kTypeObject,
kTypeMessage,
kTypeRect,
kTypeBuffer,
};
struct Rect {
int32_t mLeft, mTop, mRight, mBottom;
};
size_t countEntries() const;
const char *getEntryNameAt(size_t index, Type *type) const;
/**
* Retrieves the item at a specific index.
*/
typedef AData<
int32_t, int64_t, size_t, float, double, Rect, AString,
void *, sp<AMessage>, sp<ABuffer>, sp<RefBase>>::Basic ItemData;
/**
* Finds an item by name. This can be used if the type is unknown.
*
* \param name name of the item
* Returns an empty item if no item is present with that name.
*/
ItemData findItem(const char *name) const;
/**
* Sets an item of arbitrary type. Does nothing if the item value is empty.
*
* \param name name of the item
* \param item value of the item
*/
void setItem(const char *name, const ItemData &item);
ItemData getEntryAt(size_t index) const;
/**
* Finds an entry by name and returns its index.
*
* \retval countEntries() if the entry is not found.
*/
size_t findEntryByName(const char *name) const;
/**
* Sets the name of an entry based on index.
*
* \param index index of the entry
* \param name (new) name of the entry
*
* \retval OK the name was set successfully
* \retval BAD_INDEX invalid index
* \retval BAD_VALUE name is invalid (null)
* \retval ALREADY_EXISTS name is already used by another entry
*/
status_t setEntryNameAt(size_t index, const char *name);
/**
* Sets the item of an entry based on index.
*
* \param index index of the entry
* \param item new item of the entry
*
* \retval OK the item was set successfully
* \retval BAD_INDEX invalid index
* \retval BAD_VALUE item is invalid (null)
* \retval BAD_TYPE type is unsupported (should not happen)
*/
status_t setEntryAt(size_t index, const ItemData &item);
/**
* Removes an entry based on index.
*
* \param index index of the entry
*
* \retval OK the entry was removed successfully
* \retval BAD_INDEX invalid index
*/
status_t removeEntryAt(size_t index);
/**
* Removes an entry based on name.
*
* \param name name of the entry
*
* \retval OK the entry was removed successfully
* \retval BAD_VALUE name is invalid (null)
* \retval BAD_INDEX name not found
*/
status_t removeEntryByName(const char *name);
protected:
virtual ~AMessage();
private:
friend struct ALooper; // deliver()
uint32_t mWhat;
// used only for debugging
ALooper::handler_id mTarget;
wp<AHandler> mHandler;
wp<ALooper> mLooper;
struct Item {
union {
int32_t int32Value;
int64_t int64Value;
size_t sizeValue;
float floatValue;
double doubleValue;
void *ptrValue;
RefBase *refValue;
AString *stringValue;
Rect rectValue;
} u;
const char *mName;
size_t mNameLength;
Type mType;
void setName(const char *name, size_t len);
Item() : mName(nullptr), mNameLength(0), mType(kTypeInt32) { }
Item(const char *name, size_t length);
};
enum {
kMaxNumItems = 256
};
std::vector<Item> mItems;
/**
* Allocates an item with the given key |name|. If the key already exists, the corresponding
* item value is freed. Otherwise a new item is added.
*
* This method currently asserts if the number of elements would exceed the max number of
* elements allowed (kMaxNumItems). This is a security precaution to avoid arbitrarily large
* AMessage structures.
*
* @todo(b/192153245) Either revisit this security precaution, or change the behavior to
* silently ignore keys added after the max number of elements are reached.
*
* @note All previously returned Item* pointers are deemed invalid after this call. (E.g. from
* allocateItem or findItem)
*
* @param name the key for the requested item.
*
* @return Item* a pointer to the item.
*/
Item *allocateItem(const char *name);
/** Frees the value for the item. */
void freeItemValue(Item *item);
/** Finds an item with given key |name| and |type|. Returns nullptr if item is not found. */
const Item *findItem(const char *name, Type type) const;
void setObjectInternal(
const char *name, const sp<RefBase> &obj, Type type);
size_t findItemIndex(const char *name, size_t len) const;
void deliver();
DISALLOW_EVIL_CONSTRUCTORS(AMessage);
};