Constructing the view controller in the view architecture

Each view controller acts like a small UI controller.

The call on the first phase constructor of the view controller occurs in the UI controller.

The methods you need to implement in your CAknView-derived class are as follows:

  • C++ default constructor, which cannot contain any code that might leave. A common implementation is:

    CMyViewAppView::CMyViewAppView()
        {
        }

    The class declaration for this constructor in the class header file needs to be public to support the construction method required.

  • two-phase constructor, a common implementation is:

    CMyViewAppView* CMyViewAppView::NewL( const TRect& aRect )
        {
        CMyViewAppView* self = CMyViewAppView::NewLC( aRect );
        CleanupStack::Pop( self );
        return self;
        }
    
    CMyViewAppView* CMyViewAppView::NewLC( const TRect& aRect )
        {
        CMyViewAppView* self = new ( ELeave ) CMyViewAppView;
        CleanupStack::PushL( self );
        self->ConstructL( aRect );
        return self;
        }
    

    The declarations for CMyViewAppView::NewL() and CMyViewAppView::NewLC() in the class header file needs to be public to support the construction method required.

    In this approach, CMyViewAppView::NewL() is called from the UI controller. It creates a view object by calling CMyViewAppView::NewLC(). CMyViewAppView::NewLC() calls new (ELeave) on the C++ default constructor CMyViewAppView to create the object (and leave if it cannot), pushes a pointer to the clean-up stack in case the second phase construction method leaves, and then calls the second phase construction method of the object. When it returns to CMyViewAppView::NewL(), the pointer pushed to the cleanup stack is removed.

  • Symbian 2nd phase constructor with code that might leave. A common implementation is:

    void CMyViewAppView::ConstructL()
        {
        // construct r_name32 resources
        BaseConstructL(r_name32 );
        }
    

    CMyViewAppView::ConstructL() is a public class providing the second phase construction that accepts the rectangle the view is drawn to.

    CAknView::BaseConstructL() initializes this view with standard values. It accepts the symbolic ID name of a resource from the resource file.

  • a method for returning the UID for the view. A common implementation is:

    TUid CMyViewAppView::Id() const
        {
        return KViewId;
        }
    
    

    CMyViewAppView::Id() is the override of CAknView::ID() to return the UID of the view

    KViewId is defined somewhere in a header file, and is unique to this application

Scalability

If you wish to support scalability in your application, then you need to implement CEikAppUi::HandleResourceChangeL() in the UI controller, and then a HandleClientRectChange method in the view controller.

A common implementation is as follows:

void CMyViewAppView::HandleClientRectChange()
    {
    if ( iContainer )
        {
        iContainer->SetRect( ClientRect() );
        }
    }

, where

CMyViewAppView::HandleClientRectChange() calls CCoeControl::SetRect(aRect) to set the window size according to the requirements of the mobile device.

Activating and deactivating views

In order for a view to be displayed, it needs to be activated by CAknView::DoActivateL(). The override of this method in the view controller must create a CCoeControl-derived view to display visual content to mobile device users. The DoActivateL() call must be prepared to handle the case where it is called while the view is already active.

If the view is not published for external use, or does not handle message parameters, a simple check and return if the view is already active is sufficient.

A common implementation is as follows:

void CMyViewAppView::DoActivateL(
   const TVwsViewId& /*aPrevViewId*/,TUid /*aCustomMessageId*/,
   const TDesC8& /*aCustomMessage*/)
    {
    if (!iContainer)
        {
        iContainer = new (ELeave) CMyViewAppContainer;
        iContainer->SetMopParent(this);
        iContainer->ConstructL( ClientRect() );
        AppUi()->AddToStackL( *this, iContainer );
        } 

    // Message handling would take place here.
   }

, where

  • CMyViewAppView::DoActivateL() is the override for CAknView::DoActivateL() for the application.

  • if (!iContainer) checks to see if the view already exists.

  • iContainer = new (ELeave) CMyViewAppContainer; calls the first phase constructor of the CCoeControl-derived class that provides the view.

  • iContainer->SetMopParent(this); sets the context for the view being created. In this case, it assigns the CCoeControl-derived view to the view controller.

  • iContainer->ConstructL( ClientRect() ) calls the second phase constructor of the CCoeControl-derived class that provides the view.

  • AppUi()->AddToStackL( *this, iContainer ); adds the CCoeControl-derived view to the control stack for key event handling.

The view architecture supports an automatic recovery mechanism if CAknView::DoActivateL() leaves. The Symbian platform calls CAknView::DoDeactivate() in the view that has left, reinstates the previous view of the application, and returns to the view that was just displayed. If the application had no previous view, it exits. If the application’s previous view was the same as the activating view (that is, the view is reactivated with a new message), the application attempts to recover to the default view.

In most cases, this mechanism removes the need to put any recovery mechanism in the DoActivateL() methods. The one situation where you may consider something more complex is when the view can be reactivated (that is, activated with a new message while already active). In this case, the view may attempt a more complex strategy to preserve the existing state if a leave happens during the attempt to handle the new message.

To destroy the CCoeControl-derived control in a view control, you must override CAknView::DoDeactivate(). It is called when the application exits, or another view has been activated and the previous active window needs to be shut down. This order makes view switching fast. In DoDeactivate the view is removed from the stack and therefore the view’s container and its controls are destroyed. This function must not leave.

A common implementation is as follows:

void CMyViewAppView::DoDeactivate()
    {
    if ( iContainer )
        {
        AppUi()->RemoveFromViewStack( *this, iContainer );
        }
    
    delete iContainer;
    iContainer = NULL;
    }

, where

  • CMyViewAppView::DoDeactivateL() is the override for CAknView::DoDeactivateL() for the application.

  • if (!iContainer) checks to see if the view already exists.

  • AppUi()->RemoveFromViewStack( *this, iContainer ); removes the CCoeControl-derived view from the control stack.

  • delete iContainer; deletes the CCoeControl-derived view.