收藏
这一节讲讲活动对象的extension 用例 CAyncCallBack。
怎么使用:
一般作为成员变量。
Class A
{
private:
CAsyncCallBack* iCall;
}
找一个初始话的地方把它先构造出来。
A::PreLayoutDynInitL()
{
iCall = new (ELeave) CAsyncCallBack(
TCallBack( LaunchDlgCallback, this ),
CActive::EPriorityStandard );
}
因为CAsyncCallBack是派生于CAtive的, 这句话就是相当于Active的构造,只不过要传递一个TCallBack对象进去,看看他的构造函数
inline TCallBack(TInt (*aFunction)(TAny* aPtr),TAny* aPtr); 一目了然, 一个函数地址,一个对象地址全传给TCallBack对象了。
有读者就问,那是没时候激活活动对象啊,也就是说你在哪setactive的啊?
继续看怎么用。 。。
A::HandleCommandL ()
{
if (!iCall->IsActive())
{
iCall->Call();
}
}
在此说明一点, 上面的例子是AsyncCallBack的典型使用案例,因为在Gui的事件处理函数 比如像handleWsEventL 或者offereyEvent
或者handleCommand这些函数都是运行在CCoeEnv这个活动对象RunL里面的,为了不阻塞该Runl所以才要把一些需要等待的操作用AsyncCallBack的方式移出到别的RunL中执行,这个例子就是如此, 我们需要用AsyncCallBack去开启一个模态对话框,而这个对话框必要在事件响应函数HandleCommandL里面开启。根据活动对象的原理iCall->Call(); 并不阻塞元函数的例程。
好, 再往下看。
iCall->Call(); 就相当于Active的 SetActive()了,但是特殊之处是 因为这个AsyncCallBack是继承于 CAsyncOneShot的,所以他的call里面实际有自激活的过程iThread.RequestComplete(pS,0); KErrNone = 0,即给当前线程信号量并且激活active。这样的话在ccoeenv的runl运行完,就可以近 AsyncCallBack的runL了。
RunL()
{
调用TCallBack的handler function.
}
因为之前的handler的地址在构造的时候都已经传入,所以很简单在调回去。
这里补充只是, 回调用static的函数获得全局地址,还有void指针的概念如下:
void(类型)指针,是一种特殊的指针,它足够灵巧的指向任何数据类型的地址空间。当然它也具有一定的局限:
在我们要取得指针所指地址空间的数据的时候使用的是 ‘*’操作符,程序员必须清楚了解到对于void指针不能使用这种方式来取得指针所指的内容。因为直接取内容是不允许的。而必须把void指针转换成其他任何valid数据类型的指针,比如char,int,float等类型的指针,之后才能使用'*'取出指针的内容。这就是所谓的类型转换的概念。
最后在A里面做地址转换:
TInt A::LaunchDlgCallback( TAny* aDlg )
{
A* dlg =
static_cast<CWVSettingsUIServerListDialog*>( aDlg );
TRAP_IGNORE( dlg->DoLaunchCorrectDialogL() ); //模态对话框 会wait住当前线程。
return EFalse;
}
在这里说一下为什么要用static的函数,因为callback使用系统,那么如果用类成员函数的话,会隐藏this指针在里面,调用还得this->B()这样的话系统怎么知道this,所以要用static全局地址。这样不会通过this,而且用static还能保证干净的全局地址空间,作用域就是当前编译单元。然后callback你没有this指针的话又不行,因为你最终还要用成员函数,所以TCallBack要求你在用一个this指针作为参数传递过去,这样系统既知道你的函数地址还知道你的对象地址,其实他是把你转过来的对象地址扔到你的callback函数里,这样你回调函数里一地址转换不久可以的到this了么。
所以这里的handler函数的封装模型就是 B(TAny*) ; TCallBack(B, TAny*);
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/weiehome/archive/2009/08/17/4455246.aspx