Android 基础入门教程4.2.3 Service精通
4.2.3 Service精通分类Android 基础入门教程本节引言本节我们继续来研究Service(服务)组件本节将会学习下Android中的AIDL跨进程通信的一些 概念并不深入到源码层次暂时知道是什么会用即可开始本节内容~ 本节对应官方文档Binder1.Binder机制初涉1IBinder和Binder是什么鬼我们来看看官方文档怎么说中文翻译IBinder是远程对象的基本接口是饿了高性能而设计的轻量级远程调用机制的核心部分。但他 不仅用于远程调用也用于进程内调用。该接口定义了与远程对象间交互的协议。但不要直接实现 这个接口而是继承(extends)Binder。IBinder主要的API是transact()与之对应的API是Binder.onTransact()。通过前者你能 想远程IBinder对象发送发出调用后者使你的远程对象能够响应接收到的调用。IBinder的API都是Syncronous(同步)执行的比如transact()直到对方的Binder.onTransact()方法调用玩 后才返回。 调用发生在进程内时无疑是这样的而在进程间时在IPC的帮助下也是同样的效果。通过transact()发送的数据是ParcelParcel是一种一般的缓冲区除了有数据外还带有 一些描述它内容的元数据。元数据用于管理IBinder对象的引用这样就能在缓冲区从一个进程移动 到另一个进程时保存这些引用。这样就保证了当一个IBinder被写入到Parcel并发送到另一个进程中 如果另一个进程把同一个IBinder的引用回发到原来的进程那么这个原来的进程就能接收到发出的 那个IBinder的引用。这种机制使IBinder和Binder像唯一标志符那样在进程间管理。系统为每个进程维护一个存放交互线程的线程池。这些交互线程用于派送所有从另外进程发来的IPC 调用。例如当一个IPC从进程发到进程中那个发出调用的线程(这个应该不在线程池中)就阻塞 在transact()中了。进程中的交互线程池中的一个线程接收了这个调用它调用Binder.onTransact()完成后用一个Parcel来做为结果返回。然后进程中的那个等待的线程在 收到返回的Parcel后得以继续执行。实际上另一个进程看起来就像是当前进程的一个线程 但不是当前进程创建的。Binder机制还支持进程间的递归调用。例如进程执行自己的IBinder的transact()调用进程 的Binder而进程在其Binder.onTransact()中又用transact()向进程发起调用那么进程 在等待它发出的调用返回的同时还会用Binder.onTransact()响应进程的transact()。 总之Binder造成的结果就是让我们感觉到跨进程的调用与进程内的调用没什么区别。当操作远程对象时你经常需要查看它们是否有效有三种方法可以使用 transact()方法将在IBinder所在的进程不存在时抛出RemoteException异常。 如果目标进程不存在那么调用pingBinder()时返回false。 可以用linkToDeath()方法向IBinder注册一个IBinder.DeathRecipient 在IBinder代表的进程退出时被调用。PS:中文翻译摘自 : Android开发什么是IBinder好吧估计你看完上这一串东西可能云里雾里的这里简单的小结下IBinder是Android给我们提供的一个进程间通信的一个接口而我们一般是不直接实现这个接口的而是通过继承Binder类来实现进程间通信是Android中实现IPC(进程间通信)的一种方式2Binder机制浅析Android中的Binder机制由一系列系统组件构成Client、Server、Service Manager和Binder驱动程序大概调用流程如下另外Service Manager比较复杂这里并不详细研究流程解析-Client调用某个代理接口中的方法时代理接口的方法会将Client传递的参数打包成Parcel对象-然后代理接口把该Parcel对象发送给内核中的Binder driver-然后Server会读取Binder Driver中的请求数据假如是发送给自己的解包Parcel对象 处理并将结果返回PS:代理接口中的定义的方法和Server中定义的方法是一一对应的 另外整个调用过程是一个同步的即Server在处理时Client会被Block(锁)住! 而这里说的代理接口的定义就是等下要说的AIDL(Android接口描述语言)3为何Android使用Binder机制来实现进程间的通信可靠性在移动设备上通常采用基于Client-Server的通信方式来实现互联网与设备间的内部通信。目前linux支持IPC包括传统的管道System V IPC即消息队列/共享内存/信号量以及socket中只有socket支持Client-Server的通信方式。Android系统为开发者提供了丰富进程间通信的功能接口媒体播放传感器无线传输。这些功能都由不同的server来管理。开发都只关心将自己应用程序的client与server的通信建立起来便可以使用这个服务。毫无疑问如若在底层架设一套协议来实现Client-Server通信增加了系统的复杂性。在资源有限的手机 上来实现这种复杂的环境可靠性难以保证。传输性能socket主要用于跨网络的进程间通信和本机上进程间的通信但传输效率低开销大。消息队列和管道采用存储-转发方式即数据先从发送方缓存区拷贝到内核开辟的一块缓存区中然后从内核缓存区拷贝到接收方缓存区其过程至少有两次拷贝。虽然共享内存无需拷贝但控制复杂。比较各种IPC方式的数据拷贝次数。共享内存0次。Binder1次。Socket/管道/消息队列2次。安全性Android是一个开放式的平台所以确保应用程序安全是很重要的。Android对每一个安装应用都分配了UID/PID,其中进程的UID是可用来鉴别进程身份。传统的只能由用户在数据包里填写UID/PID这样不可靠容易被恶意程序利用。而我们要求由内核来添加可靠的UID。 所以出于可靠性、传输性、安全性。android建立了一套新的进程间通信方式。 ——摘自:Android中的Binder机制的简要理解当然作为一个初级的开发者我们并不关心上述这些Binder机制给我们带来的最直接的好处就是我们无需关心底层如何实现只需按照AIDL的规则自定义一个接口文件然后调用调用接口中的方法就可以完成两个进程间的通信了2.AIDL使用详解1AIDL是什么嘿嘿前面我们讲到IPC这个名词他的全名叫做跨进程通信(interprocess communication) 因为在Android系统中,个个应用程序都运行在自己的进程中,进程之间一般是无法直接进行数据交换的, 而为了实现跨进程Android给我们提供了上面说的Binder机制而这个机制使用的接口语言就是:AIDL(Android Interface Definition Language)他的语法很简单而这种接口语言并非真正的编程 语言只是定义两个进程间的通信接口而已而生成符合通信协议的Java代码则是由Android SDK的 platform-tools目录下的aidl.exe工具生成生成对应的接口文件在:gen目录下一般是:Xxx.java的接口 而在该接口中包含一个Stub的内部类该类中实现了在该类中实现了IBinder接口与自定义的通信接口, 这个类将会作为远程Service的回调类——实现了IBinder接口,所以可作为Service的onBind( )方法的返回值2AIDL实现两个进程间的简单通信在开始编写AIDL接口文件前我们需要了解下编写AIDL的一些注意事项AIDL注意事项接口名词需要与aidl文件名相同接口和方法前面不要加访问权限修饰符public ,private,protected等也不能用static final!AIDL默认支持的类型包括Java基本类型StringListMapCharSequence除此之外的其他类型都 需要import声明对于使用自定义类型作为参数或者返回值自定义类型需要实现Parcelable接口 详情请看后面的传递复杂数据类型自定义类型和AIDL生成的其它接口类型在aidl描述文件中应该显式import即便在该类和定义 的包在同一个包中。另外如果编写aidl你用的编译器是:Eclipse的话要注意 不要直接new file然后建立哦!这样的话是打不开文件,从而不能编写代码哦①直接新建一个txt文件,编写好后保存为.aidl格式,然后复制到对应路径下②因为aidl和接口类似,所以直接new interface,编写好内容后,来到对应java文件所在目录下修改文件后缀名;假如你使用的是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不能隐式启动的注意事项就到这里谢谢~

相关新闻

好写作AI:学术党的“规范护卫队”,让导师少叹气,让查重不找你!

好写作AI:学术党的“规范护卫队”,让导师少叹气,让查重不找你!

正在被论文折磨的你,是不是也经历过这些“至暗时刻”? 明明读了十几篇文献,写进论文却像“学术裁缝”,自己都心虚; 导师的修改意见上写着:“表述不规范”、“引用格式混乱”、“这里太口语化”——每个字都…

2026/5/17 3:36:27 阅读更多 →
应用更新机制的设计与实践:从问题到价值的完整解决方案

应用更新机制的设计与实践:从问题到价值的完整解决方案

应用更新机制的设计与实践:从问题到价值的完整解决方案 【免费下载链接】Kazumi 基于自定义规则的番剧采集APP,支持流媒体在线观看,支持弹幕。 项目地址: https://gitcode.com/gh_mirrors/ka/Kazumi 你知道吗?在移动应用开…

2026/5/17 3:36:26 阅读更多 →
Mac NTFS写入权限零成本解决方案:从诊断到精通的全流程指南

Mac NTFS写入权限零成本解决方案:从诊断到精通的全流程指南

Mac NTFS写入权限零成本解决方案:从诊断到精通的全流程指南 【免费下载链接】Free-NTFS-for-Mac Nigate,一款支持苹果芯片的Free NTFS for Mac小工具软件。NTFS R/W for macOS. Support Intel/Apple Silicon now. 项目地址: https://gitcode.com/gh_mi…

2026/5/17 3:36:25 阅读更多 →

最新新闻

STM32F303RE扩展EEPROM存储方案与优化实践

STM32F303RE扩展EEPROM存储方案与优化实践

1. 为什么需要扩展存储空间在嵌入式系统开发中,STM32F303RE这类微控制器虽然内置了Flash和SRAM,但实际项目经常会遇到存储空间不足的问题。我最近在做一个工业数据采集项目时就深有体会——需要长时间记录设备运行参数,但MCU内部的256KB Flas…

2026/7/4 12:02:48 阅读更多 →
智能散热系统设计:基于DRV8213与PID控制的嵌入式解决方案

智能散热系统设计:基于DRV8213与PID控制的嵌入式解决方案

1. 项目背景与核心组件选型 在嵌入式电子系统设计中,散热管理一直是工程师面临的关键挑战。特别是在汽车电子、医疗设备等对温度敏感的应用场景中,过热可能导致系统性能下降甚至硬件损坏。本项目采用DRV8213电机驱动器、MF25060V2-1000U-A99散热风扇和PI…

2026/7/4 12:02:48 阅读更多 →
Windows任务栏透明化神器:5种模式彻底改变你的桌面体验

Windows任务栏透明化神器:5种模式彻底改变你的桌面体验

Windows任务栏透明化神器:5种模式彻底改变你的桌面体验 【免费下载链接】TranslucentTB A lightweight utility that makes the Windows taskbar translucent/transparent. 项目地址: https://gitcode.com/gh_mirrors/tr/TranslucentTB 你是否厌倦了Windows任…

2026/7/4 12:00:48 阅读更多 →
量子傅里叶变换在多光子干涉测量中的高效应用

量子傅里叶变换在多光子干涉测量中的高效应用

1. 量子傅里叶变换在多光子干涉基准测试中的突破性进展在量子光学实验中,多光子干涉现象是量子计算和量子通信的核心基础。想象一下,当多个完全相同的光子同时进入一个光学系统时,它们会像训练有素的芭蕾舞者一样完美同步地舞动,产…

2026/7/4 12:00:48 阅读更多 →
MiniMax-M2.7 + DMXAPI:轻量级大模型调用新范式

MiniMax-M2.7 + DMXAPI:轻量级大模型调用新范式

1. 项目概述:这不是“又一个API接口”,而是大模型调用链路的轻量化重构 最近在多个技术群和开发者论坛里, MiniMax-M2.7 这个名字出现频率陡增——不是作为论文里的新架构,也不是某家大厂发布会上的PPT配图,而是真实…

2026/7/4 12:00:48 阅读更多 →
MLOps实战:从Notebook到生产环境的模型服务化与可观测性

MLOps实战:从Notebook到生产环境的模型服务化与可观测性

1. 项目概述:当模型走出Jupyter,真正开始养家糊口 “From Notebook to Production: Running ML in the Real World (Part 4)”——这个标题里藏着一个被无数数据科学家反复咀嚼、又悄悄咽下的现实:我们花了80%的时间调参、画图、写 print(mo…

2026/7/4 11:58:47 阅读更多 →

日新闻

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 正式发布,这是一个关键的安全修复版本,修复了多个方面的问题,还对部分功能进行了优化。 安全修复亮点 此次发布在安全修复上表现突出。binprot 避免了项目引用计数溢出,mcmc 因安全问题提升了上游版本号&#xf…

2026/7/4 0:04:29 阅读更多 →
终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL HMCL(Hello Minecraft! Lau…

2026/7/4 0:06:29 阅读更多 →
KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

1. KMX63与PIC18F66K40的硬件协同架构解析KMX63作为一款三轴加速度计和磁力计组合传感器,与PIC18F66K40微控制器的搭配堪称嵌入式HMI开发的黄金组合。这套硬件组合的核心优势在于KMX63提供的高精度运动感知能力与PIC18F66K40强大的信号处理能力形成了完美互补。KMX6…

2026/7/4 0:06:29 阅读更多 →

周新闻

月新闻