私はこのようなものになりました:
1)補助的なものにスコープを与えるために、内部クラスを作成しました。少なくとも、醜い内部はコードの残りの部分から分離されています。何かをするリモートサービスが必要だったので、Something
クラス名の単語
private RemoteSomethingHelper mRemoteSomethingHelper = new RemoteSomethingHelper();
class RemoteSomethingHelper {
//...
}
2) リモート サービス メソッドを呼び出すには、IBinder と実行するコードの 2 つが必要です。どちらが最初に知られるようになるかわからないため、それらを保存します。
private ISomethingService mISomethingService;
private Runnable mActionRunnable;
これらのフィールドのいずれかに書き込むたびに、以下を呼び出し_startActionIfPossible()
ます。
private void _startActionIfPossible() {
if (mActionRunnable != null && mISomethingService != null) {
mActionRunnable.run();
mActionRunnable = null;
}
}
private void performAction(Runnable r) {
mActionRunnable = r;
_startActionIfPossible();
}
RemoteSomethingHelper
もちろん、これは Runnable が mISomethingService にアクセスできることを前提としていますが、これはクラスのメソッド内で作成された runnable に当てはまります。
ServiceConnection
コールバックが UI スレッドで呼び出されるのは本当に良いことです。メイン スレッドからサービス メソッドを呼び出す場合、同期を気にする必要はありません。
ISomethingService
もちろん、AIDL によって定義されます。
3) メソッドに引数を渡すだけでなく、後で呼び出しが可能な場合に、これらの引数を使用してメソッドを呼び出す Runnable を作成します。
private boolean mServiceBound;
void startSomething(final String arg1) {
// ... starting the service ...
final String arg2 = ...;
performAction(new Runnable() {
@Override
public void run() {
try {
// arg1 and arg2 must be final!
mISomethingService.startSomething(arg1, arg2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
4) 最後に、次のようになります。
private RemoteSomethingHelper mRemoteSomethingHelper = new RemoteSomethingHelper();
class RemoteSomethingHelper {
private ISomethingService mISomethingService;
private Runnable mActionRunnable;
private boolean mServiceBound;
private void _startActionIfPossible() {
if (mActionRunnable != null && mISomethingService != null) {
mActionRunnable.run();
mActionRunnable = null;
}
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
// the methods on this class are called from the main thread of your process.
@Override
public void onServiceDisconnected(ComponentName name) {
mISomethingService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mISomethingService = ISomethingService.Stub.asInterface(service);
_startActionIfPossible();
}
}
private void performAction(Runnable r) {
mActionRunnable = r;
_startActionIfPossible();
}
public void startSomething(final String arg1) {
Intent intent = new Intent(context.getApplicationContext(),SomethingService.class);
if (!mServiceBound) {
mServiceBound = context.getApplicationContext().bindService(intent, mServiceConnection, 0);
}
ComponentName cn = context.getApplicationContext().startService(intent);
final String arg2 = ...;
performAction(new Runnable() {
@Override
public void run() {
try {
mISomethingService.startSomething(arg1, arg2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
}
context
私のクラスのフィールドです。アクティビティでは、次のように定義できますContext context=this;
アクションをキューに入れる必要はありませんでした。もしそうなら、あなたはそれを実装することができます。
startSomething(); で結果のコールバックが必要になる可能性があります。私はしましたが、これはこのコードには示されていません。