Service的总结(二)
来源:互联网 发布:淘宝直播好做吗 编辑:程序博客网 时间:2024/05/19 02:44
关于Service的概念,作用,生命周期,基本使用,IntentService的相关知识请查看Service的总结(一),这篇文章主要是关于使用Messenger实现进程间通信和aidl。
创建提供绑定的服务时,必须提供 IBinder,用以提供客户端用来与服务进行交互的编程接口。可以通过三种方法定义接口,扩展Binder类,使用Messenger和使用AIDL。
一.使用扩展Binder类
一般情况下,用于服务仅供本地应用使用,不需要跨进程的情况,这时可以实现扩展 Binder类,使客户端通过该类直接访问服务中的公共方法。
具体使用详见Service的总结(一)中的绑定服务。
二.使用Messenger类
一般情况下,用于服务与远程进程通信。Messenger底层是对AIDL进行的封装,用起来比AIDL简单。这是执行进程间通信 (IPC) 的最简单方法。
Messenger 通过Message传递消息实现交互,会在单一线程中创建包含所有请求的队列,几乎可以不用担心多线程可能会带来的问题。
1.步骤:
(1)服务端实现一个Handler,由其接受来自客户端的每个调用的回调。
(2)使用实现的Handler创建Messenger对象。
(3)通过Messenger得到一个IBinder对象,并将其通过onBind()返回给客户端。
(4)客户端使用 IBinder 将 Messenger(引用服务的 Handler)实例化,然后使用后者将 Message 对象发送给服务。
(5)服务端在其 Handler 中(具体地讲,是在 handleMessage() 方法中)接收每个 Message。
2.具体使用:
客户端和服务器之间进行通信:
(1)客户端MainAcitvity.java:
根据onServiceConnected中的IBinder可以获得服务器端的Messenger,通过此Messenger的send方法传递给服务器消息和数据。创建本地Messenger对象接收从服务器传递过来的消息和数据。
public class MainActivity extends Activity implements View.OnClickListener{ private static final String TAG = "client"; private Button bindBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initview(); } /** * 客户端的messenger */ private Messenger messenger = new Messenger(new Handler(){ @Override public void handleMessage(Message msg) { switch(msg.what){//接收从服务器发送过来的消息 case 0: String str = (String) msg.getData().get("message"); Log.d(TAG, "客户端收到消息handleMessage: "+str); break; } } }); /** * 服务端传过来的messenger */ private Messenger servicerMessenger; private void initview(){ bindBtn = (Button) this.findViewById(R.id.bind_service); bindBtn.setOnClickListener(this); } @Override public void onClick(View v) { switch(v.getId()){ case R.id.bind_service://绑定服务 Intent intent = new Intent(); intent.setAction("com.liuwei.ipc.test"); final Intent eintent = new Intent(createExplicitFromImplicitIntent(this,intent)); bindService(eintent, connection, BIND_AUTO_CREATE); break; } } ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) {//连接到服务 Log.d(TAG, "onServiceConnected: "); servicerMessenger = new Messenger(service); Message message = Message.obtain(); message.what = 1; message.replyTo = messenger;//客户端的messenger传递过去给服务器->客户端中的msg.replyTo Bundle bundle = new Bundle(); bundle.putString("message", "从客户端传递过来的消息"); message.setData(bundle); try { servicerMessenger.send(message);//客户端发送消息给服务器 } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "onServiceDisconnected: "); } }; @Override protected void onDestroy() { super.onDestroy(); unbindService(connection); } //隐式使用Intent public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) { // Retrieve all services that can match the given intent PackageManager pm = context.getPackageManager(); List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0); // Make sure only one match was found if (resolveInfo == null || resolveInfo.size() != 1) { return null; } // Get component info and create ComponentName ResolveInfo serviceInfo = resolveInfo.get(0); String packageName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceInfo.name; ComponentName component = new ComponentName(packageName, className); // Create a new intent. Use the old one for extras and such reuse Intent explicitIntent = new Intent(implicitIntent); // Set the component to be explicit explicitIntent.setComponent(component); return explicitIntent; }}
(2)服务器MessageBinderService.java:
创建服务器Messenger对象,在onbind中返回messenger.getBinder()传递给客户端,使用服务器Messenger构造出来的Handler接收从客户端发送过来的消息和数据,使用msg.replayTo.send(message)给客户端发送数据。
public class MessageBinderService extends Service { private Messenger messenger = new Messenger(new Handler(){ @Override public void handleMessage(Message msg) { switch(msg.what){//收到从客户端发送过来的消息 case 1: String str = (String) msg.getData().get("message"); Log.d("Service", "服务器收到消息handleMessage: "+str); Message message = Message.obtain(); message.what = 0; Bundle bundle = new Bundle(); bundle.putString("message", "从服务器发送数据"); message.setData(bundle); try { msg.replyTo.send(message);//从服务器发送数据,msg.replyTo是客户端Messenger } catch (RemoteException e) { e.printStackTrace(); } break; } } }); @Nullable @Override public IBinder onBind(Intent intent) { return messenger.getBinder(); }}
注册Service:
<service android:exported="true" android:enabled="true" android:name=".MessageBinderService"> <intent-filter> <action android:name="com.liuwei.ipc.test"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service>
从以上可以看出来:服务器和客户端有各自的Messenger对象,通过onbind返回给客户端服务器Messenger对象,通过客户端给服务器发送消息时的message.replyTo可以将客户端的Messenger传递给服务器,以此来实现两者之间的通信。
说明:
此处说明一个问题:在客户端代码中绑定服务使用的是
Intent intent = new Intent(); intent.setAction("com.liuwei.ipc.test"); final Intent eintent = new Intent(createExplicitFromImplicitIntent(this,intent)); bindService(eintent, connection, BIND_AUTO_CREATE);
而不是直接隐式调用
Intent intent = new Intent();intent.setAction("com.liuwei.ipc.test");bindService(intent, connection, BIND_AUTO_CREATE);
是因为在运行demo时出现了 IllegalArgumentException: Service Intent must be explicit错误,需要显式声明。
经查找相关资料使用上述解决办法。
参考:http://blog.csdn.net/shenzhonglaoxu/article/details/42675287
三.使用AIDL(Android Interface Definition Languag/Android 接口定义语言)
AIDL实现进程间的通信,尤其是用于有并发处理问题的需求,或者会有大量的并发请求。
步骤:
(1)在B应用中创建.aidl文件。
(2)在B应用中通过Stub实现aidl文件生成的接口。
(3)在B应用中创建一个Service,在服务的onBind()方法中返回实现了aidl接口的Binder对象。
(4)把B应用中aidl文件所在package连同aidl文件一起拷贝到客户端A应用。
(5)在A中绑定服务,在onServiceConnected方法中通过服务器传递过来的Binder对象得到aidl接口实例,通过调用实例的方法可以实现不同应用之间的通信。
具体使用:
以传递User对象为例进行说明:
1.对于服务器:
第一:创建aidl文件:
步骤:
(1)在main目录下新建aidl文件夹,在aidl文件夹下新建IUser.aidl文件,Studio会生成默认的aidl文件和包路径。
(2)在java目录包路径下新建User类,必须实现Parcelable序列化。
关于序列化请查看
http://www.jianshu.com/p/a60b609ec7e7
(3)在IUser.aidl同级目录下新建User.aidl文件,里面标明User所在的包和实现Parcelable。
(4)修改IUser.aidl文件,导入User类,根据需求写入所需要交互的接口。
效果:
User.java:
public class User implements Parcelable{ private String name; private int age; private User(Parcel in){ name = in.readString(); age = in.readInt(); } public User(String name, int age){ this.name = name; this.age = age; } public static final Creator<User> CREATOR = new Creator<User>() { @Override public User createFromParcel(Parcel source) { return new User(source); } @Override public User[] newArray(int size) { return new User[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeInt(age); }}
User.aidl:
package com.example.liuwei.aidlserver;parcelable User;
IUser.aidl:
package com.example.liuwei.aidlserver;import com.example.liuwei.aidlserver.User;interface IUser { List<User> getUser(); void addUser(in User user);}
其中addUser中参数前面有in,表示由客户端传入参数。
参数前面必须写有in,out或是inout。
in:参数由客户端设置,由客户端传入参数值。
out:参数由服务端设置,由服务端返回值。
inout:客户端输入端都可以设置。
注意:User对象类所在文件目录在java下,不能在aidl目录下。否则编译会报错,找不到User类。
此问题参考:http://blog.csdn.net/sacco90725/article/details/42104085
第二:创建Service:
自定义MyService继承Service,创建Binder对象实现AIDL的接口文件中的方法并在onbind方法中返回。
public class MyService extends Service{ private List<User> users = new ArrayList<>(); @Nullable @Override public IBinder onBind(Intent intent) { return stub; } IUser.Stub stub = new IUser.Stub() { @Override public List<User> getUser() throws RemoteException { return users; } @Override public void addUser(User user) throws RemoteException { if(!users.contains(user)){ users.add(user); } } };}
在清单文件中注册服务:
<service android:name=".MyService"> <intent-filter> <action android:name="com.liuwei.myService"></action> </intent-filter> </service>
2.对于客户端:
第一:创建aidl文件:
把上述服务器中aidl文件所在package连同aidl文件一起拷贝到客户端中,包括IUser.aidl,User.aidl,User.java,所在包和上述服务器时保持一致。如下所示:
第二:绑定服务,实现客户端和服务器交互:
使用bindService绑定服务,并在onServiceConnected方法中调用IUser.Stub.asInterface(service)这个方法通过服务端onBind方法返回的binder对象得到IUser的实例,调用它的方法,实现交互。
public class MainActivity extends Activity implements View.OnClickListener{ private static final String TAG = "client"; private IUser stub; private Button bind_btn; private Button unbind_btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView(){ bind_btn = (Button)this.findViewById(R.id.bind_service); unbind_btn = (Button) this.findViewById(R.id.unbind_service); bind_btn.setOnClickListener(this); unbind_btn.setOnClickListener(this); } ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "onServiceConnected: "); stub = IUser.Stub.asInterface(service); User user = new User("test", 12); try { stub.addUser(user); } catch (RemoteException e) { e.printStackTrace(); } Log.d(TAG, "onServiceConnected: users"+user.toString()); } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "onServiceDisconnected: "); } }; @Override public void onClick(View v) { switch(v.getId()){ case R.id.bind_service: Intent intent = new Intent(); intent.setAction("com.liuwei.myService"); bindService(createExplicitFromImplicitIntent(this, intent), connection, BIND_AUTO_CREATE); break; case R.id.unbind_service: unbindService(connection); break; } } public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) { // Retrieve all services that can match the given intent PackageManager pm = context.getPackageManager(); List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0); // Make sure only one match was found if (resolveInfo == null || resolveInfo.size() != 1) { return null; } // Get component info and create ComponentName ResolveInfo serviceInfo = resolveInfo.get(0); String packageName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceInfo.name; ComponentName component = new ComponentName(packageName, className); // Create a new intent. Use the old one for extras and such reuse Intent explicitIntent = new Intent(implicitIntent); // Set the component to be explicit explicitIntent.setComponent(component); return explicitIntent; }}
运行结果:
完整代码请点击这里。
- Service的总结(二)
- service的用法总结(二)
- Service总结(二)
- 基础总结之二:Service
- android的一些总结——service(二)之activity与service之间的通信
- Service的使用二
- Service的全面总结
- Service的总结
- Android 中的 Service 全面总结(二)
- Android四大组件之二:Service总结
- Android Service的总结,service, bindservice,intentservice
- android的Service学习二
- Android Service的全面总结
- linux的service相关总结
- Web Service 的一些总结
- 关于Service的一些总结
- Android的Service全面总结
- Android service的全面总结
- java基础:关于String类
- 克隆
- 集深v5迁移至润乾5问题总结
- 装了虚拟机之后,出现的两个网卡vmware1和vmware8
- php简单网站的登录和注册怎么写
- Service的总结(二)
- require开发:requirejs教程(一)
- [美团 CodeM 复赛]神秘代号
- lvm入门
- Win10中内置Linux更换阿里源
- OSAL NV区操作
- 【图像配准】基于互信息的图像配准算法:MI、EMI、ECC算法
- 什么是四层和七层反向代理
- qt布局问题