I’ve written a service and I plan to have multiple applications communicate with it using Messenger. I’ve followed the example from the Android Bound Services example for messenger.
I’ve put the service inside an Android library project and all the other Android projects use that library.
The problem I have is that multiple instances of the service run when I bind to it. Each application binds to the service in the following manner:
// Bind to the service
bindService(new Intent(ApplicationOneActivity.this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
The service is:
public class MessengerService extends Service {
/** Command to the service to display a message */
public static final int MSG_SAY_HELLO = 0;
/** Command to the service to display a message from App 1 */
public static final int MSG_APP1_HELLO = 1;
public static final int MSG_APP2_HELLO = 2;
public static final int MSG_APP3_HELLO = 3;
private int[] stat = new int[3];
private Timer timer = null;
/**
* 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;
case MSG_APP1_HELLO:
Toast.makeText(getApplicationContext(), "App One says: " + msg.arg1, Toast.LENGTH_SHORT).show();
stat[0] = msg.arg1;
break;
case MSG_APP2_HELLO:
Toast.makeText(getApplicationContext(), "App Two says: " + msg.arg1, Toast.LENGTH_SHORT).show();
stat[1] = msg.arg1;
break;
case MSG_APP3_HELLO:
Toast.makeText(getApplicationContext(), "App Three says: " + msg.arg1, Toast.LENGTH_SHORT).show();
stat[2] = msg.arg1;
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();
}
@Override
public boolean onUnbind(Intent intent) {
Toast.makeText(getApplicationContext(), "unbinding", Toast.LENGTH_SHORT).show();
return super.onUnbind(intent);
}
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
// Create and send a message to the service, using a supported 'what' value
ReportAsyncTask report = new ReportAsyncTask();
report.execute("");
}
};
@Override
public void onCreate() {
super.onCreate();
if (timer == null) {
timer = new Timer();
timer.schedule(new ScheduledTaskWithHandeler(), 10000);
Toast.makeText(getApplicationContext(), "Register Timer To Report Back ", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (timer != null) {
timer.cancel();
timer = null;
}
}
class ScheduledTaskWithHandeler extends TimerTask {
@Override
public void run() {
handler.sendEmptyMessage(0);
}
}
private class ReportAsyncTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... urls) {
String response = "";
try {
String urlParams="device=" + URLEncoder.encode(android.os.Build.MODEL, "UTF-8")
+ "&status="+URLEncoder.encode("App1 says " + stat[0] + ", App2 says " + stat[1] + ", App3 says " + stat[2],"UTF-8");
String url = "http://192.168.43.143:8080/SimpleServlet3/monitor-servlet";
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url+"?"+urlParams);
HttpResponse httpresponse = httpclient.execute(httpget);
HttpEntity entity = httpresponse.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
int l;
byte[] tmp = new byte[2048];
while ((l = instream.read(tmp)) != -1) {
response += l;
}
}
timer.schedule(new ScheduledTaskWithHandeler(), 10000);
} catch (Exception e) {
e.printStackTrace();
}
return response;
}
@Override
protected void onPostExecute(String result) {
Toast.makeText(getApplicationContext(), "Server says " + result, Toast.LENGTH_SHORT).show();
}
}
}
The Manifest for each Application looks more of less like:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app1"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="11" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/spinifex"
android:label="@string/app_name" >
<activity
android:name=".ApplicationOneActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="com.example.services.MessengerService"
android:process=":remote" />
</application>
</manifest>
Any idea what I’m doing wrong? The Toast messages pretty conclusively show that multiple instances of the same service are running. Is my project structure wrong? Should I not put the service in a separate Library project?
You must declare
<service />tag only in one AndroidManifest, and in other apps you must bind via full component name.Such as:
Also, when you do
android:process=":remote", you telling to android that process is private to current application.