AMessageの概要
17301 ワード
AMessage/ALooper/AHandlerの中で最も複雑な一環として、AMessageは私に最後に言われました.簡潔明瞭に話してほしい.
宣言
パラメータを持たない構造関数の3つのフィールドは、0 に直接すべて割り当てられます.パラメータ付きコンストラクション関数は、送信されるwhat値と送信されるhandler(処理者)を指定し、
実は、handlerのIDやhandler自身やhandlerのいるLooperを手に入れたのです.
様々なsetXXXとfindXXXの方法を理解する前に、Itemに関する2つの方法があって、私たちが見る価値があります.
この関数は2つのことをしましたは、設定されたlenをmNameLengthフィールドに与え、nameの長さを示す. は空間を割り当て、設定したnameをフィールドmNameに割り当てられたメモリ空間にコピーする.
ここで、マクロまずforループが見えますが、実はこのループで、私たちが設定したlenの長さに一致する名前(長さlen、名前nameの項目) を見つけました.は、このアイテムの下付き を返します.
この方法には
簡単です.説明します.は、設定するnameのlenを取得し、このlenとnameに基づいてItemsで設定されているかどうかを探します. がある場合は、その位置の値(stringValueまたはrefValueの場合)を削除します.そうでなければ、mNumItems配列の次の空の要素に を割り当てます.はこのitem(注意:操作したばかりの要素を指すポインタ) を返します.
まずItemsで木に対応する上nameとtypeを見たItem を探しますがあればtypeが正しいかどうかを見ます.の上のはこのitemを返して、その他の情況、すべてNULL を返します
この方法も基礎的で、簡単に言えば Itemオブジェクトにメモリが割り当てられ、typeフィールドに が割り当てられます.入力ポインタobjが空でない場合、強いポインタとなり、このポインタ(refValue) が得る.
同様に、
findXXXシリーズの方法は大同小異で、ここではただ一つを代表として選びましょうキー値ペアItemsで、nameに基づいてitemが見つかります. 見つかったら、ABuffタイプのポインタを、前にsetBufferで設定したbuffer に向けます.
は、最初に前の処理者handlerをバインドする. handlerのdeliverMessageメソッドを使用する.
は、まず、構造関数において送信されたメッセージモニタALooperをバインドする. はlooperのpostを呼び出した.このpostの方法は一節で述べたが,ここではもう述べない.
バインド上の構造関数にはALooperが入力されます. AReplyTokenを作成します(ALooperで説明しています). は、name「replyID」とこのtokenを結合してキー値ペアを形成する. すぐにこのメッセージをpostします. postというメッセージを返すと、受信者が返すメッセージ.
9.2で述べたpostAndAwaitResponseに対応する.ここではAReplayTokenとメッセージの返信を伝達メッセージに送り、返信を要求します.
前の2つの方法の洗礼を経て、ここはたぶんみんな本を一目で見ることができて、ここはreplayTokenを交換することでしょう
まとめ
宣言 #ifndef A_MESSAGE_H_
#define A_MESSAGE_H_
#include
#include
#include
#include
namespace android {
struct ABuffer;
struct AHandler;
struct AString;
class Parcel;
// ALooper
struct AReplyToken : public RefBase {
AReplyToken(const sp &looper)
: mLooper(looper),
mReplied(false) {
}
private:
friend struct AMessage;
friend struct ALooper;
wp mLooper;
sp mReply;
bool mReplied;
// Looper
sp getLooper() const {
return mLooper.promote();
}
// if reply is not set, returns false; otherwise, it retrieves the reply and returns true
bool retrieveReply(sp *reply) {
if (mReplied) {
*reply = mReply;
mReply.clear();
}
return mReplied;
}
// sets the reply for this token. returns OK or error
status_t setReply(const sp &reply);
};
struct AMessage : public RefBase {
AMessage();
AMessage(uint32_t what, const sp &handler);
// 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
// Parcel AMessage
static sp 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.
// Parcel AMessage
void writeToParcel(Parcel *parcel) const;
// whay ( )
void setWhat(uint32_t what);
uint32_t what() const;
void setTarget(const sp &handler);
void clear();
// set ( )
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 &obj);
void setBuffer(const char *name, const sp &buffer);
void setMessage(const char *name, const sp &obj);
void setRect(
const char *name,
int32_t left, int32_t top, int32_t right, int32_t bottom);
bool contains(const char *name) const;
// find ( )
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 *obj) const;
bool findBuffer(const char *name, sp *buffer) const;
bool findMessage(const char *name, sp *obj) 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;
//post
status_t post(int64_t delayUs = 0);
// Posts the message to its target and waits for a response (or error)
// before returning.
// , post
status_t postAndAwaitResponse(sp *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.
bool senderAwaitsResponse(sp *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.
status_t postReply(const sp &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 dup() const;
// 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 changesFrom(const sp &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,
};
size_t countEntries() const;
const char *getEntryNameAt(size_t index, Type *type) const;
protected:
virtual ~AMessage();
private:
friend struct ALooper; // deliver()
uint32_t mWhat;
// used only for debugging
ALooper::handler_id mTarget;
wp mHandler;
wp mLooper;
struct Rect {
int32_t mLeft, mTop, mRight, mBottom;
};
// " "
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);
};
enum {
kMaxNumItems = 64
};
Item mItems[kMaxNumItems];
size_t mNumItems;
Item *allocateItem(const char *name);
void freeItemValue(Item *item);
const Item *findItem(const char *name, Type type) const;
void setObjectInternal(
const char *name, const sp &obj, Type type);
size_t findItemIndex(const char *name, size_t len) const;
void deliver();
DISALLOW_EVIL_CONSTRUCTORS(AMessage);
};
} // namespace android
#endif // A_MESSAGE_H_
ヘッダファイルに簡単な注釈を行った後、CPPファイルの中で、いくつかの後でよく見られる重要な方法がどのように長いかを見てみましょう.
コンストラクタ
AMessage::AMessage(void)
: mWhat(0),
mTarget(0),
mNumItems(0) {
}
AMessage::AMessage(uint32_t what, const sp &handler)
: mWhat(what),
mNumItems(0) {
setTarget(handler);
}
2つの構造関数が見られる.
#ifndef A_MESSAGE_H_
#define A_MESSAGE_H_
#include
#include
#include
#include
namespace android {
struct ABuffer;
struct AHandler;
struct AString;
class Parcel;
// ALooper
struct AReplyToken : public RefBase {
AReplyToken(const sp &looper)
: mLooper(looper),
mReplied(false) {
}
private:
friend struct AMessage;
friend struct ALooper;
wp mLooper;
sp mReply;
bool mReplied;
// Looper
sp getLooper() const {
return mLooper.promote();
}
// if reply is not set, returns false; otherwise, it retrieves the reply and returns true
bool retrieveReply(sp *reply) {
if (mReplied) {
*reply = mReply;
mReply.clear();
}
return mReplied;
}
// sets the reply for this token. returns OK or error
status_t setReply(const sp &reply);
};
struct AMessage : public RefBase {
AMessage();
AMessage(uint32_t what, const sp &handler);
// 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
// Parcel AMessage
static sp 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.
// Parcel AMessage
void writeToParcel(Parcel *parcel) const;
// whay ( )
void setWhat(uint32_t what);
uint32_t what() const;
void setTarget(const sp &handler);
void clear();
// set ( )
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 &obj);
void setBuffer(const char *name, const sp &buffer);
void setMessage(const char *name, const sp &obj);
void setRect(
const char *name,
int32_t left, int32_t top, int32_t right, int32_t bottom);
bool contains(const char *name) const;
// find ( )
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 *obj) const;
bool findBuffer(const char *name, sp *buffer) const;
bool findMessage(const char *name, sp *obj) 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;
//post
status_t post(int64_t delayUs = 0);
// Posts the message to its target and waits for a response (or error)
// before returning.
// , post
status_t postAndAwaitResponse(sp *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.
bool senderAwaitsResponse(sp *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.
status_t postReply(const sp &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 dup() const;
// 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 changesFrom(const sp &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,
};
size_t countEntries() const;
const char *getEntryNameAt(size_t index, Type *type) const;
protected:
virtual ~AMessage();
private:
friend struct ALooper; // deliver()
uint32_t mWhat;
// used only for debugging
ALooper::handler_id mTarget;
wp mHandler;
wp mLooper;
struct Rect {
int32_t mLeft, mTop, mRight, mBottom;
};
// " "
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);
};
enum {
kMaxNumItems = 64
};
Item mItems[kMaxNumItems];
size_t mNumItems;
Item *allocateItem(const char *name);
void freeItemValue(Item *item);
const Item *findItem(const char *name, Type type) const;
void setObjectInternal(
const char *name, const sp &obj, Type type);
size_t findItemIndex(const char *name, size_t len) const;
void deliver();
DISALLOW_EVIL_CONSTRUCTORS(AMessage);
};
} // namespace android
#endif // A_MESSAGE_H_
AMessage::AMessage(void)
: mWhat(0),
mTarget(0),
mNumItems(0) {
}
AMessage::AMessage(uint32_t what, const sp &handler)
: mWhat(what),
mNumItems(0) {
setTarget(handler);
}
setTarget
の具体的な長さはどのようなものですか?いいですよ.見せてあげましょう.void AMessage::setTarget(const sp &handler) {
if (handler == NULL) {
mTarget = 0;
mHandler.clear();
mLooper.clear();
} else {
mTarget = handler->id();
mHandler = handler->getHandler();
mLooper = handler->getLooper();
}
}
実は、handlerのIDやhandler自身やhandlerのいるLooperを手に入れたのです.
set/findシリーズ関連メソッド
様々なsetXXXとfindXXXの方法を理解する前に、Itemに関する2つの方法があって、私たちが見る価値があります.
1. void AMessage::Item::setName(const char *name, size_t len)
// assumes item's name was uninitialized or NULL
void AMessage::Item::setName(const char *name, size_t len) {
mNameLength = len;
mName = new char[len + 1];
memcpy((void*)mName, name, len + 1);
}
この関数は2つのことをしました
2. inline size_t AMessage::findItemIndex(const char *name, size_t len) const
inline size_t AMessage::findItemIndex(const char *name, size_t len) const {
#ifdef DUMP_STATS
size_t memchecks = 0;
#endif
size_t i = 0;
for (; i < mNumItems; i++) {
if (len != mItems[i].mNameLength) {
continue;
}
#ifdef DUMP_STATS
++memchecks;
#endif
if (!memcmp(mItems[i].mName, name, len)) {
break;
}
}
#ifdef DUMP_STATS
{
Mutex::Autolock _l(gLock);
++gFindItemCalls;
gAverageNumItems += mNumItems;
gAverageNumMemChecks += memchecks;
gAverageNumChecks += i;
reportStats();
}
#endif
return i;
}
ここで、マクロ
DUMP_STATS
が開く場合を分析する.3. AMessage::Item *AMessage::allocateItem(const char *name)
AMessage::Item *AMessage::allocateItem(const char *name) {
size_t len = strlen(name);
size_t i = findItemIndex(name, len);
Item *item;
if (i < mNumItems) {
item = &mItems[i];
freeItemValue(item);
} else {
CHECK(mNumItems < kMaxNumItems);
i = mNumItems++;
item = &mItems[i];
item->setName(name, len);
}
return item;
}
この方法には
freeItemValue
が含まれています.何をしていますか.資源を解放する仕事は,単独では話さない.void AMessage::freeItemValue(Item *item) {
switch (item->mType) {
case kTypeString:
{
delete item->u.stringValue;
break;
}
case kTypeObject:
case kTypeMessage:
case kTypeBuffer:
{
if (item->u.refValue != NULL) {
item->u.refValue->decStrong(this);
}
break;
}
default:
break;
}
}
簡単です.説明します.
4. const AMessage::Item * AMessage::findItem(const char *name, Type type)
const AMessage::Item *AMessage::findItem(
const char *name, Type type) const {
size_t i = findItemIndex(name, strlen(name));
if (i < mNumItems) {
const Item *item = &mItems[i];
return item->mType == type ? item : NULL;
}
return NULL;
}
5. void AMessage::setObjectInternal(const char *name, const sp &obj, Type type)
void AMessage::setObjectInternal(
const char *name, const sp &obj, Type type) {
Item *item = allocateItem(name);
item->mType = type;
if (obj != NULL) { obj->incStrong(this); }
item->u.refValue = obj.get();
}
この方法も基礎的で、簡単に言えば
6.二つの重要なsetXXX
1) AMessage::setBuffer
void AMessage::setBuffer(const char *name, const sp &buffer) {
setObjectInternal(name, sp(buffer), kTypeBuffer);
}
setObjectInternal
が呼び出され、nameとこのbufferを指すポインタが対応した(作成されたItem(キー値ペア))2) AMessage::setMessage
void AMessage::setMessage(const char *name, const sp &obj) {
Item *item = allocateItem(name);
item->mType = kTypeMessage;
if (obj != NULL) { obj->incStrong(this); }
item->u.refValue = obj.get();
}
同様に、
setObjectInternal
が呼び出され、nameとこのAMessageを指すポインタが対応した(作成されたItem(キー値ペア))7.対応するfindXXX
findXXXシリーズの方法は大同小異で、ここではただ一つを代表として選びましょう
bool AMessage::findBuffer(const char *name, sp *buf) const {
const Item *item = findItem(name, kTypeBuffer);
if (item) {
*buf = (ABuffer *)(item->u.refValue);
return true;
}
return false;
}
8. void AMessage::deliver()
347 void AMessage::deliver() {
348 sp handler = mHandler.promote();
349 if (handler == NULL) {
350 ALOGW("failed to deliver message as target handler %d is gone.", mTarget);
351 return;
352 }
353
354 handler->deliverMessage(this);
355}
deliverMessage
の方法は、一節で見たことがありますが、MessageのonMessageReceivedに置いて処理することです.興味のある子供靴は戻って見てもいいです.ここでは説明しません.9.メッセージの送信方法
9.1 status_t AMessage::post(int64_t delayUs)
357 status_t AMessage::post(int64_t delayUs) {
358 sp looper = mLooper.promote();
359 if (looper == NULL) {
360 ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
361 return -ENOENT;
362 }
363
364 looper->post(this, delayUs);
365 return OK;
366}
9.2 AMessage::postAndAwaitResponse(sp *response)
368 status_t AMessage::postAndAwaitResponse(sp *response) {
369 sp looper = mLooper.promote();
370 if (looper == NULL) {
371 ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
372 return -ENOENT;
373 }
374
375 sp token = looper->createReplyToken();
376 if (token == NULL) {
377 ALOGE("failed to create reply token");
378 return -ENOMEM;
379 }
380 setObject("replyID", token);
381
382 looper->post(this, 0 /* delayUs */);
383 return looper->awaitResponse(token, response);
384 }
9.3 status_t AMessage::postReply(const sp &replyToken)
386 status_t AMessage::postReply(const sp &replyToken) {
387 if (replyToken == NULL) {
388 ALOGW("failed to post reply to a NULL token");
389 return -ENOENT;
390 }
391 sp looper = replyToken->getLooper();
392 if (looper == NULL) {
393 ALOGW("failed to post reply as target looper is gone.");
394 return -ENOENT;
395 }
396 return looper->postReply(replyToken, this);
397 }
9.2で述べたpostAndAwaitResponseに対応する.ここではAReplayTokenとメッセージの返信を伝達メッセージに送り、返信を要求します.
9.4
399 bool AMessage::senderAwaitsResponse(sp *replyToken) {
400 sp tmp;
401 bool found = findObject("replyID", &tmp);
402
403 if (!found) {
404 return false;
405 }
406
407 *replyToken = static_cast(tmp.get());
408 tmp.clear();
409 setObject("replyID", tmp);
410 // TODO: delete Object instead of setting it to NULL
411
412 return *replyToken != NULL;
413 }
前の2つの方法の洗礼を経て、ここはたぶんみんな本を一目で見ることができて、ここはreplayTokenを交換することでしょう