Symbian/Android/iOS/WM程序框架对比

Symbian:

Symbian程序一般分为两类:Server程序、UI程序

  • Server程序:Server程序一般无UI,并且一般不在应用程序列表中显示启动图标,运行时在后台运行。

Server程序主要包括派生于CServer2的Server实现类及派生于CSession2的Client服务类。Server程序启动时,会创建CServer2派生类的实例,并在系统中以特定的名称注册(通过调用CServer2::Start(const TDesC& name))。Client通过Server名称与Server创建连接,并获得与Server连接的Session Handle,之后的请求都通过Session Handle完成。Server收到Client的连接请求时,会为Client建立对应的服务Session,之后在该Session中处理所有的Client请求。

典型的Server程序启动代码:

GLDEF_C TInt E32Main()
{
    CTrapCleanup* cleanup = CTrapCleanup::New();
    if (cleanup == NULL)
    {
        return KErrGeneral;
    }
    CActiveScheduler *pA = new CActiveScheduler;
    CActiveScheduler::Install(pA);
    CXXXServer *pS = CXXXServer::NewL();
    TInt err = pS->Start(KXXXServerName);
    CActiveScheduler::Start();
    delete pS;
    delete pA;
    delete cleanup;
    return KErrNone;
}

典型的CServer2派生类代码:

class CXXXServer : public CServer2
{
public:
    CXXXServer (CActive::TPriority aActiveObjectPriority);
    CSession2* NewSessionL(const TVersion& aVersion,const RMessage2& aMessage) const;
    static CXXXServer * NewL();
    static CWTPServer* NewLC();
    ~CXXXServer ();
    ……
};

CSession2* CXXXServer ::NewSessionL(const TVersion& /*aVersion*/, const RMessage2& /*aMessage*/) const
{
    CXXXServerSession* session = new (ELeave) CXXXServerSession(this);
    return session;
}

典型的CSession2派生类代码:

class CXXXServerSession: public CSession2
{
public:
    CXXXServerSession(CXXXServer* aServer);
    void ServiceL(const RMessage2& aMessage);
    CXXXServer* iServer;
    ……
};

void CXXXServerSession::ServiceL(const RMessage2& aMessage)
{
    TInt ret = KErrNone;
    switch (aMessage.Function())
    {
    case :
        ……
        break;
    ……
        break;
    default:
        break;
    }

    aMessage.Complete(ret);
}

典型的Client连接Server及请求服务代码:

class RXXXServSession : public RSessionBase
{
public:
    RXXXServSession ();
    TInt Connect();
    TVersion Version() const;
    void Close();

    TBool Stop();
};

TInt RXXXServSession ::Connect()
{
    TInt ret = CreateSession(KXXXServerName,Version(),kDefaultMessageSlots);
    if(ret == KErrNotFound)
    {
        RProcess process;
        ret = process.Create(KXXXServerPath, KNullDesC);
        if(ret != KErrNone)
        {
             return ret;
        }
        CleanupClosePushL(process);
        process.Resume();
        TInt retry = 10;
        do
        {
            User::After(1000);
            ret = CreateSession(KXXXServerName,Version(),kDefaultMessageSlots);
        }while((ret == KErrNotFound) && (retry--));
        CleanupStack::PopAndDestroy(1);
        return ret;
    }
    else
    {
        return ret;
    }
}

TBool RXXXServSession::Stop()
{
    return (SendReceive(EXXX_SERVICE_STOP) == KErrNone);
}

 

UI程序:UI程序一般会在应用程序列表中显示启动图标,用户可选择启动图标启动程序。Symbian UI程序的详细结构,请参考 跟着Code走,详解Symbian UI程序框架(1)——UI程序结构 ,此处只是简述之。

0_1282471587OlKt.gif 

Symbian UI程序的结构大体来看也是符合MVC结构的,但是我觉得它并不是严格的符合MVC结构(当然这也取决于对于MVC结构的理解,也许我对MVC结构的理解也不是那么对)。其默认的程序框架,只有Controller/View,并没有Modal部分。如果写程序的人,自己把Modal部分的代码独立出来,那么可能就比较符合MVC结构一些。

UI程序典型的框架必须代码:

LOCAL_C CApaApplication* NewApplication()
    {
    return new CXXXApplication;
    }

GLDEF_C TInt E32Main()
    {
    return EikStart::RunApplication( NewApplication );
    }

以上代码中,EikStart::RunApplication是库中的代码,该函数会完成UI程序框架的初始化(初始化工作包括创建CEikonEnv实例,CEikonEnv实例整个程序唯一,使用了单例模式,可以通过CEikonEnv::Static()访问该对象。CEikonEnv对象可以看做是整个UI程序的Engine,它派生自CActive,是一个活动对象。CEikonEnv会建立与系统各个Server的连接(包括窗口Server等),从这些系统Server获得事件,并通过AppUi类分发到对应的UI控件),并调用NewApplication创建应用程序实例类,之后会再依次调用以下两个函数创建Document类及AppUi类。普通程序并不会在Application类及Document类中写太多代码,除非程序是文档处理程序。手机程序极少会是文档处理程序,所以MVC中的Controller一般情况下,只有AppUi类的代码会被用到。(从这个角度来说,Symbian UI程序的MVC结构设计,并不是太符合手机程序开发的需要)

CApaDocument* CXXXApplication::CreateDocumentL()
    {
    return CXXXDocument::NewL(*this);
    }

CEikAppUi* CXXXDocument::CreateAppUiL()
    {
    return new (ELeave) CXXXAppUi;
    }

 

AppUi类是整个UI程序的核心,CEikonEnv对象调用它完成UI页面的切换,UI操作事件/重绘事件的分发。AppUi类派生自CAknViewAppUi,基类中完成了页面切换,事件分发的基本代码。一般来说,AppUi类只需要UI页面初始化的代码。

AppUi类的典型代码:

class CXXXAppUi : public CAknViewAppUi
    {
public:
    // constructor and destructor
    CXXXAppUi ();
    virtual ~CXXXAppUi ();
    void ConstructL();

public:
    // from CCoeAppUi
    virtual TKeyResponse HandleKeyEventL(
                const TKeyEvent& aKeyEvent,
                TEventCode aType );

    // from CEikAppUi
    void HandleCommandL( TInt aCommand );
    void HandleResourceChangeL( TInt aType );

    // from CAknAppUi
    void HandleViewDeactivation( const TVwsViewId& aViewIdToBeDeactivated, const TVwsViewId &aNewlyActivatedViewId );

private:
    CXXXView* iXXXView;
    CYYYView* iYYYView;
    };

void CXXXAppUi::ConstructL()
    {
    BaseConstructL( EAknEnableSkin );
    InitializeContainersL();
    }

void CXXXAppUi::InitializeContainersL()
    {
    iXXXView = CXXXView::NewL();
    AddViewL( iXXXView );
    SetDefaultViewL( *iXXXView );
    iYYYView = CYYYView::NewL();
    AddViewL( iYYYView );
    ……
    }

 

View类实例是程序可显示的页面,但是View类本身并不是可显示的控件或控件派生类,它只是符合系统View管理接口的实体而已。View类必须包括一个可现实的控件实例,以及其他如菜单实例。

View类典型代码:

class CXXXView : public CAknView
    {
public:
    // constructors and destructor
    CXXXView ();
    static CXXXView * NewL();
    static CXXXView * NewLC();       
    void ConstructL();
    virtual ~CXXXView ();
    // from base class CAknView
    TUid Id() const;
    void HandleCommandL( TInt aCommand );
protected:
    // from base class CAknView
    void DoActivateL(
        const TVwsViewId& aPrevViewId,
        TUid aCustomMessageId,
        const TDesC8& aCustomMessage );
    void DoDeactivate();
    void HandleStatusPaneSizeChange();
private:
    CXXXContainer* iXXXContainer;
    };

void CXXXView::DoActivateL(
        const TVwsViewId& /*aPrevViewId*/,
        TUid /*aCustomMessageId*/,
        const TDesC8& /*aCustomMessage*/ )
    {
    if ( iXXXContainer == NULL )
        {
        iXXXContainer = CreateContainerL();
        iXXXContainer ->SetMopParent( this );
        AppUi()->AddToStackL( *this, iXXXContainer );
        } 
    }

void CXXXView::DoDeactivate()
    {
    if ( iXXXContainer != NULL )
        {
        AppUi()->RemoveFromViewStack( *this, iXXXContainer );
        delete iXXXContainer ;
        iXXXContainer = NULL;
        }
    }

以上View类代码中iXXXContainer成员是真正可显示的控件(一般来说,它本身是控件,占据整个程序窗口区域。它同时是个控件容器,真正的有效UI控件会以它为父窗口,占据程序窗口的部分区域)。

 

控件Container典型代码:

class CXXXContainer : public CCoeControl
    {
……
public:
    // from base class CCoeControl
    TInt CountComponentControls() const;
    CCoeControl* ComponentControl( TInt aIndex ) const;
    TKeyResponse OfferKeyEventL(
            const TKeyEvent& aKeyEvent,
            TEventCode aType );
    void HandleResourceChange( TInt aType );
protected:
    // from base class CCoeControl
    void SizeChanged();

private:
    // from base class CCoeControl
    void Draw( const TRect& aRect ) const;

private:
    void InitializeControlsL();
    void LayoutControls();
    CCoeControl* iFocusControl;
    MEikCommandObserver* iCommandObserver;
private:
    CEikImage* iImage1;
    CEikLabel* iLabel1;
    };

void CXXXContainer ::LayoutControls()
    {
    iImage1->SetExtent( TPoint( 87, 89 ), TSize( 117, 117 ) );
    iLabel1->SetExtent( TPoint( 186, 265 ), TSize( 85, 34 ) );
    }

TKeyResponse CXXXContainer ::OfferKeyEventL(
        const TKeyEvent& aKeyEvent,
        TEventCode aType )
    {
    if ( iFocusControl != NULL
        && iFocusControl->OfferKeyEventL( aKeyEvent, aType ) == EKeyWasConsumed )
        {
        return EKeyWasConsumed;
        }
    return CCoeControl::OfferKeyEventL( aKeyEvent, aType );
    }

void CTestContainer::Draw( const TRect& aRect ) const
    {
    CWindowGc& gc = SystemGc();
    gc.Clear( aRect );
    }

从以上代码可以看出,控件容器类是派生自CCoeControl的,本身是控件。另外,还需要注意的是,UI事件(例如按键事件和绘制事件)是直接由控件处理的。AppUi类在分发事件时,不会经过View,而是直接找到对应的控件。AppUi类分发事件的详细过程,请参考 跟着Code走,详解Symbian UI程序框架(2)——程序结构进阶,窗口管理及事件分发

===================================================================

Android

对于Android下的应用,首先需要明确的是,每个Android应用其实都不能被称作真正意义上的程序,它们只是受Android系统管理的一些Component而已。系统会在与用户的交互过程中,调用并执行对应组件的代码。Android应用在运行时的状态,取决于你对各个Component的属性配置及系统运行时的状态。

Android下的Component分为Activity、Service、BroadcastReceiver及ContentProvider。Activity显示一个UI页面,Service定义一个后台运行的服务,BroadcastReceiver用以监听系统中的通知,ContentProvider用以向其他组件提供数据。你可以在工程配置文件AndroidManifest.xml中配置Component的属性,当然你也可以通过运行时的代码来改变属性(但是有些属性运行时改变,未必会生效)。例如,你可以指定Component运行时的进程名,可以指定多个Component是在同一个进程中执行,还是在各自不同的进程中执行……Android开发者网站中对各种Component的说明已经非常详细了,因为这里这简要列出几个要点。

Activity:从Activity类派生,一般在资源文件中定义包含UI元素的layout,在onCreate中调用setContentView指定layout,UI就显示出来了。如果UI中有button等可能与用户交互的UI元素,可通过findViewById获得元素,并调用setOnClickListener之类的函数设置点击处理函数。如果需要显示菜单,可以在onCreateContextMenu中创建menu,并在onContextItemSelected中根据menu ID进行处理。如果需要弹出Dialog,则首先定义一些Dialog ID,并在需要谈Dialog的地方通过调用showDialog(ID)弹出,然后在onCreateDialog(id)中创建Dialog(你可以在这里关联Dialog中UI元素对应的响应代码)。

 

Service:从Service类派生,一般在onCreate及onStart中完成初始化。初始化工作包括准备好与外部通信及Service本身相关功能(例如,如果你有长线任务需要在单独线程中处理,可能需要创建线程)。为处理外部请求,可响应onBind,onBind会返回一个符合IBinder接口的对象,Client就可以通过这个对象发送Message给Service了。Service需要实现MessageHandler来处理Client的请求。

Service典型代码:

public class XXXService extends Service {
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_WRS_CHANGE:
                ……
                break;
                ……
                        default:
                super.handleMessage(msg);
            }
        }
    }
    final Messenger mMessenger = new Messenger(new IncomingHandler());


    public void onCreate() {
        super.onCreate();
        ……
    }
    public void onStart() {
        ……
    }
    public void onDestroy() {
        super.Destroy();
        ……
    }
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
}

Client连接Service的典型代码:

public class MsgToService {
    private void send(Message msg) {
        try {
            int i = 3;
            while( mService == null){
                i--;
                Thread.sleep(300);
                if(i==1)
                    break;
            }
            if(mService != null) {
                mService.send(msg);
            }
            else {
            }
        } catch (RemoteException e) {
        } catch (InterruptedException e) {
        }
    }
    private ServiceConnection mConnection  = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = new Messenger(service);
            try {
            } catch (Exception e) {
            }
        }

        public void onServiceDisconnected(ComponentName className) {
            mService = null;
        }
    };

    public void doBindService() {        
        boolean ret = mContext.bindService(new Intent(mContext, XXXService.class), mConnection, Context.BIND_AUTO_CREATE);
        mIsBound = ret;
    }

    public void doUnbindService() {
        if (mIsBound) {
            if (mService != null) {
                try {
                    mContext.unbindService(mConnection);
                    mIsBound = false;
                } catch (Exception e) {
                }
            }
        }
    }
}

 

BroadcaseReceiver:派生自BroadcastReceiver,需要在AndroidManifest.xml中指定该Component对应的Intent-filter,即它监听系统的哪些通知,然后实现onReceive函数进行响应即可。

 

ContentProvider:派生自ContentProvider,实现insert/delete/query/update等函数处理对应的请求。ContentProvider内部可以采用文件或者数据库保存数据,insert/delete/query/update的参数包含每次请求对应的数据。

Client调用ContentProvider的典型代码:

public final static String Log_TYPE = "Type";
public static final Uri CONTENT_URI = Uri.parse("content://com.xxx.db/log");
ContentResolver cr = c.getContentResolver();
ContentValues values = new ContentValues();
values.put(Log_TYPE, type);
cr.insert(CONTENT_URI, values);

============================================================================

iOS:

Delegate模式在iOS中得到了疯狂的使用,对于程序开发人员来说,编写iOS程序就是使用XCode生成程序基本框架后,根据需要填满Delegate留下的空即可。

main函数典型代码:

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

iOS下没有Garbage Collection机制,取而代之的是AutoreleasePool。当调用对象的autorelease函数后,该对象会被记录到最邻近的AutoreleasePool,AutoreleasePool的drain被调用或者析构时,所有记录下来的对象会被真正释放。AutoreleasePool降低了内存管理的复杂度,可以做到谁分配谁释放(函数可返回在函数内部分配的对象,返回之前调用autorelease,调用者不负责内存释放)。

UIApplicationMain是iOS程序框架的启动函数。第三个参数传递派生如UIApplication的类名,一般很少有程序会派生UIApplication类,所以多数情况下直接传入nil,系统将使用默认的UIApplication类。第四个参数传递Application Delegate的类名,Application Delegate类实现了UIApplicationDelegate协议,程序框架在合适的时候(例如,程序启动、程序切换到后台,程序切换到前台,程序终止等)调用Application Delegate的函数。如果你在程序的主xib资源文件中设置了Application Delegate的连接,UIApplicationMain的第四个参数也可以传nil。

iOS程序的主要代码入口都在Application Delegate类中,并且大多数情况下只会实现程序启动和程序终止两个接口。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 
    // Override point for customization after application launch.
    ……
}

- (void)applicationWillTerminate:(UIApplication *)application {
    /*
     Called when the application is about to terminate.
     See also applicationDidEnterBackground:.
     */
    ……
}

程序基本框架有了之后,接下来就是UI显示及用户交互了。工程的主xib文件中有一个window对象,代表应用程序窗口,向其中加入其它UI元素,即完成UI元素的显示。UI元素由一系列派生于UIView的元对象成,UI元素创建时会指定其在屏幕上占据的区域,UIView中可通过调用addSubView加入子View,子元素也可以通过调用removeFromSuperView从父View中删除。

UIView的显示,Apple也是采用MVC结构,每个View一般对应一个Controller。但是框架本身并未体现出View的Modal,编写代码时,需要你自己把数据管理部分的代码分割开来,体现是MVC中的Modal。

典型的View显示代码:

@interface XXXView : UIViewController {
}

@implementation XXXView

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
}
- (void)viewDidUnload {
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}
- (void)dealloc {
    [super dealloc];
}
@end

用户事件的响应:你可以在UI资源文件xib文件中,连接UI元素(例如UIButton)的事件响应函数,也可以在代码中创建UI元素时,或者之后调用setTarget及setAction设置响应函数。

============================================================================

Windows Mobile:

Windows Mobile的程序结构跟Windows的一致,你可以采用MFC或者Win32编程。如果采用MFC编程,在对应的事件处理接口函数中填入代码即可。如果采用Win32编程,则需要自己建立消息循环的基础代码,并分别完成消息响应函数。相关的文章非常多,直接Google或者百度之。

============================================================================

Android/iOS/WM MFC编程是最方便的,基本上程序框架都比较完备,你只需要填空即可。Symbian/WM Win32编程麻烦一点,需要你完成的代码多一点。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值