Continued from service tutorial-I…,

3. Service using Messenger:

Now i am going to explain Working with messengers in service:

If you need to be able to write a Service that can perform complicated communication with clients in remote processes (beyond simply the use of Context.startService to send commands to it), then you can use the Messenger class instead of writing full AIDL files.

An example of a Service that uses Messenger as its client interface is shown here. First is the Service itself, publishing a Messenger to an internal Handler when bound:

[sourcecode language=”java”]

public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;

/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}

/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());

/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}

[/sourcecode]

—————————————————————————————————
If we want to make this service run in a remote process (instead of the standard one for its .apk), we can use android:process in its manifest tag to specify one:

<service android:name=”MessengerService”
android:process=”:remote” />

Note that the name “remote” chosen here is arbitrary, and you can use other names if you want additional processes. The ‘:’ prefix appends the name to your package’s standard process name.

With that done, clients can now bind to the service and send messages to it. Note that this allows clients to register with it to receive messages back as well:

[sourcecode language=”java” autolinks=”true”]

public class ServiceUsingMessangerActivity extends Activity {
/** Messenger for communicating with the service. */
Messenger mService = null;

/** Flag indicating whether we have called bind on the service. */
boolean mBound;

/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);
mBound = true;
}

public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected — that is, its process crashed.
mService = null;
mBound = false;
}
};

public void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported ‘what’ value
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}

@Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,Context.BIND_AUTO_CREATE);
}

@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}

[/sourcecode]

4. Service using Remote AIDL files:

Each application in Android runs in its own process. An application cannot directly access another application’s memory space. This is called application sand-boxing.

In order to allow cross-application communication, Android provides an implementation of interprocess communication (IPC) protocol. IPC protocols tend to get complicated because of all the marshaling/un marshaling of data that is necessary.

To help with this, Android provides Android Interface Definition Language, or AIDL. It is a lightweight implementation of IPC using a syntax that is very familiar to Java developers, and a tool that automates the stub creation.

In order to allow for one application to call into another, we typically have to:

1. Define the AIDL interface:

AIDL interface looks like a general java interface.By default,AIDL supports the following data types:

-> All primitive types in java (such as int,long,char,boolean)

2. Implement the interface:

3. Expose the interface to clients.

5. IntentService:

While the base class for creating a Service is the Service class you can also implement IntentService. The IntentService is used to perform a certain task in the background. Once done, the instance of IntentService terminate itself automatically. Examples for its usage would be to download a certain resources from the Internet. The IntentService class offers the onHandleIntent() method which will be asynchronously called by the Android system.

                                           It is advisable to use thread/asynTask or Service to handle long running task such as file I/O, internet access etc. IntentService is simple, easy to use and take care of many hectic tasks for You.Read more about IntentService at developer.android. A simple use case of the topic can be:

  • Your activity send a web request to IntentService to process
  • Your IntentService execute that request using DefaultHttpClient
  • And Return results (whatever, true,false list of objects/records etc) back to the calling activity

Now the task is to return the results back to the activity.  There are two options available either we can use Broadcast receiver or ResultReceiver

  1. Broadcast should be used if you want to send data/notifications across applications, whenever you send broadcast its sent system wide read more about broadcast receivers at developer.android.
  2. Result receiver is an interface you implement and pass it to the intentService through putExtra. IntentService then fetch this object and call its receiver.send function to send anything (in bundle) to calling activity[who started the intentservice]. Result receiver has preference over broadcast receivers if your all communication is internal to your application.

[sourcecode language=”java”]
public class CheckIntentService extends IntentService {

private int count;
public static final int INIT = 1;
public static final int RUNNING = 2;
public static final int END = 3;

public CheckIntentService()
{
super("Downloading");
}

@Override
protected void onHandleIntent(Intent intent) {
count = 0;
ResultReceiver receiver = intent.getParcelableExtra("receiver");
Bundle bundle = new Bundle();
bundle.putString("message", "Init the service");

receiver.send(INIT, bundle);

bundle = new Bundle();

while (count < 10) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bundle.putString("message", "Running the service");
bundle.putInt("count", count);
receiver.send(RUNNING, bundle);
count++;
}
bundle = new Bundle();
bundle.putString("message", "End of the service");
bundle.putInt("count", count);
receiver.send(END, bundle);
}
}

public class IntentServiceDemo extends Activity {

public static final String TAG = "IntentServiceDemo";

// private ResultReceiver receiver = new ResultReceiver(new Handler()) ;
ResultReceiver r = new ResultReceiver(new Handler()) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
String str = "";
if (resultCode == CheckIntentService.INIT) {
str = resultData.getString("message");
Log.i(TAG, str);
} else if (resultCode == CheckIntentService.RUNNING
|| resultCode == CheckIntentService.END) {
str = resultData.getString("message");
int count = resultData.getInt("count", 0);
Log.i(TAG, "message:" + str);
Log.i(TAG, "count:" + count);
}

}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

findViewById(R.id.button1).setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

Intent intentService = new Intent(IntentServiceDemo.this,
CheckIntentService.class);
intentService.putExtra("receiver", r);
startService(intentService);

}
});

}

}

[/sourcecode]

Note:  Don’t use constructor with parameter in IntentService extended class.It shows an exception.

public CheckIntentService(String name)
{
super(“Downloading”);
}

Service Tutorial in android Part-II
Tagged on:                     

Leave a Reply

Your email address will not be published. Required fields are marked *