Saturday, October 24, 2009

Observer Pattern in MFC

As I walk through the different design concepts of the Design Pattern book by GoF, I usually try to find from my past experience about any practical implementation of these patterns. This way I found out one practical implementation of the Observer Pattern in microsoft foundation class (MFC) library which I would like to share with you.

Before explaining the application of Observer Pattern in MFC, let me give you a brief introduction of this pattern. Observer pattern helps you in notifying and updating all the dependent objects, if one object changes state. This pattern has two main objects – Subject and Observer. Multiple number of observers can be attached to a particular Subject. All the observers are notified and in turn gotten updated if the Subject changes its state. This is also known as the publish-subscribe. The subject is the publisher of changes, and the Observers are the subscribers to those changes.

The class diagram will look like the following.



And the sequence diagram of this pattern is like this.



What these two diagrams essentially depict is that in the Observer Pattern, we have a Subject, which can attach one or more Observers through its Attach() function. Whenever it changes its state it Notifies all the attached Observers through its Notify function. The observers in turn synchronize their states with that of the Subject through the GetSubjectState function.

Now let me dissect the MFC's Document-View architecture and explain how the Observer Pattern has been implemented there. In MFC, the Document acts as the Subject and the views attached to it act as the observers. The Document (Subject) has to notify and update the views (observers) whenever it changes its state. This is done through the function UpdateAllViews () of the CDocument class.

Let me show you the actual code of the UpdateAllViews from doccore.cpp under the MFC folder.

void
CDocument :: UpdateAllViews(CView* pSender, LPARAM lHint, CObject* pHint)
{
ASSERT(pSender == NULL || !m_viewList.IsEmpty());

POSITION pos = GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = GetNextView(pos);
ASSERT_VALID(pView);
if (pView != pSender)
pView->OnUpdate(pSender, lHint, pHint);
}
}


As you can see from the code that UpdateAllViews function actually traverses through all the views attached through it and call the view's OnUpdate function. Hence UpdateAllViews acts as the Notify function of the Observer pattern.

Let me show you the actual code of OnUpdate from viewcore.cpp. It goes like this:

void
CView :: OnUpdate(CView* pSender,LPARAM, CObject*)
{
ASSERT(pSender != this);
UNUSED(pSender);
Invalidate(TRUE);
}

As its is clear from the above code, that the OnUpdate function will actually invalidate the view area, which will force the views to redraw themselves synchronizing their states with the current state of the Document.

This is all about the notification from Document to View. But what about the Attach and Detach function of the Subject. We have similar functions in the Document class which are as follows:

void CDocument :: AddView(CView* pView)
{
ASSERT_VALID(pView);
ASSERT(pView->m_pDocument == NULL);
ASSERT(m_viewList.Find(pView, NULL) == NULL);
m_viewList.AddTail(pView);
ASSERT(pView->m_pDocument == NULL);
pView->m_pDocument = this;

OnChangedViewList();
}

void CDocument :: RemoveView(CView* pView)
{
ASSERT_VALID(pView);
ASSERT(pView->m_pDocument == this);

m_viewList.RemoveAt(m_viewList.Find(pView));
pView->m_pDocument = NULL;

OnChangedViewList();
}

As this is clear from the above listings that CDocument :: AddView is similar to the Attach function of the Subject, and RemoveView is like the Detach function as in the Observer Pattern.

Similar to the Observer Pattern, the Document has a list of its attached views through its m_viewList member and each view has a reference to its document through its m_pDocument member.

From the above discussion, it has become clear that the MFC's Document- View architecture is one of the applications of the Observer Pattern.

Saturday, October 10, 2009

WiFi Subsystem in Android

As i was trying to understand the WiFi subsystem of Android i came out with a diagram to depict the flow of events between different functional blocks of it. I would like to share it with you.

It goes like this:



Hope it will help the Android developers' community.

Thursday, October 8, 2009

Tabs in Android - through an example

As i was trying to experiment with the different widgets of Android, i developed this example to show how Tab works in Android.

And the application looks like the following:



And the next tab looks like:



The first thing we need to to do is working on the XML layout.

The XML code of the layout my example is as follows:

(?xml version="1.0" encoding="utf-8"?)
(LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
)

(TabHost android:id="@+id/TabHost01" android:layout_width="wrap_content" android:layout_height="wrap_content")
(TabWidget android:id="@android:id/tabs" android:layout_width="wrap_content" android:layout_height="wrap_content" /)
(FrameLayout android:id="@android:id/tabcontent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="65px")
(AnalogClock android:id="@+id/AnalogClock01" android:layout_width="wrap_content" android:layout_height="wrap_content")(/AnalogClock)
(DigitalClock android:text="DigitalClock01" android:id="@+id/DigitalClock01" android:layout_width="wrap_content" android:layout_height="wrap_content")(/DigitalClock)
(/FrameLayout)
(/TabHost)
(/LinearLayout)

And the Java code for this example is as follws:

import android.app.Activity;
import android.os.Bundle;
import android.widget.TabHost;

public class tabexample extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

TabHost tabs = (TabHost)findViewById(R.id.TabHost01);

tabs.setup();

TabHost.TabSpec spec1 = tabs.newTabSpec("tag1");

spec1.setContent(R.id.AnalogClock01);
spec1.setIndicator("Analog Clock");

tabs.addTab(spec1);

TabHost.TabSpec spec2 = tabs.newTabSpec("tag2");
spec2.setContent(R.id.DigitalClock01);
spec2.setIndicator("Digital Clock");

tabs.addTab(spec2);
}
}

Hope this helps the newcomers of Android...

Saturday, August 15, 2009

Inter Process Communication in Android through Intent

In Android, one of the nice ways for passing data between different processes is through the help of Intent. In the following example i have tried to explain it by two different applications. One application is called the IntentSupplier. This is started from another application called IntentExample. The application IntentSupplier passes some string data to the IntentExample app through the help of an Intent object which the IntentSupplier application displays in a message box.

The IntentSupplier application looks like the following.




When we click one of the buttons it passes its string data to the IntentExample which looks like the following.



The source code for IntentSupplier is as follows:

package android.training.intentsupplier;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class IntentSupplier extends Activity {


/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Button button1 = (Button)findViewById(R.id.Button01);

Button button2 = (Button)findViewById(R.id.Button02);

button1.setOnClickListener(onClickButton1);
button2.setOnClickListener(onClickButton2);

}

private OnClickListener onClickButton1 = new OnClickListener() {

public void onClick(View v){

if (v.getId() == R.id.Button01){

returnResult("Message1 coming from IntentSupplier");
}
}
};

private OnClickListener onClickButton2 = new OnClickListener() {

public void onClick(View v){

if (v.getId() == R.id.Button02){

returnResult("Message2 coming from IntentSupplier");
}
}
};

void returnResult(String msg) {

Intent i = new Intent();

i.putExtra("android.training.intentsupplier.resultfromintentsupplier", msg);

setResult(RESULT_OK, i);

finish();
}

}


Look at the function

void returnResult(String msg).

Here at the line i.putExtra("android.training.intentsupplier.resultfromintentsupplier", msg), we are basically parceling the data (msg) and giving it a label called resultfromintentsupplier. Please see how the package info is prefixed with this label.

The source code for the IntentExample is as follows:

package android.training.intentexample;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

public class IntentExample extends Activity {

static final int REQUEST_CODE = 1001;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

Intent getMessageFromIntentSupplier = new Intent();

getMessageFromIntentSupplier.setClassName("android.training.intentsupplier", "android.training.intentsupplier.IntentSupplier");

getMessageFromIntentSupplier.setAction("android.training.intentsupplier.android.intent.action.INTENTSUPPLIERTEST");

getMessageFromIntentSupplier.addCategory("CATEGORY_DEFAULT");

getMessageFromIntentSupplier.setType("vnd.example.greeting/vnd.example.greeting-text");

try {
startActivityForResult(getMessageFromIntentSupplier,REQUEST_CODE);

}

catch(ActivityNotFoundException e) {
Log.e("IntentExample", "Activity could not be started...");
}

}
}

public void onActivityResult(int requestcode, int resultcode, Intent result ) {

if(requestcode == REQUEST_CODE){
if(resultcode == RESULT_OK){
message = result.getStringExtra("android.training.intentsupplier.resultfromintentsupplier");

new AlertDialog.Builder(this)
.setTitle("Msg from Intent Supplier")
.setMessage(message)
.setNeutralButton("Close", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int sumthin) {
// do nothing – it will close on its own
}
})
.show();
}
}
}

}

The AndroidManifest.xml file of the IntentSupplier application looks like the following:

(** Please replace the "(" & ")" brackets with the angular brackets to xmlize the file contents)

(?xml version="1.0" encoding="utf-8"?)
(manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.training.intentsupplier"
android:versionCode="1"
android:versionName="1.0")
(application android:icon="@drawable/icon" android:label="@string/app_name")
(activity android:name=".IntentSupplier"
android:label="@string/app_name")

(intent-filter)
(action android:name="android.intent.action.MAIN" /)
(category android:name="android.intent.category.LAUNCHER" /)
(/intent-filter)

(intent-filter)
(action android:name="android.intent.action.INTENTSUPPLIERTEST" /)
(category android:name="android.intent.category.DEFAULT" /)
(data android:mimeType="vnd.example.greeting/vnd.example.greeting-text" /)
(/intent-filter)
(/activity)
(/application)
(uses-sdk android:minSdkVersion="3" /)
(/manifest)

The main.xml file of the IntentSupplier application looks like the following:

(?xml version="1.0" encoding="utf-8"?)
(LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
)
(TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/)
(Button android:text="Message1" android:id="@+id/Button01" android:layout_width="fill_parent" android:layout_height="wrap_content")(/Button)
(Button android:text="Message2" android:id="@+id/Button02" android:layout_width="fill_parent" android:layout_height="wrap_content")(/Button)
(/LinearLayout)

In this example we have started the IntentSupplier app through the function startActivityForResult. It then waits for the result from the child activity, and once the result arrives, the callback function onActivityResult is called. in this function we extract the data sent from the child activity (by using the function getStringExtra) and show it in a message box.

To run this application we need to run once the IntentSupplier application first.

Hope this discussion becomes helpful for the newbies of Android.

Sunday, July 5, 2009

My first time experience with Android Webkit

As I was trying to play around with WebKit, I tried to load an web page through it in Android. A good starting point for WebKit may be found at

http://developer.apple.com/documentation/Cocoa/Conceptual/DisplayWebContent/DisplayWebContent.html .

The source code of my android application is pretty straight forward.

It goes like this:

public class WebKitExample extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

WebView webView;

setContentView(R.layout.main);

webView = (WebView)findViewById(R.id.appView);

webView.getSettings().setJavaScriptEnabled(true);

webView.loadUrl("http://www.google.com");
}
}

We need to add the XML resource in the main.layout as the following:

(WebView android:id="@+id/appView"
android:layout_height="wrap_content"
android:layout_width="fill_parent" /)

We also need to add the permission to the manifest file as the following:

(uses-permission android:name = "android.permission.INTERNET" /)

And the application will look like the following in the emulator.



Although the example shown here is pretty simple but it can be a starting point in learning Webkit in Android. Hope this helps the newbies of Android.

Sunday, June 14, 2009

Parameterized factory design pattern in Android Media Service Framework

As i was going through the Media framework of Android, i have found the implementation of a parameterized factory pattern in the way MediaPlayerService class creates the concrete media players.

Let me give an idea of the parameterized factory implementation as discussed in the GoF book. It goes like this.

class Creator {

public:

virtual Product* CreateProduct( ProductId id);

};

And the implementation will look like the following:

Product* Creator :: CreateProduct (ProductId id)
{

if (id == Product1) return new Product1;

if (id == Product2) return new Product2;

//repeat for the other products

return 0;

}

Product1, Product2 etc are all derived from the base class Product.

Now let us dissect the Media Framework of Android to see how this design pattern has been implemented to create the different Media players.

The base class of all the players are MediaPlayerInterface which is again derived from MediaPlayerBase.

MediaPlayerService has got a static function called

"static sp createPlayer(player_type playerType, void* cookie, notify_callback_f notifyFunc)"

which actually takes care of the creation of the concrete players namely PVPlayer, MidiFile and VorbisPlayer.

Hence the class MediaPlayerService works as the Factory class for creating the Concrete Players besides handling other responsibilities.

The class MediaPlayerService can be found at \base\media\libmediaplayerservice of the Android source code.

The createPlayer function goes like the following :

static sp(MediaPlayerBase) createPlayer(player_type playerType, void* cookie,
notify_callback_f notifyFunc)
{
sp(MediaPlayerBase) p;
switch (playerType) {
#ifndef NO_OPENCORE
case PV_PLAYER:
LOGV(" create PVPlayer");
p = new PVPlayer();
break;
#endif
case SONIVOX_PLAYER:
LOGV(" create MidiFile");
p = new MidiFile();
break;

case VORBIS_PLAYER:
LOGV(" create VorbisPlayer");
p = new VorbisPlayer();
break;
}
if (p != NULL) {
if (p->initCheck() == NO_ERROR) {
p->setNotifyCallback(cookie, notifyFunc);
} else {
p.clear();
}
}
if (p == NULL) {
LOGE("Failed to create player object");
}
return p;
}

As we can see from the above code that MediaPlayerBase here works as the base class Product. And we create different products (different concrete media players) through the function createPlayer which works as the CreateProduct function in the example at the beginning.

The above similarity shows how a Parameterized Factory Pattern has been implemented in the Android Media Framework by MediaService layer to create different Media Players.