Why can't we call api of android (AIDL based) remote service directly?
package com.myapp.myclient;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import com.myapp.myservice.RemoteServiceInterface;
public class MyClient extends Activity {
RemoteServiceInterface remoteInterface;
ServiceConnection connection;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent i = new Intent();
i.setAction("com.myapp.myservice.RemoteService");
startRemoteInterface(i);
bindRemoteInterface(i);
/* This code doesn't execute. Raises a Null Pointer
Exception, indicating that remoteInterface is not
initialized. */
try {
Toast.makeText(getBaseContext(), remoteInterface.getMessage(), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
/* Whereas this code does work. */
Button getMessage = (Button)findViewById(R.id.getMessage);
getMessage.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String msg = null;
try {
msg = remoteInterface.getMessage();
} catch (RemoteException e) {
e.printStackTrace();
}
Toast.makeText(getBaseContext(), msg, Toast.LENGTH_SHORT).show();
}
});
}
class RemoteServiceConnection implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
remoteInterface = RemoteServiceInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
private void startRemoteInterface(Intent i) {
startService(i);
}
private void bindRemoteInterface(Intent i) {
if(connection == null){
connection = new RemoteServiceConnection();
bindService(i, connection, Context.BIND_AUTO_CREATE);
} else {
Toast.makeText(getBaseContext(), "Service cannot bind - already bound.", Toast.LENGTH_SHORT).show();
}
}
}
Here is my remote service code:
package com.myapp.myservice;
import android.开发者_运维知识库app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class RemoteService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
private final RemoteServiceInterface.Stub mBinder = new RemoteServiceInterface.Stub() {
@Override
public String getMessage() throws RemoteException {
return "Hello World!";
}
};
}
Here is my aidl file :
package com.myapp.myservice;
interface RemoteServiceInterface {
String getMessage();
}
Thanks in advance,
RupeshbindRemoteInterface(i);
/* This code doesn't execute. Raises a Null Pointer
Exception, indicating that remoteInterface is not
initialized. */
try {
Toast.makeText(getBaseContext(), remoteInterface.getMessage(), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
Please keep in mind that the bind is an asychronus call you have to wait for the callback in the ServiceConnection for onServiceConnected and perform actions after that.
Also you have to use the asInterface method to get the real interface for your connection this is demonstrated by the google aidl example
RemoteServiceInterface mIRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Following the example above for an AIDL interface,
// this gets an instance of the IRemoteInterface, which we can use to call on the service
mIRemoteService = RemoteServiceInterface.Stub.asInterface(service);
}
// Called when the connection with the service disconnects unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "Service has unexpectedly disconnected");
mIRemoteService = null;
}
};
You can then make the call on the mIRemoteService object. either directly in the onServiceConnected callback or by notifying the service.
remoteInterface
is NULL before service is connected (onServiceConnected
called) .
startService
is an async
call, you call startService
don't mean the service is started and connected . when service is connected , onServiceConnected
is called , then you can use the connection to call remote service .
Actually , you should always check weather remoteInterface
is null or not .
精彩评论