Service Tutorial in android Part-II

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:


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();
 }
 }

—————————————————————————————————
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:


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;
 }
 }
 }

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.

IMyInterface.aidl:

package com.ramesh.services.aidl.demo;

interface IMyInterface
{
 void setUserName(in String name);
 String getName();
}

ServiceUsingAidl.java:

public class ServiceUsingAidl extends Service {

private String userName;

@Override
 public IBinder onBind(Intent intent) {
 return mBinder;
 }

private IMyInterface.Stub mBinder = new IMyInterface.Stub() {

@Override
 public void setUserName(String name) throws RemoteException {

userName = name;
 }

@Override
 public String getName() throws RemoteException {
 return userName;
 }
 };
}

AidlDemo.java:


public class AidlDemo extends Activity {

public static final String TAG = "Aidl Demo";
 private IMyInterface mService;

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

Intent serviceIntent = new Intent(this, ServiceUsingAidl.class);
 bindService(serviceIntent, conn, Service.BIND_AUTO_CREATE);

Button btn = (Button) findViewById(R.id.button1);
 btn.setOnClickListener(setNameListener);

Button btn2 = (Button) findViewById(R.id.button1);
 btn2.setOnClickListener(getNameListener);

}

private ServiceConnection conn = new ServiceConnection() {

@Override
 public void onServiceDisconnected(ComponentName name) {
 Log.i(TAG, "Service disconnected.");
 }

@Override
 public void onServiceConnected(ComponentName name, IBinder service) {
 Log.i(TAG, "Service connected.");
 mService = (IMyInterface) service;
 }
 };

private OnClickListener setNameListener = new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 if (mService != null) {
 try {
 mService.setUserName("Andorid world");
 } catch (RemoteException e) {
 e.printStackTrace();
 }
 }
 }
 };
 private OnClickListener getNameListener = new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 if (mService != null) {
 try {
 String str = mService.getName();
 Toast.makeText(AidlDemo.this, str, Toast.LENGTH_SHORT)
 .show();
 } catch (RemoteException e) {
 e.printStackTrace();
 }
 }
 }
 };
}

In manifest, we add service like a simple service.

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.
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);

}
 });

}

}

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

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

 
Feel free to comment on my posts.............
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s