バウンドサービスに関するドキュメントを読みました。ここでは、アクティビティからリモート(つまり同じコンテキストではない)サービスへのメッセージを介して簡単に通信できることが示されていますが、サービスからバウンドにメッセージを送信する方法はありますか活動?たとえば、私のアクティビティは同じアプリケーションの実行中のバックグラウンドサービスにバインドされ、それにメッセージを送信し、このメッセージを受信すると、サービスはアクティビティへのメッセージで応答します。これを実装するにはどうすればよいですか。このトピックを説明するドキュメントを教えていただけますか?
5 に答える
注:これは、進行中のサービスとアクティビティ専用であり、質問のようにリモートではありません。
サービスを使用してアクティビティと通信するには、アクティビティからサービスに渡すことができるリスナーを作成する必要があります。
アクティビティにバインドされたサービスを作成する必要があります。
最初のステップはサービスを作ることです。サービスには、Binderオブジェクトとバインダーオブジェクトを返すメソッドがあることを確認してください。以下は、バインダーを取得するためにサービスで使用した例です。また、このバインダーにはリスナーを設定するメソッドがあり、BoundServiceListenerタイプフィールドとしてサービスに保存されることに注意してください。
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class DownloadBgBinder extends Binder {
public DownloadBgService getService() {
// Return this instance of LocalService so clients can call public methods
return DownloadBgService.this;
}
public void setListener(BoundServiceListener listener) {
mListener = listener;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
次に、サービスが更新を送信するために使用できるバインダーオブジェクトに渡すことができるある種のインターフェイスを作成する必要があります。以下は私のBoundServiceListenerです。
public interface BoundServiceListener {
public void sendProgress(double progress);
public void finishedDownloading();
}
次に、アクティビティで、サービスへのバインドに使用されるServiceConnectionオブジェクトを作成する必要があります。したがって、このようなものを追加します。
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
DownloadBgBinder binder = (DownloadBgBinder) service;
mService = binder.getService();
binder.setListener(new BoundServiceListener() {
@Override
public void sendProgress(double progress) {
// Use this method to update our download progress
}
@Override
public void finishedDownloading() {
}
});
mBound = true;
}
ここで注意すべき重要な行は
binder.setListener(new BoundServiceListener() {
@Override
public void sendProgress(double progress) {
// Use this method to update our download progress
}
@Override
public void finishedDownloading() {
}
});
この部分では、実際にBoundServiceListenerインターフェイスをサービスクラスに送信しています。次に、サービスクラスはここでそのリスナーオブジェクトを使用します
if (mListener!=null)
mListener.finishedDownloading();
if (mListener!=null)
mListener.sendProgress(percent);
これで、これをサービスクラスの必要な場所に配置でき、アクティビティに進捗状況の更新が送信されます。
また、実際にサービスをバインドして開始するには、アクティビティに以下を含めるようにしてください。
Intent intent = new Intent(this, DownloadBgService.class);
startService(intent);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
サービスにバインドしても、startserviceを呼び出すまで実際には開始されないことに注意してください。サービスにバインドすると、サービスがアクティビティに接続されるだけです。startService()メソッドはサービスを呼び出します
onStartCommand(Intent intent, int flags, int startId)
また、マニフェストでサービスを宣言します
<service android:name=".services.DownloadBgService" />
また、アクティビティが終了するときにサービスのバインドを解除します
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
お役に立てれば。
リモートメッセンジャーサービスサンプルのリファレンスドキュメントに例があります。
1)transact / onTransactメソッドを独自のBinder.classに実装し、バインダープロキシがIInterface.classオブジェクトを実装します(匿名またはクラスを直接拡張することにより)これらのメソッドで渡されたものを使用しますParcel.classオブジェクト
2)ローカルインターフェイスを独自のBinderオブジェクトにアタッチします3 )サービスを作成し、onBindメソッドからバインダープロキシ実装を返します4)bindService(ServiceConnection)でボンドを作成します5)これにより、インターフェイス実装で作成されたバインドを介してプロキシバインダーが返されます
これは、カーネルバインダースペースを使用したIPCのAndroid実装です
コード例で単純化:
class ServiceIPC extends Service {
@Override
public Binder onBind() {
return new IInterface() {
IInterface _local = this;
@Override
public IBinder asBinder() {
return new Binder()
{
//
// allow distinguish local/remote impl
// avoid overhead by ipc call
// see Binder.queryLocalInterface("descriptor");
//
attachLocalInterface(_local,"descriptor");
}
@Override
public boolean onTransact(int code,
Parcel in,
Parcel out,
int flags)
throws RemoteException {
//
// your talk between client & service goes here
//
return whatsoever // se super.onTransact();
}
}
}
}.asBinder();
}
}
*次に、クライアント側とサービス側でIBinderを使用して、transactメソッドを相互に通信できます(ブース側で同じonTransactメソッドを使用するため、奇数/イブコードを使用してローカルリモート側を嫌う4つの例)
を使用してこれを実行できるはずです。Androidの課金APIのようなAIDLファイルが行います。RPC呼び出しを行う方法です(リモートプロセス間で通信します)。ただし、使用する各メソッドを宣言する必要があります。すでに述べたインターフェースのようなものです。
要するに、答えは、ResponseHandlerを備えたメッセンジャーをmsg.replyTo()に割り当てることです。以下の例でそれをどのように行うかを見てみましょう。
この例の機能の概要: この例では、MainActivityにボタンがあり、そのonClick()がsendMessage(View view)にリンクされています。ボタンがクリックされると、RemoteServiceにカスタムメッセージを送信します。リモートサービスでカスタムメッセージを受信したら、CurrentTimeをカスタムメッセージに追加して、MainActivityに送り返します。
MainActivity.java
public class MainActivity extends AppCompatActivity {
ServiceConnector serviceConnector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.serviceConnector = new ServiceConnector();
Intent intent = new Intent(this,RemoteService.class);
bindService(intent,serviceConnector, Context.BIND_AUTO_CREATE);
}
public void sendMessage(View view) {
Message msg = Message.obtain();
msg.replyTo = new Messenger(new ResponseHandler(this));
Bundle bundle = new Bundle();
bundle.putString("MyString", "Time");
msg.setData(bundle);
try {
this.serviceConnector.getMessenger().send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
ResponseHandler.java
public class ResponseHandler extends Handler {
MainActivity mainActivity;
public ResponseHandler(Context context){
this.mainActivity = (MainActivity) context;
}
@Override
public void handleMessage(@NonNull Message msg) {
Bundle data = msg.getData();
String dataString = data.getString("respData");
Toast.makeText(this.mainActivity,dataString,Toast.LENGTH_SHORT).show();
}
}
ServiceConnector.java
public class ServiceConnector implements ServiceConnection {
private Messenger messenger;
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder)
{
this.messenger = new Messenger(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
this.messenger = null;
}
public Messenger getMessenger(){
return this.messenger;
}
}
RemoteService.java
public class RemoteService extends Service {
private final IBinder iBinder = new Messenger(new IncomingHandler(this)).getBinder();
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return iBinder;
}
}
IncomingHandler.java
public class IncomingHandler extends Handler {
private RemoteService remoteService;
public IncomingHandler(Context context)
{
this.remoteService = (RemoteService)context;
}
public RemoteService getService()
{
return this.remoteService;
}
@Override
public void handleMessage(@NonNull Message msg) {
try {
msg.replyTo.send(getCurrentTime(msg));
} catch (RemoteException e) {
e.printStackTrace();
}
}
public Message getCurrentTime(Message msg){
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss MM/dd/yyyy", Locale.US);
Message resp = Message.obtain();
Bundle bResp = new Bundle();
bResp.putString("respData", msg.getData().getString("MyString") + " : " +(dateFormat.format(new Date())).toString());
resp.setData(bResp);
return resp;
}
}