
| January 2005 The what, why and how of a "mixin" (M-class) |
|
|
A "mixin" (or M-Class) in Symbian OS is an abstract base class with the sole purpose of defining an interface between objects. A typical example would be to provide an interface to an active object class that provides asynchronous services. We'll take a look at how the TcpEx example from the Comms and Telephony training package makes use of this.
The class CretrieveHttp (declared in the file TcpExActive.h) performs a simple HTTP Get operation. The class CTCPExAppUi (declared in the file TcpEx.h) makes use of an asynchronous service (sending an HTTP get request and retrieving the result) provided by CretrieveHttp by means of an M ("Mixin") class MRetrieveHttpCallbacks (declared in the file TcpExActive.h) which contains a number of virtual methods serving as callback functions. The definition of MretrieveHttpCallbacks looks like this: // A 'Mixin' - an abstract base class which classes that will make use of CRetrieveHttp will derive from, // basically a way of registering callback functions... class MretrieveHttpCallbacks { public: // Pure virtual implemented by classes which inherit from MretrieveHttpCallback // will use to pick up (and act on) changes of state in CretrieveHttp. virtual void StateChange(TRetrieveHttpProgress aState) = 0 ; } ; and CRetrieveHttp looks like this: // A class which can perform an HTTP: "GET" operation. class CRetrieveHttp : public Cactive { public: // Usual two-phase construction stuff... static CRetrieveHttp* NewL(MRetrieveHttpCallbacks& aCallback); static CRetrieveHttp* NewLC(MRetrieveHttpCallbacks& aCallback); ~CRetrieveHttp(); // The usual active object stuff - every Active Object _must_ implement RunL,
DoCancel, and a request method of some description void RunL() ; void DoCancel() ; void RequestL(const TDesC& aURL) ; // Access method to get at the retrieved data
TDesC &GetResponseData() ; private:
// Usual two-phase construction stuff... void ConstructL(); // Standard C++ constructor/destructor CRetrieveHttp(MRetrieveHttpCallbacks& aCallback) ; // Various bits of the URL
TBuf<KMaxServerNameLength> iServerName; // The HTTP request
TBuf8<KMaxRequestLength> iRequest ; // Response data TBuf8<KReceiveChunkSize> iResponseChunk ; TBuf<KResponseLength> iResponse ; // Sockety stuff and IP address
RSocketServ iSockServer ; RHostResolver iResolver ; RSocket iSocket ; TNameEntry iHostAddress ; TSockXfrLength iResponseChunkSizePkg ; // Sundry state and status bits TRetrieveHttpProgress iState ; // Progress callback MRetrieveHttpCallbacks& iCallbacks ; } ; Note that it contains a reference to an instance of MRetrieveHttpCallbacks as one of its members; this will be initialized from the reference to MRetrieveHttpCallbacks passed in through its NewLC(...) to its constructor like this: // // The usual Symbian OS 2-Phase construction // CRetrieveHttp* CRetrieveHttp::NewLC(MRetrieveHttpCallbacks& aCallback) { CRetrieveHttp* self = new(ELeave) CRetrieveHttp(aCallback); CleanupStack::PushL(self); self->ConstructL(); return self; } // // Standard C++ constructor // CRetrieveHttp::CRetrieveHttp(MRetrieveHttpCallbacks& aCallback) : CActive(0), iCallbacks (aCallback) // first-phase C++ constructor { iState = EIdle ; } CTCPExAppUi derives from MretrieveHttpCallbacks, implements the callback function MretrieveHttpCallbacks::StateChange(..., and has a pointer to an instance of CRetrieveHttp as a member variable. Its declaration looks like this: // // CTCPExAppUi // class CTCPExAppUi : public CEikAppUi, public MRetrieveHttpCallbacks { public: // construction/destruction void ConstructL(); ~CTCPExAppUi(); private:
// methods inherited from CeikAppUi void HandleCommandL(TInt aCommand); void DynInitMenuPaneL(TInt aMenuId, CEikMenuPane* aMenuPane); // Method inherited from MretrieveHttpCallbacks virtual void StateChange(TRetrieveHttpProgress aState) ; private: CTCPExAppView* iAppView; CRetrieveHttp* iRetriever; void StartRequest(const TDesC& aUri); }; CTCPExAppUi registers its implementation of the single callback in MRetrieveHttpCallbacks with CRetrieveHttp by passing a reference to itself when it constructs an instance of CretrieveHttp in its own second phase constructor. // The second phase constructor of the application UI class.
void CTCPExAppUi::ConstructL() { // BaseConstructL() completes the UI framework's // construction of the App UI. BaseConstructL(); iAppView = CTCPExAppView::NewL(ClientRect());
iRetriever = CRetrieveHttp::NewL(*this) ;
} CTCPExAppUi requests a service from CRetrieveHttp by calling CretrieveHttp::RequestL(...) with a pointer to a descriptor containing the URL of the web page it wishes to retrieve. void CTCPExAppUi::StartRequest(const TDesC& aUri) { iRetriever->RequestL(aUri) ; } CTCPExAppUi signals the progress of the request (and its eventual completion) to CTCPExAppUi by calling the member functions defined in MretrieveHttpCallbacks and implemented by CTCPExAppUi.
// // Mandatory RunL from CActive - This is where it all happens, basically a big switch // statement that implements a state machine that goes through all the stages of // performing the "GET" operation // void CRetrieveHttp::RunL() { TBool finished = EFalse ; switch (iState) { // Perform actions for various states } // Notify our "owner" of state change iCallbacks.StateChange(iState) ; if (finished)
DoCancel() ; Else SetActive() ; } As well as demonstrating the use of "mixins", TcpEx also illustrates the use of TCP/IP sockets, and if you look at the complete code for CRetrieveHttp::RunL(...), which we have shortened in this document for clarity, and CretrieveHttp::RequestL(...), you'll also find code illustrating
For a detailed description of this and other related topics (including the use of the Symbian OS built-in HTTP client and simple Telephony), see the "Comms and Telephony" training package in the Symbian OS Docs & Tools section>>
| |
Copyright © 2001 - 2009 Sony Ericsson Mobile Communications AB. All Rights Reserved.