9

バウンドサービスに関するドキュメントを読みました。ここでは、アクティビティからリモート(つまり同じコンテキストではない)サービスへのメッセージを介して簡単に通信できることが示されていますが、サービスからバウンドにメッセージを送信する方法はありますか活動?たとえば、私のアクティビティは同じアプリケーションの実行中のバックグラウンドサービスにバインドされ、それにメッセージを送信し、このメッセージを受信すると、サービスはアクティビティへのメッセージで応答します。これを実装するにはどうすればよいですか。このトピックを説明するドキュメントを教えていただけますか?

4

5 に答える 5

29

注:これは、進行中のサービスとアクティビティ専用であり、質問のようにリモートではありません。

サービスを使用してアクティビティと通信するには、アクティビティからサービスに渡すことができるリスナーを作成する必要があります。

アクティビティにバインドされたサービスを作成する必要があります。

最初のステップはサービスを作ることです。サービスには、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;
    }
}

お役に立てれば。

于 2012-08-18T00:37:15.207 に答える
7

リモートメッセンジャーサービスサンプルのリファレンスドキュメントに例があります。

于 2012-05-11T09:07:43.590 に答える
0

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つの例)

于 2018-12-24T14:04:02.617 に答える
0

を使用してこれを実行できるはずです。Androidの課金APIのようなAIDLファイルが行います。RPC呼び出しを行う方法です(リモートプロセス間で通信します)。ただし、使用する各メソッドを宣言する必要があります。すでに述べたインターフェースのようなものです。

于 2019-05-11T06:10:09.753 に答える
0

要するに、答えは、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;

    }
}
于 2022-02-27T01:53:47.923 に答える