AIDL и Messenger одновременно - PullRequest
4 голосов
/ 27 декабря 2011

Я пытаюсь написать демонстрацию о том, как использовать AIDL и Messenger одновременно, но у меня есть ошибка, и я не знаю причину.

MessengerDEMOActivity.java

public class MessengerDEMOActivity extends Activity {
    /** Called when the activity is first created. */

    private MessengerDEMOServiceConnection MDSconnection = null;
    private Messenger mMessenger = null;

    class IncomingHandler extends Handler {
            public void handleMessage(Message msg) {
            Bundle b = msg.getData();
            System.out.println("MESSENGER! " + b.getString("MESSENGER"));
        }
    }

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

        mMessenger = new Messenger(new IncomingHandler());

        MDSconnection = new MessengerDEMOServiceConnection(mMessenger);
        Intent intent = new Intent();
        intent.putExtra("ID", "AIDL");
        intent.setClassName("messenger.demo", messenger.demo.MessengerDEMOService.class.getName());
        bindService(intent, MDSconnection, Context.BIND_AUTO_CREATE);

    }
}

MessengerDEMOServiceConnection.java

public class MessengerDEMOServiceConnection implements ServiceConnection {

    private IMessengerDEMOService service = null;
    private Messenger mMessenger = null;

    public MessengerDEMOServiceConnection(Messenger mMessenger) {
        super();
        System.out.println("MessengerDEMOServiceConnection SocketServiceConnection()");
        this.mMessenger = mMessenger;
    }

    public void onServiceConnected(ComponentName name, IBinder boundService) {
        System.out.println("MessengerDEMOServiceConnection onServiceConnected()");
        service = IMessengerDEMOService.Stub.asInterface((IBinder) boundService);

        Messenger mService = new Messenger(boundService);

        Message msg = Message.obtain(null, 5);
        msg.replyTo = mMessenger;
        try {
            mService.send(msg); // line 31
        } catch (RemoteException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        try {
            service.foo();
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void onServiceDisconnected(ComponentName name) {
        System.out.println("MessengerDEMOServiceConnection onServiceDisconnected()");
        service = null;
    }
}

MessengerDEMOService.java

public class MessengerDEMOService extends Service {

    private Messenger mMessenger = null;

    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            System.out.println("MessengerDEMOService IncomingHandler");
            Messenger activityMessenger = msg.replyTo;
            Message m = new Message();
            Bundle b = new Bundle();
            b.putString("MESSENGER", "blablabla");
            m.setData(b);
            try {
                activityMessenger.send(m);
            } catch (RemoteException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public void onCreate() {
        System.out.println("MessengerDEMOService onCreate");
        mMessenger = new Messenger(new IncomingHandler());
    }

    public IBinder onBind(Intent intent) {

        System.out.println("MessengerDEMOService onBind()");

        if (intent.getExtras().getString("ID").equals("AIDL") == true) {
            System.out.println("MessengerDEMOService onBind() AIDL");
            return new IMessengerDEMOService.Stub() {
                public void foo() {
                    System.out.println("MessengerDEMOService onBind() foo()");
                }
            };
        }

        System.out.println("MessengerDEMOService onBind() MESSENGER");
        return mMessenger.getBinder();
    }
}

И трассировка стека:

12-27 16:42:29.412: INFO/System.out(832): MessengerDEMOServiceConnection SocketServiceConnection()
12-27 16:42:29.442: INFO/System.out(832): MessengerDEMOService onCreate
12-27 16:42:29.452: INFO/System.out(832): MessengerDEMOService onBind()
12-27 16:42:29.452: INFO/System.out(832): MessengerDEMOService onBind() AIDL
12-27 16:42:29.542: INFO/System.out(832): MessengerDEMOServiceConnection onServiceConnected()
12-27 16:42:29.572: WARN/Parcel(832): **** enforceInterface() expected 'messenger.demo.IMessengerDEMOService' but read 'android.os.IMessenger'
12-27 16:42:29.572: DEBUG/AndroidRuntime(832): Shutting down VM
12-27 16:42:29.572: WARN/dalvikvm(832): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
12-27 16:42:29.592: ERROR/AndroidRuntime(832): FATAL EXCEPTION: main
12-27 16:42:29.592: ERROR/AndroidRuntime(832): java.lang.SecurityException: Binder invocation to an incorrect interface
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at android.os.Parcel.enforceInterface(Native Method)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at messenger.demo.IMessengerDEMOService$Stub.onTransact(IMessengerDEMOService.java:49)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at android.os.Binder.transact(Binder.java:249)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at android.os.IMessenger$Stub$Proxy.send(IMessenger.java:89)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at android.os.Messenger.send(Messenger.java:50)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at messenger.demo.MessengerDEMOServiceConnection.onServiceConnected(MessengerDEMOServiceConnection.java:31)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at android.app.ActivityThread$PackageInfo$ServiceDispatcher.doConnected(ActivityThread.java:1247)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at android.app.ActivityThread$PackageInfo$ServiceDispatcher$RunConnection.run(ActivityThread.java:1264)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at android.os.Handler.handleCallback(Handler.java:587)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at android.os.Handler.dispatchMessage(Handler.java:92)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at android.os.Looper.loop(Looper.java:123)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at android.app.ActivityThread.main(ActivityThread.java:4627)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at java.lang.reflect.Method.invokeNative(Native Method)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at java.lang.reflect.Method.invoke(Method.java:521)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
12-27 16:42:29.592: ERROR/AndroidRuntime(832):     at dalvik.system.NativeStart.main(Native Method)

Без этих строк кодработает:

Message msg = Message.obtain(null, 5);
            msg.replyTo = mMessenger;
            try {
                mService.send(msg); // line 31
            } catch (RemoteException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }

Работает без AIDL и работает AIDL "один".Могу ли я вызывать onBinder более одного раза?

1 Ответ

4 голосов
/ 27 декабря 2011

Могу ли я вызывать onBinder более одного раза?

Простой ответ : да.На самом деле это происходит, если два разных приложения подключаются к одному и тому же сервису.

Так почему же это не работает ?Потому что вы используете два разных интерфейса для связи.

Что происходит подробно :

  1. Вы подключаетесь к услуге (AIDL)
  2. Вы пытаетесь send отправить сообщение мессенджером
  3. Android отправляет это сообщение службе по AIDL
  4. Первое, что нужно сделать, это то, что данные интерфейсы совпадают (сравнивая Interface Descriptor) (Подробнее см. Stub.onTransact)
  5. Android замечает, что эти интерфейсы не совпадают, и выдает SecurityException

Не выбрасывается RemoteException, посколькуsend() метод еще не вызван.

Простое исправление : поймать SecurityException.Но я бы посчитал это крайне плохим стилем (как всегда, когда логика вашего приложения основывается на исключениях).

Не так просто исправить : чтобы это работало, оба интерфейса должны иметь один и тот же дескриптор интерфейса (определенный в Stub.DESCRIPTOR в сгенерированном вами классе AIDL).Однако вам нужно реализовать Proxy / Stub для IPC самостоятельно (не так уж и плохо).

Еще одно исправление : создание двух ServiceConnection классов.Один отвечает за AIDL, другой за мессенджер.

Лучшее исправление (ИМО) : Выберите один метод за раз.Ваше решение похоже на поездку на работу (в одиночку) с двумя автомобилями одновременно.

...