Android Api Demos登顶之路(五十五)Service Messenger Service

来源:互联网 发布:淘宝信用贷款在哪里查 编辑:程序博客网 时间:2024/05/22 14:38

这个demo演示了Messenger的用法。Messenger(信使),允许我们跨进程使用Handler处理消息。
* 我们先来简单分析一下使用信使实现服务端与客户端双向发送消息的基本思路
* 客户端向服务端发送消息:
1.在服务端构造一个Messenger,通过Messenger(Handler)的构造方法进行构造,handler用来处理从客户端发送过来的消息。
2.获取Messenger的IBinder并返回给客户端
3.客户端通过Messenger的另一个构造方法Messenger(IBinder)接收从服务端传递过来的Messenger。
4.调用Messenger的send方法就要以向服务端发送消息了。
服务端向客户端发送消息:
1.在客户端构造一个Messenger,使用Handler
2.通过Message的replyTo属性,将构造好的这个Messenger附加到Message身上。
3.当客户端向服务端发送Message时,客户端的这个Messenger实例也一同发送到了服务端
4.服务端通过解析Message的replyTo属性,获取到这个信使
5.尔后就可以使用这个信使的send方法向客户端发送消息了。
注意:运行时要先安装服务端,再安装客户端
服务端代码:

public class MessengerService extends Service {    // 定义一个信使集合,用于存放客户端传递过来的信使,每个信使与一个Handler相对应,    // 使用某个信使向客户端发送消息,客户端就会使用对应的Handler来处理这些消息    // 当我们在客户端使用Messenger(Handler)的构造方法构造一个Messenger时,Messenger与这个Handler就关联在一起了    private List<Messenger> clients = new ArrayList<Messenger>();    private NotificationManager mNM;    private int mValue;    // 定义从客户端发送过来的消息的类型    private static final int MSG_REGISTER_CLIENT = 1;    private static final int MSG_UNREGISTER_CLIENT = 2;    private static final int MSG_SET_VALUE = 3;    // 定义一个处理消息的类    private class IncomingHandler extends Handler {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {            case MSG_REGISTER_CLIENT:                clients.add(msg.replyTo);                break;            case MSG_UNREGISTER_CLIENT:                clients.remove(msg.replyTo);                break;            case MSG_SET_VALUE:                mValue = msg.arg1;                // 向所有客户端发送同样的消息                for (int i = 0; i < clients.size(); i++) {                    // 构造一条消息                    Message message = Message.obtain(null, MSG_SET_VALUE,                            mValue, 0);                    // 将这条消息发送给客户端                    try {                        clients.get(i).send(message);                    } catch (RemoteException e) {                        e.printStackTrace();                        // 出现异常则将这个信使删除                        clients.remove(i);                    }                }                break;            // 其余情况调用父类的方法,防止消息丢失            default:                super.handleMessage(msg);            }        }    }    // 构造信使    private Messenger mMessenger = new Messenger(new IncomingHandler());    @Override    public IBinder onBind(Intent intent) {        return mMessenger.getBinder();    }    @Override    public void onCreate() {        super.onCreate();        // 显示一个Notification        mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);        showNotification();    }    private void showNotification() {        Intent intent = new Intent(this, NotificationActivity.class);        PendingIntent contentintent = PendingIntent.getActivity(this, 0,                intent, PendingIntent.FLAG_CANCEL_CURRENT);        Notification.Builder builder = new Builder(this);        builder.setSmallIcon(R.drawable.ic_launcher).setTicker("服务已经启动")                .setContentTitle("Messenger Service")                .setContentText("通知服务端与客户端可以双向通讯了!")                .setContentIntent(contentintent)                .setWhen(System.currentTimeMillis());        Notification noti = builder.build();        mNM.notify(R.string.hello_world, noti);    }    @Override    public void onDestroy() {        super.onDestroy();        mNM.cancel(R.string.hello_world);        Toast.makeText(this, "服务已经停止", 0).show();    }}

在服务端还创建了一个简单的activity,用于当点击Notification时显示的界面:NotificationActivity

public class NotificationActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }}

服务端配置文件中的设置

<service             android:name="com.fishtosky.messengerservicedemo.MessengerService"            android:enabled="true"            android:exported="true">            <intent-filter >                <action android:name="com.fishtosky.aidl"/>                <category android:name="android.intent.category.DEFAULT"/>            </intent-filter>        </service>        <activity             android:name="com.fishtosky.messengerservicedemo.NotificationActivity"></activity>

客户端代码:MainActivity

public class MainActivity extends Activity {    public static final int MSG_SET_VALUE = 3;    private static final int MSG_UNREGISTER_CLIENT = 2;    private static final String SERVICE_ACTION = "com.fishtosky.aidl";    protected static final int MSG_REGISTER_CLIENT = 1;    private Messenger mService;    private boolean isBound;    private TextView state;    // 定义一个内部类,用于处理服务端发送过来的消息    class FromServiceHandler extends Handler {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {            case MSG_SET_VALUE:                state.setText("Received from Service:" + msg.arg1);                break;            default:                super.handleMessage(msg);            }        }    }    // 定义客户端的信使,可以利用这个信使向客户端发送消息    private Messenger clientMessenger = new Messenger(            new FromServiceHandler());    // 建立与服务端的连接    private ServiceConnection conn = new ServiceConnection() {        @Override        public void onServiceDisconnected(ComponentName name) {            mService = null;            state.setText("服务端与客户端的连接已断开!");        }        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            // 接收到从服务端传递过来的信使            mService = new Messenger(service);            state.setText("Attached.");            // 构造一条消息,在服务端注册该客户端的集合            try {                Message message = Message.obtain(null, MSG_REGISTER_CLIENT);                message.replyTo = clientMessenger;                mService.send(message);                // 发送一条带数据的信息                message = Message.obtain(null, MSG_SET_VALUE,                        this.hashCode(), 0);                mService.send(message);            } catch (RemoteException e) {                e.printStackTrace();            }            Toast.makeText(MainActivity.this, "服务端与客户端已经建立连接!", 0).show();        }    };    private void doBind() {        Intent intent = new Intent();        intent.setAction(SERVICE_ACTION);        bindService(intent, conn, Context.BIND_AUTO_CREATE);        isBound = true;        state.setText("服务已经开启");    }    private void doUnbind() {        if (isBound) {            //向服务端发送信号解除对信使的注册            if(mService!=null){                Message msg=Message.obtain(null, MSG_UNREGISTER_CLIENT);                try {                    msg.replyTo=clientMessenger;                    mService.send(msg);                } catch (RemoteException e) {                    e.printStackTrace();                }            }            unbindService(conn);            isBound = false;            state.setText("服务已经停止");        }    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        state=(TextView) findViewById(R.id.state);        Button bind=(Button) findViewById(R.id.bind);        Button unBind=(Button) findViewById(R.id.unbind);        state.setText("Not Attached");        bind.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                doBind();            }        });        unBind.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                doUnbind();            }        });    }}

客户端布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <TextView        android:textAppearance="?android:attr/textAppearanceMedium"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/hello_world" />    <Button         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:id="@+id/bind"        android:layout_gravity="center_horizontal"        android:text="Bind Service"/>    <Button         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:id="@+id/unbind"        android:layout_gravity="center_horizontal"        android:text="Unbind Service"/>    <TextView        android:textAppearance="?android:attr/textAppearanceMedium"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center_horizontal"        android:id="@+id/state" /></LinearLayout>
0 0