Как вызвать удаленную службу Android (IPC) из виджета / локальной службы? - PullRequest
5 голосов
/ 11 января 2011

Я пытаюсь удаленно управлять живыми обоями из виджета. Они находятся в одном и том же APK, но, очевидно, разные процессы. Называть «активность» живых обоев для меня бесполезно, поскольку это другой процесс. Виджет имеет простые кнопки, которые при нажатии

Так что (я думаю) мне нужны IPC и AIDL.

Сначала я создал AIDL на стороне обоев, которая работала нормально. У него есть три метода без дополнительных параметров. Но когда я добавил клиентскую сторону к виджету, я получил сообщение об ошибке, в котором говорится, что я не могу привязаться к этому удаленному интерфейсу, поскольку виджет уже является BroadcastListener. Я попытался включить обработку кнопок без необходимости, чтобы виджет был BroadcastListener, но это кажется невозможным.

Ну, нет проблем, верно? Я только что создал службу в виджете, которая привязывается к удаленному интерфейсу, потому что, хотя виджет является BroadcastListener, службы нет, и все должно быть хорошо.

Или я так думал.

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

Невозможно запустить службу Intent (act = com.blabla.IRemoteService): не найдено.

Я использую getApplicationContext () внутри службы виджета для привязки к удаленному материалу. У меня есть служба виджетов в манифесте, но у меня нет удаленной службы там. Когда я помещаю его туда, я получаю неспецифическое исключение InstantiationException.

В службе виджета onStart () я делаю это:

getApplicationContext().bindService(new Intent(IWallpaperRemote.class.getName()), 
  mConnection, Context.BIND_AUTO_CREATE);

У меня тоже есть ...

private ServiceConnection mConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className,
            IBinder service) {
        mService = IWallpaperRemote.Stub.asInterface(service);
        isBound = true;
        Log.i("WidgetServiceConnection", "binding to service succeeded");
    }

    public void onServiceDisconnected(ComponentName className) {
        mService = null;
        isBound = false;
        Log.i("WidgetServiceConnection", "binding to service lost!");
    }
};

У меня такой вопрос: кто-нибудь когда-нибудь успешно делал удаленный вызов из виджета в другое приложение? Учитывая, что я имею в виду живые обои здесь и тот факт, что я не заинтересован в вызове активности в процессе виджета, но вызывает вызовы функций в живых обоях, какие у меня есть варианты, кроме IPC, если таковые имеются? *

А если IPC - это путь, что я делаю не так?

1 Ответ

15 голосов
/ 11 января 2011

Я нашел ответ на свой вопрос.Чтобы упростить задачу для других, вот решение:

При выполнении удаленного сервиса необходимо написать AIDL, который будет скомпилирован в своего рода интерфейс-заглушку, реализацию этого интерфейса (то есть код, которыйвыполняется, когда кто-то вызывает удаленные методы), и класс, который расширяет «Service», который возвращает класс реализации в методе onBind ().(Обычный локальный сервис возвращает ноль в этом методе)

Теперь я не понял, что вы ДОЛЖНЫ иметь определение сервиса в манифесте - С ФИЛЬТРОМ НАМЕРЕНИЯ!

Скажем, ваш AIDLназывается IRemoteService.aidl, тогда у вас есть класс RemoteService, который выглядит следующим образом:

public class RemoteService extends Service {
  public IBinder onBind(Intent intent) {
    Log.i("RemoteService", "onBind() called");
    return new RemoteServiceImpl();
  }
  /**
   * The IRemoteInterface is defined through IDL
   */
  public class RemoteServiceImpl extends IRemoteService.Stub {
    public void remoteDetonateBirthdayCake() throws RemoteException {
        //your code here
    }
  };
}

В вашем манифесте Android вы хотите:

<service android:name="RemoteService"> 
    <intent-filter>
        <action android:name="com.sofurry.favorites.IRemoteService"></action>
</intent-filter>
</service>

Обратите внимание на имя службы:Это «RemoteService», а не «IRemoteService» или даже «RemoteServiceImpl».Вам нужно имя класса, который расширяет "Service", метод onBind которого мы переопределили.

Для завершения приведем код на стороне клиента - и да, этот код также работает из другой службы, дляпример, который вы начали с вашего виджета;)

IRemoteService mService;
RemoteServiceConnection mConnection = new RemoteServiceConnection();
getApplicationContext().bindService(new Intent(IRemoteService.class.getName()), mConnection, Context.BIND_AUTO_CREATE);

... где RemoteServiceConnection может быть внутренним классом, например так:

class RemoteServiceConnection implements ServiceConnection {
    public void onServiceConnected(ComponentName className, 
        IBinder service ) {
        mService = IRemoteService.Stub.asInterface(service);
        isBound = true;
    }

    public void onServiceDisconnected(ComponentName className) {
        mService = null;
        isBound = false;
    }
};

И теперь вы можете звонить..

mService.remoteDetonateBirthdayCake();

В заключение: убедитесь, что в манифесте android указан раздел службы, задайте для «name» класс, который возвращает фактическую реализацию в методе onBind (), и вы также должны иметьФильтр намерений с определением действия, указывающим на интерфейс AIDL.

Подсказка: если вы вызываете удаленные службы из приложения внутри другого APK, добавьте элемент «категория» в фильтр намерений и установите егоПО УМОЛЧАНИЮ.

...