开发者

Why can't we call api of android (AIDL based) remote service directly?

I was writing a simple AIDL based android remote service & a client to access the API exposed by the remote service. I checked on the internet, in every posts people have called the remote service API inside button's onClickListener() method of client code. However when i tried to call the API exposed by remote service outside the onClickListener() method it throws me NullPointerException, indicating that my service object has not been initialized (Please check the comments inside the onCreate method of client code). I have attached my code with this question. If anyone can explain me why is the behavior so then that would be really great.

Here is client code :

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,

Rupesh


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

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 .

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜