Android 绑定类型服务---使用信使(Messenger)
以下是信使(Messenger)對象的使用概要:
1.??服務端實現的一個處理器(Handler接口),這個處理器針對每次來自客戶端的調用接收一次回調;
2.??這個處理器被用于創建一個信使對象(Messager)(這個信使對象要引用這個處理器);
3.??信使對象創建一個創建一個服務端從onBind()方法中返回給客戶端的IBinder對象;
4.??客戶端使用這個IBinder對象來實例化這個信使對象(信使引用了服務端的處理器),客戶端使用這個信使給服務端發送Message對象;
5.??服務端在它的處理器(Handler)的handleMessage()方法中依次接收每個Message對象
在這種方法中,沒有給客戶端提供服務端的方法調用,相反,客戶端會給發送服務端消息(Message)對象,服務端會在它的處理器中接受這些消息對象。
以下是使用Messenger接口的服務端示例代碼:
public class MessengerService extends Service {
? ? /** Command to the service to display a message */
? ? static final int MSG_SAY_HELLO = 1;
? ? /**
? ? ?* Handler of incoming messages from clients.
? ? ?*/
? ? class IncomingHandler extends Handler {
? ? ? ? @Override
? ? ? ? public void handleMessage(Message msg) {
? ? ? ? ? ? switch (msg.what) {
? ? ? ? ? ? ? ? case MSG_SAY_HELLO:
? ? ? ? ? ? ? ? ? ? Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? super.handleMessage(msg);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? /**
? ? ?* Target we publish for clients to send messages to IncomingHandler.
? ? ?*/
? ? final Messenger mMessenger = new Messenger(new IncomingHandler());
? ? /**
? ? ?* When binding to the service, we return an interface to our messenger
? ? ?* for sending messages to the service.
? ? ?*/
? ? @Override
? ? public IBinder onBind(Intent intent) {
? ? ? ? Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
? ? ? ? return mMessenger.getBinder();
? ? }
}
注意看處理器(Handler)中的handleMessage()方法,這是服務接受輸入Message對象和基于what成員屬性判斷做什么的地方。
客戶端需要做的所有工作就是基于服務端返回的IBinder對象創建一個Messenger對象,并且使用這個Messenger對象的send()方法發送消息。如,以下是一個簡單的Activity代碼,它綁定服務,并且給服務發送MSG_SAY_HELLO消息。
public class ActivityMessenger extends Activity {
? ? /** Messenger for communicating with the service. */
? ? Messenger mService = null;
? ? /** Flag indicating whether we have called bind on the service. */
? ? boolean mBound;
? ? /**
? ? ?* Class for interacting with the main interface of the service.
? ? ?*/
? ? private ServiceConnection mConnection = new ServiceConnection() {
? ? ? ? public void onServiceConnected(ComponentName className, IBinder service) {
? ? ? ? ? ? // This is called when the connection with the service has been
? ? ? ? ? ? // established, giving us the object we can use to
? ? ? ? ? ? // interact with the service. ?We are communicating with the
? ? ? ? ? ? // service using a Messenger, so here we get a client-side
? ? ? ? ? ? // representation of that from the raw IBinder object.
? ? ? ? ? ? mService = new Messenger(service);
? ? ? ? ? ? mBound = true;
? ? ? ? }
? ? ? ? public void onServiceDisconnected(ComponentName className) {
? ? ? ? ? ? // This is called when the connection with the service has been
? ? ? ? ? ? // unexpectedly disconnected -- that is, its process crashed.
? ? ? ? ? ? mService = null;
? ? ? ? ? ? mBound = false;
? ? ? ? }
? ? };
? ? public void sayHello(View v) {
? ? ? ? if (!mBound) return;
? ? ? ? // Create and send a message to the service, using a supported 'what' value
? ? ? ? Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
? ? ? ? try {
? ? ? ? ? ? mService.send(msg);
? ? ? ? } catch (RemoteException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? @Override
? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.main);
? ? }
? ? @Override
? ? protected void onStart() {
? ? ? ? super.onStart();
? ? ? ? // Bind to the service
? ? ? ? bindService(new Intent(this, MessengerService.class), mConnection,
? ? ? ? ? ? Context.BIND_AUTO_CREATE);
? ? }
? ? @Override
? ? protected void onStop() {
? ? ? ? super.onStop();
? ? ? ? // Unbind from the service
? ? ? ? if (mBound) {
? ? ? ? ? ? unbindService(mConnection);
? ? ? ? ? ? mBound = false;
? ? ? ? }
? ? }
}
?
我們注意到這個例子中沒有顯示服務端是如何能夠響應客戶端的,如果想要服務端響應,那么就需要在客戶端也創建一個信使(Messenger)對象,然后在客戶端收到onServiceConnected()回調時,它給服務發送一個Message對象,這個對象在send()方法的參數的replyTo成員中包含了客戶端的信使(Messenger)對象。
?
在以下代碼示例中你能夠看到客戶端和服務端是如何進行雙向通信的
MessageService.java(服務端):
/*
?* Copyright (C) 2010 The Android Open Source Project
?*
?* Licensed under the Apache License, Version 2.0 (the "License");
?* you may not use this file except in compliance with the License.
?* You may obtain a copy of the License at
?*
?* ? ? ?http://www.apache.org/licenses/LICENSE-2.0
?*
?* Unless required by applicable law or agreed to in writing, software
?* distributed under the License is distributed on an "AS IS" BASIS,
?* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
?* See the License for the specific language governing permissions and
?* limitations under the License.
?*/
package com.example.android.apis.app;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
import java.util.ArrayList;
// Need the following import to get access to the app resources, since this
// class is in a sub-package.
import com.example.android.apis.R;
import com.example.android.apis.app.RemoteService.Controller;
/**
?* This is an example of implementing an application service that uses the
?* {@link Messenger} class for communicating with clients. ?This allows for
?* remote interaction with a service, without needing to define an AIDL
?* interface.
?*
?* <p>Notice the use of the {@link NotificationManager} when interesting things
?* happen in the service. ?This is generally how background services should
?* interact with the user, rather than doing something more disruptive such as
?* calling startActivity().
?*/
public class MessengerService extends Service {
? ? /** For showing and hiding our notification. */
? ? NotificationManager mNM;
? ? /** Keeps track of all current registered clients. */
? ? ArrayList<Messenger> mClients = new ArrayList<Messenger>();
? ? /** Holds last value set by a client. */
? ? int mValue = 0;
? ? /**
? ? ?* Command to the service to register a client, receiving callbacks
? ? ?* from the service. ?The Message's replyTo field must be a Messenger of
? ? ?* the client where callbacks should be sent.
? ? ?*/
? ? static final int MSG_REGISTER_CLIENT = 1;
? ? /**
? ? ?* Command to the service to unregister a client, ot stop receiving callbacks
? ? ?* from the service. ?The Message's replyTo field must be a Messenger of
? ? ?* the client as previously given with MSG_REGISTER_CLIENT.
? ? ?*/
? ? static final int MSG_UNREGISTER_CLIENT = 2;
? ? /**
? ? ?* Command to service to set a new value. ?This can be sent to the
? ? ?* service to supply a new value, and will be sent by the service to
? ? ?* any registered clients with the new value.
? ? ?*/
? ? static final int MSG_SET_VALUE = 3;
? ? /**
? ? ?* Handler of incoming messages from clients.
? ? ?*/
? ? class IncomingHandler extends Handler {
? ? ? ? @Override
? ? ? ? public void handleMessage(Message msg) {
? ? ? ? ? ? switch (msg.what) {
? ? ? ? ? ? ? ? case MSG_REGISTER_CLIENT:
? ? ? ? ? ? ? ? ? ? mClients.add(msg.replyTo);
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case MSG_UNREGISTER_CLIENT:
? ? ? ? ? ? ? ? ? ? mClients.remove(msg.replyTo);
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case MSG_SET_VALUE:
? ? ? ? ? ? ? ? ? ? mValue = msg.arg1;
? ? ? ? ? ? ? ? ? ? for (int i=mClients.size()-1; i>=0; i--) {
? ? ? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? ? ? mClients.get(i).send(Message.obtain(null,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MSG_SET_VALUE, mValue, 0));
? ? ? ? ? ? ? ? ? ? ? ? } catch (RemoteException e) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? // The client is dead. ?Remove it from the list;
? ? ? ? ? ? ? ? ? ? ? ? ? ? // we are going through the list from back to front
? ? ? ? ? ? ? ? ? ? ? ? ? ? // so this is safe to do inside the loop.
? ? ? ? ? ? ? ? ? ? ? ? ? ? mClients.remove(i);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? super.handleMessage(msg);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? /**
? ? ?* Target we publish for clients to send messages to IncomingHandler.
? ? ?*/
? ? final Messenger mMessenger = new Messenger(new IncomingHandler());
? ? @Override
? ? public void onCreate() {
? ? ? ? mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
? ? ? ? // Display a notification about us starting.
? ? ? ? showNotification();
? ? }
? ? @Override
? ? public void onDestroy() {
? ? ? ? // Cancel the persistent notification.
? ? ? ? mNM.cancel(R.string.remote_service_started);
? ? ? ? // Tell the user we stopped.
? ? ? ? Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show();
? ? }
? ? /**
? ? ?* When binding to the service, we return an interface to our messenger
? ? ?* for sending messages to the service.
? ? ?*/
? ? @Override
? ? public IBinder onBind(Intent intent) {
? ? ? ? return mMessenger.getBinder();
? ? }
? ? /**
? ? ?* Show a notification while this service is running.
? ? ?*/
? ? private void showNotification() {
? ? ? ? // In this sample, we'll use the same text for the ticker and the expanded notification
? ? ? ? CharSequence text = getText(R.string.remote_service_started);
? ? ? ? // Set the icon, scrolling text and timestamp
? ? ? ? Notification notification = new Notification(R.drawable.stat_sample, text,
? ? ? ? ? ? ? ? System.currentTimeMillis());
? ? ? ? // The PendingIntent to launch our activity if the user selects this notification
? ? ? ? PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
? ? ? ? ? ? ? ? new Intent(this, Controller.class), 0);
? ? ? ? // Set the info for the views that show in the notification panel.
? ? ? ? notification.setLatestEventInfo(this, getText(R.string.remote_service_label),
? ? ? ? ? ? ? ? ? ? ? ?text, contentIntent);
? ? ? ? // Send the notification.
? ? ? ? // We use a string id because it is a unique number. ?We use it later to cancel.
? ? ? ? mNM.notify(R.string.remote_service_started, notification);
? ? }
}
?
MessengerServiceActivities.java(客戶端):
package com.example.android.apis.app;
import com.example.android.apis.R;
import com.example.android.apis.app.LocalServiceActivities.Binding;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MessengerServiceActivities {
? ? /**
? ? ?* Example of binding and unbinding to the remote service.
? ? ?* This demonstrates the implementation of a service which the client will
? ? ?* bind to, interacting with it through an aidl interface.</p>
? ? ?*
? ? ?* <p>Note that this is implemented as an inner class only keep the sample
? ? ?* all together; typically this code would appear in some separate class.
? ? ?*/
? ? public static class Binding extends Activity {
? ? ? ? /** Messenger for communicating with service. */
? ? ? ? Messenger mService = null;
? ? ? ? /** Flag indicating whether we have called bind on the service. */
? ? ? ? boolean mIsBound;
? ? ? ? /** Some text view we are using to show state information. */
? ? ? ? TextView mCallbackText;
? ? ? ? /**
? ? ? ? ?* Handler of incoming messages from service.
? ? ? ? ?*/
? ? ? ? class IncomingHandler extends Handler {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void handleMessage(Message msg) {
? ? ? ? ? ? ? ? switch (msg.what) {
? ? ? ? ? ? ? ? ? ? case MessengerService.MSG_SET_VALUE:
? ? ? ? ? ? ? ? ? ? ? ? mCallbackText.setText("Received from service: " + msg.arg1);
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? ? ? super.handleMessage(msg);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? /**
? ? ? ? ?* Target we publish for clients to send messages to IncomingHandler.
? ? ? ? ?*/
? ? ? ? final Messenger mMessenger = new Messenger(new IncomingHandler());
? ? ? ? /**
? ? ? ? ?* Class for interacting with the main interface of the service.
? ? ? ? ?*/
? ? ? ? private ServiceConnection mConnection = new ServiceConnection() {
? ? ? ? ? ? public void onServiceConnected(ComponentName className,
? ? ? ? ? ? ? ? ? ? IBinder service) {
? ? ? ? ? ? ? ? // This is called when the connection with the service has been
? ? ? ? ? ? ? ? // established, giving us the service object we can use to
? ? ? ? ? ? ? ? // interact with the service. ?We are communicating with our
? ? ? ? ? ? ? ? // service through an IDL interface, so get a client-side
? ? ? ? ? ? ? ? // representation of that from the raw service object.
? ? ? ? ? ? ? ? mService = new Messenger(service);
? ? ? ? ? ? ? ? mCallbackText.setText("Attached.");
? ? ? ? ? ? ? ? // We want to monitor the service for as long as we are
? ? ? ? ? ? ? ? // connected to it.
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? Message msg = Message.obtain(null,
? ? ? ? ? ? ? ? ? ? ? ? ? ? MessengerService.MSG_REGISTER_CLIENT);
? ? ? ? ? ? ? ? ? ? msg.replyTo = mMessenger;
? ? ? ? ? ? ? ? ? ? mService.send(msg);
? ? ? ? ? ? ? ? ? ? // Give it some value as an example.
? ? ? ? ? ? ? ? ? ? msg = Message.obtain(null,
? ? ? ? ? ? ? ? ? ? ? ? ? ? MessengerService.MSG_SET_VALUE, this.hashCode(), 0);
? ? ? ? ? ? ? ? ? ? mService.send(msg);
? ? ? ? ? ? ? ? } catch (RemoteException e) {
? ? ? ? ? ? ? ? ? ? // In this case the service has crashed before we could even
? ? ? ? ? ? ? ? ? ? // do anything with it; we can count on soon being
? ? ? ? ? ? ? ? ? ? // disconnected (and then reconnected if it can be restarted)
? ? ? ? ? ? ? ? ? ? // so there is no need to do anything here.
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? // As part of the sample, tell the user what happened.
? ? ? ? ? ? ? ? Toast.makeText(Binding.this, R.string.remote_service_connected,
? ? ? ? ? ? ? ? ? ? ? ? Toast.LENGTH_SHORT).show();
? ? ? ? ? ? }
? ? ? ? ? ? public void onServiceDisconnected(ComponentName className) {
? ? ? ? ? ? ? ? // This is called when the connection with the service has been
? ? ? ? ? ? ? ? // unexpectedly disconnected -- that is, its process crashed.
? ? ? ? ? ? ? ? mService = null;
? ? ? ? ? ? ? ? mCallbackText.setText("Disconnected.");
? ? ? ? ? ? ? ? // As part of the sample, tell the user what happened.
? ? ? ? ? ? ? ? Toast.makeText(Binding.this, R.string.remote_service_disconnected,
? ? ? ? ? ? ? ? ? ? ? ? Toast.LENGTH_SHORT).show();
? ? ? ? ? ? }
? ? ? ? };
? ? ? ? void doBindService() {
? ? ? ? ? ? // Establish a connection with the service. ?We use an explicit
? ? ? ? ? ? // class name because there is no reason to be able to let other
? ? ? ? ? ? // applications replace our component.
? ? ? ? ? ? bindService(new Intent(Binding.this,
? ? ? ? ? ? ? ? ? ? MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
? ? ? ? ? ? mIsBound = true;
? ? ? ? ? ? mCallbackText.setText("Binding.");
? ? ? ? }
? ? ? ? void doUnbindService() {
? ? ? ? ? ? if (mIsBound) {
? ? ? ? ? ? ? ? // If we have received the service, and hence registered with
? ? ? ? ? ? ? ? // it, then now is the time to unregister.
? ? ? ? ? ? ? ? if (mService != null) {
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? Message msg = Message.obtain(null,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MessengerService.MSG_UNREGISTER_CLIENT);
? ? ? ? ? ? ? ? ? ? ? ? msg.replyTo = mMessenger;
? ? ? ? ? ? ? ? ? ? ? ? mService.send(msg);
? ? ? ? ? ? ? ? ? ? } catch (RemoteException e) {
? ? ? ? ? ? ? ? ? ? ? ? // There is nothing special we need to do if the service
? ? ? ? ? ? ? ? ? ? ? ? // has crashed.
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? // Detach our existing connection.
? ? ? ? ? ? ? ? unbindService(mConnection);
? ? ? ? ? ? ? ? mIsBound = false;
? ? ? ? ? ? ? ? mCallbackText.setText("Unbinding.");
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? /**
? ? ? ? ?* Standard initialization of this activity. ?Set up the UI, then wait
? ? ? ? ?* for the user to poke it before doing anything.
? ? ? ? ?*/
? ? ? ? @Override
? ? ? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? ? ? setContentView(R.layout.messenger_service_binding);
? ? ? ? ? ? // Watch for button clicks.
? ? ? ? ? ? Button button = (Button)findViewById(R.id.bind);
? ? ? ? ? ? button.setOnClickListener(mBindListener);
? ? ? ? ? ? button = (Button)findViewById(R.id.unbind);
? ? ? ? ? ? button.setOnClickListener(mUnbindListener);
? ? ? ? ? ? mCallbackText = (TextView)findViewById(R.id.callback);
? ? ? ? ? ? mCallbackText.setText("Not attached.");
? ? ? ? }
? ? ? ? private OnClickListener mBindListener = new OnClickListener() {
? ? ? ? ? ? public void onClick(View v) {
? ? ? ? ? ? ? ? doBindService();
? ? ? ? ? ? }
? ? ? ? };
? ? ? ? private OnClickListener mUnbindListener = new OnClickListener() {
? ? ? ? ? ? public void onClick(View v) {
? ? ? ? ? ? ? ? doUnbindService();
? ? ? ? ? ? }
? ? ? ? };
? ? }
}
總結
以上是生活随笔為你收集整理的Android 绑定类型服务---使用信使(Messenger)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转载] 百科全说——漆浩:怎样健康饮茶
- 下一篇: NAS实现类型对比:统一式、网关式和横向