5

ウィジェットからライブ壁紙をリモート コントロールしようとしています。それらは同じ APK にありますが、明らかに異なるプロセスです。ライブ壁紙の「アクティビティ」を呼び出すことは、別のプロセスであるため、ほとんど役に立ちません。ウィジェットにはシンプルなボタンがあり、押すと、

だから私が必要としているのは(私が思うに)IPCとAIDLです。

まず、壁紙側で AIDL を作成しましたが、うまくいきました。追加のパラメーターのない 3 つのメソッドがあります。しかし、クライアント側をウィジェットに追加すると、ウィジェットが既に BroadcastListener であるため、そのリモート インターフェイスにバインドできないというエラーが表示されました。Widget を BroadcastListener にすることなくボタン処理を取得しようとしましたが、それは不可能のようです。

問題ありませんよね?ウィジェットは BroadcastListener ですが、サービスはそうではなく、すべて問題ないため、リモート インターフェイスにバインドするウィジェット内にサービスを作成しました。

とか、そう思いました。

さて、ウィジェット サービスをトリガーするウィジェットのボタンを取得しています。リモート サービスにバインドすると、次の警告が表示されます。

サービスを開始できません インテント (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がここに行く方法である場合、私は何を間違っていますか?

4

1 に答える 1

15

私は自分の質問に対する答えを見つけました。他の人にとって物事を簡単にするための解決策は次のとおりです。

リモート サービスを実行する場合、一種のスタブ インターフェイスにコンパイルされる AIDL、そのインターフェイスの実装 (つまり、誰かがリモート メソッドを呼び出したときに実行されるコード)、および「サービス」を拡張するクラスを記述する必要があります。 " onBind() メソッドで実装クラスを返します。(通常のローカル サービスは、そのメソッドで null を返します)

私が理解していなかったのは、マニフェストにサービス定義が必要だということです - WITH INTENT FILTER!

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>

サービス名に注意してください。「IRemoteService」でも「RemoteServiceImpl」でもなく、「RemoteService」です。onBind メソッドをオーバーライドした「​​Service」を拡張するクラスの名前が必要です。

最後に、クライアント側のコードを示します。このコードは、別のサービス (たとえば、ウィジェットから開始したサービス) 内からも機能します ;)

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 マニフェストにサービス スタンザを用意し、onBind() メソッドで実際の実装を返すクラスに "name" を設定してください。 AIDL インターフェイス。

ヒント: 別の APK 内のアプリからリモート サービスを呼び出す場合は、"category" 要素もインテント フィルターに追加し、DEFAULT に設定します。

于 2011-01-11T20:14:32.450 に答える