我正在写一个简单的基于AIDL的Android远程服务&客户端访问远程服务公开的API。我在互联网上查了一下,人们在按钮的onClickListener()客户端代码方法中调用了远程服务API。但是,当我试图在onClickListener()方法之外调用远程服务公开的API时,它会抛出NullPointerException,表明我的服务对象尚未初始化(请检查客户端代码的onCreate方法内的注释)。我已将此代码附加到此问题中。如果有人能解释我为什么这样的行为那么那将是非常好的
这是客户端代码:
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();
}
}
}
这是我的远程服务代码:
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!";
}
};
}
这是我的aidl文件:
package com.myapp.myservice;
interface RemoteServiceInterface {
String getMessage();
}
提前致谢,
Rupesh
答案 0 :(得分:4)
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();
}
请记住,绑定是一个asychronus调用,您必须等待onServiceConnected的ServiceConnection中的回调并在此之后执行操作。
此外,您必须使用asInterface方法来获取连接的真实界面,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;
}
};
然后,您可以在mIRemoteService对象上进行调用。直接在onServiceConnected回调中或通知服务。
答案 1 :(得分:1)
remoteInterface
调用)之前, onServiceConnected
为NULL 。
startService
是async
来电,您拨打startService
并不意味着该服务已启动并已连接。连接服务时,调用onServiceConnected
,然后您可以使用该连接来呼叫远程服务。
实际上,您应该始终检查天气remoteInterface
是否为空。