北京理工大學%20陳罡
在Symbian開發中,很多朋友都提出了gprs串連無法關斷的問題。
這種問題的主要表象是——
當我們關閉gprs串連的時候,程式就發生異常退出了。(屢試不爽)
這是為什麼呢?
我做了很多實驗 ,都一樣的效果,即使採用Nokia論壇提供的例子也是同樣的結果。
只要把socket engine一刪除,整個程式就退出了。
就拿HttpExample為例,我們看看它的解構函式是如何操作的吧:
CClientEngine::~CClientEngine() {
iSession.Close();
iSocketServ.Close() ;
delete iPostData;
iPostData = NULL;
}
我試過這個解構函式,如果直接delete掉CClientEngine引擎對象,那麼程式會毫不猶豫的
退出,而不是關掉串連。如果把iSocketServ.Close()這句注釋掉,就像下面這樣:
CClientEngine::~CClientEngine() {
iSession.Close();
// iSocketServ.Close() ; <------ 注釋掉
delete iPostData;
iPostData = NULL;
}
那麼程式的gprs串連根本不會斷開。
這可如何是好呢?我們知道symbian系統也是運行在arm處理器上的,而iSession是包含有
flash晶片上的檔案操作的。那麼會不會是由於晶片處理速度太慢或者由於關斷iSession
需要一段時間(其實也就是1~2秒鐘的時間),而這個操作恰恰是非同步行為導致的呢?
我們假設一下,如果iSession.Close()的操作是非同步,在Symbian系統還沒有把iSession關閉
之前,我們調用了iSockServ.Close(),這樣就導致了錯誤。
出於這個疑問,我開始了實驗,我先手工添加如下函數:
void CClientEngine::CloseSockSvr()
{
iSocketServ.Close() ;
if(iCurConn == EConnected) iCurConn = ENotConnected ;
}
void CClientEngine::CloseSession()
{
iSession.Close() ;
}
也就是不從解構函式中直接關閉iSession和iSocketServ,而是把這兩個關閉函數
獨立出來,變成公有函數,由CClientEngine引擎的外部來逐一關閉。
實驗證明,這樣從菜單上,先手工關閉iSession,然後等一至兩秒鐘後,再手工
關閉iSocketServ,是完全可以實現gprs串連關閉的,而且程式也不會退出。
那麼如何讓程式自動關閉gprs串連呢?
我考慮採用timer,一個使用中的物件,來完成這個任務。
標頭檔定義:
#include <e32base.h>
class CMbAppUi ;
class CCloseTimer : public CTimer
{
protected:
CMbAppUi * m_ui ;
TInt m_sec_count ;
private: // from CActive
void RunL();
void Queue() ; // inner time delay function
public:
CCloseTimer();
virtual ~CCloseTimer();
void ConstructL(CMbAppUi * pui) ;
};
下面是cpp檔案定義:
#include <coemain.h>
#include "CloseTimer.h"
#include "MbAppUi.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
const TInt KIntervalTime = 1000000 ; // 2 second
CCloseTimer::CCloseTimer():CTimer(EActivePriorityLogonA) // -------> 這裡把優先順序定成最低
{ // 保證系統只有再閒置時候才運行Timer
m_ui = NULL ;
m_sec_count = 0 ;
}
CCloseTimer::~CCloseTimer()
{
}
void CCloseTimer::RunL()
{
Queue(); // ----------> 這裡就是延時操作了
m_sec_count++ ;
if(m_sec_count == 1 ) m_ui->CloseSession() ; // ------> 這裡關閉了iSession,
else if(m_sec_count == 3) m_ui->CloseSockSvr() ; // ---->兩秒鐘後,我們關閉iSocketServ
else if(m_sec_count == 4) { // 至此,外部的gprs串連已經完全關閉了。
if(m_ui->iMsgCount) m_ui->ShowGlobalNote() ;
} else if(m_sec_count >= 5) {
Cancel() ;
if(m_ui->iMsgCount) m_ui->StopCloseTimer() ;
else m_ui->HandleCommandL(EEikCmdExit) ;
}
}
void CCloseTimer::Queue() {
After(KIntervalTime) ;
}
void CCloseTimer::ConstructL(CMbAppUi * pui)
{
CTimer::ConstructL() ;
CActiveScheduler::Add( this ) ; // ------>這句是把當前timer加入到Active Object的調度器中去
if(pui != NULL) m_ui = pui ;
Queue() ; // ------->這句必須要加,否則調度器不會有機會運行喔!
}
嗯,這個技術大概就是這個樣子了。
上述的代碼是在Symbian S60 2.1 sdk下面調試通過。在6600,6670,7610,6681等真機上測試通過。