北京建网站找哪个公司,运城网站开发,外贸网站设计公司价格,什么网站能免费做推广4.2.3 Service精通 分类 Android 基础入门教程 本节引言#xff1a; 本节#xff0c;我们继续来研究Service(服务)组件#xff0c;本节将会学习下Android中的AIDL跨进程通信的一些 概念#xff0c;并不深入到源码层次#xff0c;暂时知道是什么#xff0c;会用即可假如你使用的是Android Studio的话不同于Eclipse如果你按照Eclipse那样创建一个AIDL文件会发现 并没有编译生成对应的XXX.java文件AS下创建AIDL需要在main目录下新建一个aidl文件夹然后定义一个 和aidl包名相同的包最后创建一个aidl文件接着按ctrl f9重新编译就可以了上面两者成功编译的结果如下你可以分别在对应目录下找到对应的AIDL文件1.服务端Step 1创建AIDL文件IPerson.aidlpackage com.jay.aidl; interface IPerson { String queryPerson(int num); }我们打开IPerson.java看看里面的代码IPerson.java/* * This file is auto-generated. DO NOT MODIFY. * Original file: C:\\Code\\ASCode\\AIDLServer\\app\\src\\main\\aidl\\com\\jay\\aidl\\IPerson.aidl */ package com.jay.aidl; public interface IPerson extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.jay.aidl.IPerson { private static final java.lang.String DESCRIPTOR com.jay.aidl.IPerson; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.jay.aidl.IPerson interface, * generating a proxy if needed. */ public static com.jay.aidl.IPerson asInterface(android.os.IBinder obj) { if ((objnull)) { return null; } android.os.IInterface iin obj.queryLocalInterface(DESCRIPTOR); if (((iin!null)(iin instanceof com.jay.aidl.IPerson))) { return ((com.jay.aidl.IPerson)iin); } return new com.jay.aidl.IPerson.Stub.Proxy(obj); } Override public android.os.IBinder asBinder() { return this; } Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_queryPerson: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 data.readInt(); java.lang.String _result this.queryPerson(_arg0); reply.writeNoException(); reply.writeString(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.jay.aidl.IPerson { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote remote; } Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } Override public java.lang.String queryPerson(int num) throws android.os.RemoteException { android.os.Parcel _data android.os.Parcel.obtain(); android.os.Parcel _reply android.os.Parcel.obtain(); java.lang.String _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(num); mRemote.transact(Stub.TRANSACTION_queryPerson, _data, _reply, 0); _reply.readException(); _result _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_queryPerson (android.os.IBinder.FIRST_CALL_TRANSACTION 0); } public java.lang.String queryPerson(int num) throws android.os.RemoteException; }这里我们关注的只是**asInterface(IBinder)**和我们定义的接口中的**queryPerson()**方法!该方法会把IBinder类型的对象转换成IPerson类型的,必要时生成一个代理对象返回结果其他的我们可以不看直接跳过进行下一步。Step 2**自定义我们的Service类,完成下述操作:1)继承Service类,同时也自定义了一个PersonQueryBinder类用来继承IPerson.Stub类就是实现了IPerson接口和IBinder接口2)实例化自定义的Stub类,并重写Service的onBind方法,返回一个binder对象!AIDLService.javapackage com.jay.aidlserver; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import com.jay.aidl.IPerson.Stub; /** * Created by Jay on 2015/8/18 0018. */ public class AIDLService extends Service { private IBinder binder new PersonQueryBinder(); private String[] names {B神,艹神,基神,J神,翔神}; private String query(int num) { if(num 0 num 6){ return names[num - 1]; } return null; } Override public IBinder onBind(Intent intent) { return null; } private final class PersonQueryBinder extends Stub{ Override public String queryPerson(int num) throws RemoteException { return query(num); } } }Step 3在AndroidManifest.xml文件中注册Serviceservice android:name.AIDLService intent-filter action android:nameandroid.intent.action.AIDLService / category android:nameandroid.intent.category.DEFAULT / /intent-filter /service这里我们并没有提供Activity界面但是改应用提供的Service可以供其他app来调用2.客户端直接把服务端的那个aidl文件复制过来然后我们直接在MainActivity中完成和绑定本地Service的操作有点类似流程如下1)自定义PersonConnection类实现ServiceConnection接口2)以PersonConnection对象作为参数,调用bindService绑定远程ServicebindService(service,conn,BIND_AUTO_CREATE);ps:第三个参数是设置如果服务没有启动的话,自动创建3)和本地Service不同绑定远程Service的ServiceConnection并不能直接获取Service的onBind( )方法返回的IBinder对象只能返回onBind( )方法所返回的代理对象需要做如下处理:iPerson IPerson.Stub.asInterface(service);再接着完成初始化,以及按钮事件等就可以了具体代码如下MainActivity.javapackage com.jay.aidlclient; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import com.jay.aidl.IPerson; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private EditText edit_num; private Button btn_query; private TextView txt_name; private IPerson iPerson; private PersonConnection conn new PersonConnection(); Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bindViews(); //绑定远程Service Intent service new Intent(android.intent.action.AIDLService); service.setPackage(com.jay.aidlserver); bindService(service, conn, BIND_AUTO_CREATE); btn_query.setOnClickListener(this); } private void bindViews() { edit_num (EditText) findViewById(R.id.edit_num); btn_query (Button) findViewById(R.id.btn_query); txt_name (TextView) findViewById(R.id.txt_name); } Override public void onClick(View v) { String number edit_num.getText().toString(); int num Integer.valueOf(number); try { txt_name.setText(iPerson.queryPerson(num)); } catch (RemoteException e) { e.printStackTrace(); } edit_num.setText(); } private final class PersonConnection implements ServiceConnection { public void onServiceConnected(ComponentName name, IBinder service) { iPerson IPerson.Stub.asInterface(service); } public void onServiceDisconnected(ComponentName name) { iPerson null; } } }接下来先启动AIDLServivce然后再启动AIDLClient输入查询序号即可获得对应姓名 当然也可以直接启动AIDLClient也会获得同样效果效果图如下3传递复杂数据的AIDL Service上面的例子我们传递的只是要给int类型的参数然后服务端返回一个String类型的参数看似满足 我们的基本需求不过实际开发中我们可能需要考虑传递复杂数据类型的情况下面我们来学习下 如何向服务端传递复杂数据类型的数据开始之前我们先来了解Parcelable接口——Parcelable接口简介相信用过序列化的基本上都知道这个接口了除了他还有另外一个Serializable同样是用于序列化的 只是Parcelable更加轻量级速度更快但是写起来就有点麻烦了当然如果你用的as的话可以用 的插件来完成序列化比如Android Parcelable Code Generator当然这里我们还是手把手教大家来实现这个接口~首先需要实现writeToParcel和readFromPacel方法 写入方法将对象写入到包裹(parcel)中,而读取方法则从包裹中读取对象, 请注意,写入属性顺序需与读取顺序相同接着需要在该类中添加一个名为CREATOR的static final属性 改属性需要实现android.os.Parcelable.Creator接口再接着需要从写接口中的两个方法createFromParcel(Parcel source)方法:实现从source创建出JavaBean实例的功能newArray(int size):创建一个类型为T,长度为size的数组,只有一个简单的return new T[size]; (这里的T是Person类)最后describeContents():这个我也不知道是拿来干嘛的,直接返回0即可不用理他——另外非原始类型中除了String和CharSequence以外其余均需要一个方向指示符。 方向指示符包括in、out、和inout。in表示由客户端设置out表示由服务端设置inout表示客户端和服务端都设置了该值。好的接着来写代码试试(AS这里自定义类型有点问题暂时还没解决就用回Eclipse~)代码示例自定义两种对象类型:Person与Salary,Person作为调用远程的Service的参数,Salary作为返回值! 那么首先要做的就是创建Person与Salary类,同时需要实现Parcelable接口1.——服务端Step 1创建Person.aidl和Salary.aidl的文件因为他们需要实现Parcelable接口所以就下面一条语句Person.aidl: parcelable Person; Salary.aidl: parcelable Salary;Step 2分别建立Person类与Salary类需实现Parcelable接口重写对应的方法!PS:因为我们后面是根据Person对象来获取Map集合中的数据,所以Person.java中我们重写了hashcode和equals 的方法;而Salary类则不需要!Person.java:package com.jay.example.aidl; import android.os.Parcel; import android.os.Parcelable; /** * Created by Jay on 2015/8/18 0018. */ public class Person implements Parcelable{ private Integer id; private String name; public Person() {} public Person(Integer id, String name) { this.id id; this.name name; } public Integer getId() { return id; } public void setId(Integer id) { this.id id; } public void setName(String name) { this.name name; } public String getName() { return name; } //实现Parcelable必须实现的方法,不知道拿来干嘛的,直接返回0就行了 Override public int describeContents() { return 0; } //写入数据到Parcel中的方法 Override public void writeToParcel(Parcel dest, int flags) { //把对象所包含的数据写入到parcel中 dest.writeInt(id); dest.writeString(name); } //必须提供一个名为CREATOR的static final属性 该属性需要实现 //android.os.Parcelable.CreatorT接口 public static final Parcelable.CreatorPerson CREATOR new Parcelable.CreatorPerson() { //从Parcel中读取数据,返回Person对象 Override public Person createFromParcel(Parcel source) { return new Person(source.readInt(),source.readString()); } Override public Person[] newArray(int size) { return new Person[size]; } }; //因为我们集合取出元素的时候是根据Person对象来取得,所以比较麻烦, //需要我们重写hashCode()和equals()方法 Override public int hashCode() { final int prime 31; int result 1; result prime * result ((name null) ? 0 : name.hashCode()); return result; } Override public boolean equals(Object obj) { if (this obj) return true; if (obj null) return false; if (getClass() ! obj.getClass()) return false; Person other (Person) obj; if (name null) { if (other.name ! null) return false; } else if (!name.equals(other.name)) return false; return true; } } prepstrongSalary.java/strong~照葫芦画瓢/p pre package com.jay.example.aidl; import android.os.Parcel; import android.os.Parcelable; /** * Created by Jay on 2015/8/18 0018. */ public class Salary implements Parcelable { private String type; private Integer salary; public Salary() { } public Salary(String type, Integer salary) { this.type type; this.salary salary; } public String getType() { return type; } public Integer getSalary() { return salary; } public void setType(String type) { this.type type; } public void setSalary(Integer salary) { this.salary salary; } Override public int describeContents() { return 0; } Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(type); dest.writeInt(salary); } public static final Parcelable.CreatorSalary CREATOR new Parcelable.CreatorSalary() { //从Parcel中读取数据,返回Person对象 Override public Salary createFromParcel(Parcel source) { return new Salary(source.readString(), source.readInt()); } Override public Salary[] newArray(int size) { return new Salary[size]; } }; public String toString() { return 工作: type 薪水: salary; } }Step 3创建一个ISalary.aidl的文件在里面写一个简单的获取工资信息的方法package com.jay.example.aidl; import com.jay.example.aidl.Salary; import com.jay.example.aidl.Person; interface ISalary { //定义一个Person对象作为传入参数 //接口中定义方法时,需要制定新参的传递模式,这里是传入,所以前面有一个in Salary getMsg(in Person owner); }ps:这里可以记得如果使用的是自定义的数据类型的话,需要import哦切记Step 4核心Service的编写 定义一个SalaryBinder类继承Stub,从而实现ISalary和IBinder接口;定义一个存储信息的Map集合! 重新onBind方法,返回SalaryBinder类的对象实例!AidlService.javapackage com.jay.example.aidl_complexservice; import java.util.HashMap; import java.util.Map; import com.jay.example.aidl.ISalary.Stub; import com.jay.example.aidl.Person; import com.jay.example.aidl.Salary; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; public class AidlService extends Service { private SalaryBinder salaryBinder; private static MapPerson,Salary ss new HashMapPerson, Salary(); //初始化Map集合,这里在静态代码块中进行初始化,当然你可也以在构造方法中完成初始化 static { ss.put(new Person(1, Jay), new Salary(码农, 2000)); ss.put(new Person(2, GEM), new Salary(歌手, 20000)); ss.put(new Person(3, XM), new Salary(学生, 20)); ss.put(new Person(4, MrWang), new Salary(老师, 2000)); } Override public void onCreate() { super.onCreate(); salaryBinder new SalaryBinder(); } Override public IBinder onBind(Intent intent) { return salaryBinder; } //同样是继承Stub,即同时实现ISalary接口和IBinder接口 public class SalaryBinder extends Stub { Override public Salary getMsg(Person owner) throws RemoteException { return ss.get(owner); } } Override public void onDestroy() { System.out.println(服务结束); super.onDestroy(); } }注册下Service:service android:name.AidlService intent-filter action android:nameandroid.intent.action.AIDLService / category android:nameandroid.intent.category.DEFAULT / /intent-filter /service2——客户端编写Step 1把服务端的AIDL文件拷贝下拷贝后目录如下Step 2编写简单的布局,再接着就是核心MainActvitiy的实现了 定义一个ServciceConnection对象,重写对应方法,和前面的普通数据的类似 再接着在bindService,然后再Button的点击事件中获取Salary对象并显示出来MainActivity.javapackage com.jay.example.aidl_complexclient; import com.jay.example.aidl.ISalary; import com.jay.example.aidl.Person; import com.jay.example.aidl.Salary; import android.app.Activity; import android.app.Service; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends Activity { private ISalary salaryService; private Button btnquery; private EditText editname; private TextView textshow; private ServiceConnection conn new ServiceConnection() { Override public void onServiceDisconnected(ComponentName name) { salaryService null; } Override public void onServiceConnected(ComponentName name, IBinder service) { //返回的是代理对象,要调用这个方法哦! salaryService ISalary.Stub.asInterface(service); } }; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnquery (Button) findViewById(R.id.btnquery); editname (EditText) findViewById(R.id.editname); textshow (TextView) findViewById(R.id.textshow); Intent it new Intent(); it.setAction(com.jay.aidl.AIDL_SERVICE); bindService(it, conn, Service.BIND_AUTO_CREATE); btnquery.setOnClickListener(new OnClickListener() { Override public void onClick(View v) { try { String name editname.getText().toString(); Salary salary salaryService.getMsg(new Person(1,name)); textshow.setText(name salary.toString()); }catch(RemoteException e){e.printStackTrace();} } }); } Override protected void onDestroy() { super.onDestroy(); this.unbindService(conn); } }运行截图PS这里的代码是之前用Eclipse写的代码Android Studio下自定义类型有点问题 暂时没找到解决方法如果知道的朋友请告知下万分感激 出现的问题如下两个实例的代码下载(基于Eclipse的)1)使用AIDL完成进程间的简单通信2传递复杂数据的AIDL Service的实现3.直接通过Binder的onTransact完成跨进程通信上面讲过Android可以通过Binder的onTrensact方法来完成通信下面就来简单试下下还是前面那个根据 序号查询名字的例子服务端实现/** * Created by Jay on 2015/8/18 0018. */ public class IPCService extends Service{ private static final String DESCRIPTOR IPCService; private final String[] names {B神,艹神,基神,J神,翔神}; private MyBinder mBinder new MyBinder(); private class MyBinder extends Binder { Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code){ case 0x001: { data.enforceInterface(DESCRIPTOR); int num data.readInt(); reply.writeNoException(); reply.writeString(names[num]); return true; } } return super.onTransact(code, data, reply, flags); } } Override public IBinder onBind(Intent intent) { return mBinder; } }客户端实现public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private EditText edit_num; private Button btn_query; private TextView txt_result; private IBinder mIBinder; private ServiceConnection PersonConnection new ServiceConnection() { Override public void onServiceDisconnected(ComponentName name) { mIBinder null; } Override public void onServiceConnected(ComponentName name, IBinder service) { mIBinder service; } }; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bindViews(); //绑定远程Service Intent service new Intent(android.intent.action.IPCService); service.setPackage(com.jay.ipcserver); bindService(service, PersonConnection, BIND_AUTO_CREATE); btn_query.setOnClickListener(this); } private void bindViews() { edit_num (EditText) findViewById(R.id.edit_num); btn_query (Button) findViewById(R.id.btn_query); txt_result (TextView) findViewById(R.id.txt_result); } Override public void onClick(View v) { int num Integer.parseInt(edit_num.getText().toString()); if (mIBinder null) { Toast.makeText(this, 未连接服务端或服务端被异常杀死, Toast.LENGTH_SHORT).show(); } else { android.os.Parcel _data android.os.Parcel.obtain(); android.os.Parcel _reply android.os.Parcel.obtain(); String _result null; try{ _data.writeInterfaceToken(IPCService); _data.writeInt(num); mIBinder.transact(0x001, _data, _reply, 0); _reply.readException(); _result _reply.readString(); txt_result.setText(_result); edit_num.setText(); }catch (RemoteException e) { e.printStackTrace(); } finally { _reply.recycle(); _data.recycle(); } } } }运行截图代码比较简单就不多解释了~用到自己改改即可PS:代码参考于:Android aidl Binder框架浅析4.Android 5.0后Service一些要注意的地方今天在隐式启动Service的时候遇到这样一个问题然后程序一启动就崩了,后来苦扣良久才发下是Android 5.0惹的祸 原来5.0后有个新的特性就是Service Intent must be explitict好吧就是不能隐式去启动Service咯解决的方法也很简单 比如StartService的startService(new Intent(getApplicationContext(), com.aaa.xxxserver));这样写程序直接crash掉要写成下面这样startService(new Intent(getApplicationContext(), LoadContactsService.class));如果是BindService的Intent service new Intent(android.intent.action.AIDLService);的基础上要加上包名service.setPackage(com.jay.ipcserver);这样就可以了~官方文档http://developer.android.com/intl/zh-cn/guide/components/intents-filters.html#Types 文档说明处:本节小结好的关于Service的最后一节就到这里本节讲解了Binder的基本概念以及实现进程间通信的 两种方式通过AIDL以及Binder.onTransact()来实现跨进程通信最后还讲解了下Android 5.0后 使用Service不能隐式启动的注意事项就到这里谢谢~