目录
 
startServic
bindService
AIDL和Messenger区别
IntentService
AIDL
startServic
Service的创建
 1) 创建一个类继承Service,当然子类也可以例如IntentService.重写方法:onCreate(): 
 在每个service的生命周期中这个方法会且仅会调用一次,并且它的调用在onStartCommand()以及onBind()之前,我们可以在这个方法中进行一些一次性的初始化工作。onStartCommand(): 
 其他组件通过startService()启动service,就会调用这个方法,service的主要操作就在这里.onBind(): 
 其他组件通过bindService()进行绑定Service,就会调用这个方法.这个方法返回一个IBinder,这意味重写的时候必须返回一个IBinder对象,这个IBinder是用来支撑其他组件和Service通信.假如不希望被绑定,返回一个Null就可以了.onDestory(): 
 这是service一生中调用的最后一个方法,当这个方法被调用之后,service就会被销毁。所以我们应当在这个方法里面进行一些资源的清理,比如注册的一些监听器什么的。2)注册
一般我们用名字在Mainfest文件进行声明就好了. 
 属性介绍:android:enabled : 如果为true,则这个service可以被系统实例化,如果为false,则不行。默认为true
android:exported : 如果为true,则其他应用的组件也可以调用这个service并且可以与它进行互动,如果为false,则只有与service同一个应用或者相同user ID的应用可以开启或绑定此service。它的默认值取决于service是否有intent filters。如果一个filter都没有,就意味着只有指定了service的准确的类名才能调用,也就是说这个service只能应用内部使用——其他的应用不知道它的类名。这种情况下exported的默认值就为false。反之,只要有了一个filter,就意味着service是考虑到外界使用的情况的,这时exported的默认值就为true
android:icon : 一个象征着这个service的icon
android:isolatedProcess : 如果设置为true,这个service将运行在一个从系统中其他部分分离出来的特殊进程中,我们只能通过Service API来与它进行交流。默认为false。
android:label : 显示给用户的这个service的名字。如果不设置,将会默认使用的label属性。
android:name : 这个service的路径名,例如“com.lypeer.demo.MyService”。这个属性是唯一一个必须填的属性。
android:permission : 其他组件必须具有所填的权限才能启动这个service。
android:process : service运行的进程的name。默认启动的service是运行在主进程中的。
启动Service
 startServicbindService
 首先我们来说明一下,就是说这个bindService是一种比startService复杂的方式,不过这个BindService的交互比startService更加复杂.
客户端配置
 调用bindService()方法.public boolean bindService(Intent service, ServiceConnection conn, int flags) {
     return mBase.bindService(service, conn, flags);
 }
 参数分析:参数一:intent,指定启动哪一个service以及传递一些数据过去
参数二:ServiceConnection 通信的关键类 
 重写两个回调方法: 
 onServiceConnected(): 
 目的获取返回的IBinder接口,类似一个代理类的作用,然后通过这个代理类去获取Service,然后调用其内部的方法.onServiceDisconnected() 
 Android系统会在与服务的连接意外中断时(例如当服务崩溃或被终止时)调用该方法。当客户端取消绑定时,系统“绝对不会”调用该方法。参数三:int值,它是一个指示绑定选项的标志,通常应该是 BIND_AUTO_CREATE,以便创建尚未激活的服务。 其他可能的值为 BIND_DEBUG_UNBIND 和 BIND_NOT_FOREGROUND,或 0(表示无)。
服务端配置
 根据上面绑定的Service需求,需要重写OnBind(),返回一个IBinder接口对象,用于交互.获取IBinder接口
 IBinder接口的,一个在整个Android系统中都非常重要的东西,是为高性能而设计的轻量级远程调用机制的核心部分.它不仅仅是内部调用,也可以远程调用. 
 我们只要记住一个重点:Binder类对象,客户端可以通过这个类似代理类的方式调用服务端的共有方法.1)继承Binder类(同一个进程间的) 
 1. service类中创建一个Binder实例(重点在于公共方法) 
 1) 包含客户端可调用的公共方法 
 2) 返回当前Service实例,其中有公共方法 
 3) 由当前service承载的其他类的实例,其中包含客户端可调用的公共方法 
 方式一:OnBind()方法返回这个Binder实例.
 客户端通过onServiceDisconnected(),接受这个对象,使用这个方法.2)使用Messenger 
 Messenger核心是Message以及Handler进行线程间通信. 
 步骤:服务端实现一个Handler,接受客户端的调用的回调. 服务端创建Messenger对象通过Messenger得到IBinder对象,返回给客户端.
 客户端使用IBinder将Messenger实例化,然后将Message对象发给服务.
 服务端Handler接受Message对象,然后实现对应方法.
 这种是利用了Handler和Message的机制.    //服务端
     public class MessengerServiceDemo extends Service {        static final int MSG_SAY_HELLO = 1;
        class ServiceHandler extends Handler {
             @Override
             public void handleMessage(Message msg) {
                 switch (msg.what) {
                     case MSG_SAY_HELLO:
                         //当收到客户端的message时,显示hello
                         Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
                         break;
                     default:
                         super.handleMessage(msg);
                 }
             }
         }    final Messenger mMessenger = new Messenger(new ServiceHandler());
    @Nullable
     @Override
     public IBinder onBind(Intent intent) {
         Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
         //返回给客户端一个IBinder实例
         return mMessenger.getBinder();
     }
 }
 这里最主要的方法是我们需要在OnBind上面下功夫,要知道Messenger是可以关联Handler,并且可以返回IBinder的.当然,这里因为是跨进程通讯的,所以要让别的应用知道怎么找到我们Service.就是在注册文件上做文章.
       <service  android:name=".ActivityMessenger" android:enabled="true" android:exported="true">
         <intent-filter>
             <action android:name="com.lypeer.messenger"></action>
             <category android:name="android.intent.category.DEFAULT"/>
         </intent-filter>
     </service>
 客户端:  public class ActivityMessenger extends Activity {
        static final int MSG_SAY_HELLO = 1;
        Messenger mService = null;
         boolean mBound;        private ServiceConnection mConnection = new ServiceConnection() {
             public void onServiceConnected(ComponentName className, IBinder service) {
                 //接收onBind()传回来的IBinder,并用它构造Messenger
                 mService = new Messenger(service);
                 mBound = true;
             }            public void onServiceDisconnected(ComponentName className) {
                 mService = null;
                 mBound = false;
             }
         };        //调用此方法时会发送信息给服务端
         public void sayHello(View v) {
             if (!mBound) return;
             //发送一条信息给服务端
             Message msg = Message.obtain(null, 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.activity_main);
         }        @Override
         protected void onStart() {
             super.onStart();
             //绑定服务端的服务,此处的action是service在Manifests文件里面声明的
             Intent intent = new Intent();
             intent.setAction("com.lypeer.messenger");
             //不要忘记了包名,不写会报错
             intent.setPackage("com.lypeer.ipcserver");
             bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
         }        @Override
         protected void onStop() {
             super.onStop();
             // Unbind from the service
             if (mBound) {
                 unbindService(mConnection);
                 mBound = false;
             }
         }
     }
 细节: 
 1) 首先我们需要注意在OnCreate()上面,对Intent做文章,要设置包名,毕竟是跨进程. 
 2) onServiceConnected()方法获取服务端返回的IBinder,构造Messenger,然后通过Messenger发送Message进行交互. 
 3)Messenger是一个信使.AIDL和Messenger区别
 这么说,Messenger的内部实现还是AIDL. 
 Messnger好处:它会把所有的请求排入队列,因此你几乎可以不用担心多线程可能会带来的问题。但是只能实现串行的信息交互. 
 AIDL:可以令项目中存在大量的并发交互.IntentService
 默认情况下service将工作于应用的主线程,而这将会降低所有正在运行的Activity的性能。而IntentService就不同了.
 不需要担心多线程问题,会自动请求停止服务,但是不绑定,会有一个工作队列.
 特色: 创建默认的工作线程,用于在应用的主线程外执行传递给 onStartCommand() 的所有 Intent
onHandleIntent() 实现,这样的话就永远不必担心多线程问题了
处理完所有启动请求后停止服务,从此再也不用担心我忘记调用 stop() 了
 提供 onBind() 的默认实现(返回 null)
 提供 onStartCommand() 的默认实现,可将 Intent 依次发送到工作队列和 onHandleIntent() 实现
 因此我们只需要实现onHandleIntent()方法来完成具体的功能逻辑就可以了。
 例子:    public class IntentServiceDemo extends IntentService {
        public IntentServiceDemo(String name) {
             super(name);
             //构造方法
         }        @Override
         protected void onHandleIntent(Intent intent) {
             //在这里根据intent进行操作
         }
     }接受Intent,会根据Intent进行操作,但是主要要是重写其他方法,就不要删除超类实现,而且不能处理多个请求.
  AIDL
 这个语言的目的是为了实现进程间通信. 在一个进程访问另外一个进程的数据,还有调用特定的方法.
特点:
文件类型: .aidl文件
数据类型:  AIDL默认支持一些数据类型.非默认数据使用前必须导包.使用对象也需要导包.
   默认:
   Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。
   String 类型。
   CharSequence类型。
   List类型:List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable(下文关于这个会有详解)。List可以使用泛型。
   Map类型:Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。Map是不支持泛型的。定向Tag:除非是基本类型和String ,CharSequence.这些是默认的in
 in:客户端流向服务端
 out:服务端流向客户端
 inout:双向流动
 大约思路:
 客户端传递对象信息给客户端,服务端改动,客户端就会改动.AIDL类型:
 1) 定义parcelable对象,以供其他AIDL文件使用AIDL中非默认支持的数据类型的。
 2) 定义方法接口,以供系统使用来完成跨进程通信的.定义接口,里面都是方法.注意AIDL我们在乎的是定义并非实现.
 AIDL的实现:
 1) 实现Parcelable接口,目的是为了我们传送的数据能够在内存之间流通.过程可以说是序列化和反序列化. 
 客户端–>序列化对象–>服务端—>反序列化对象如何快速生成一个可序列化类?目的是为了我们的操作对象能够传. 
 注意:假如是默认就不需要这样了.编译器生成: 
 1. Bean类(成员变量,set,get); 
 2. 实现Parcelable接口,主动解决错误.(alt+enter) 
 3. 注意,因为默认是in定向tag,所以只有写出的这么一个方法,假如需要其他就添加.  @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(name);
         dest.writeInt(price);
     }    /**
      * 参数是一个Parcel,用它来存储与传输数据
      * @param dest
      */
     public void readFromParcel(Parcel dest) {
         //注意,此处的读值顺序应当是和writeToParcel()方法中一致的
         name = dest.readString();
         price = dest.readInt();
     }
 2)书写AIDL 
 Book.aild文件引入后,就能让其他类使用这么一个对象.AS: 
 AIDL:直接生成,写好接口. 
 但是AS的文件路径需要我们处理一下,因为AS上面有分成Aidl包.这时候aidl文件就不能跟自己的.java文件对应了.(因为我们要求文件的报名要一样.) 
 因为我们的工具是自动到java下找java文件,我们要将java文件放到aidl包的的方式.修改 build.gradle 文件:在 android{} 中间加上下面的内容:
  sourceSets {
      main {
          java.srcDirs = ['src/main/java', 'src/main/aidl']
      }
     }
 但是目录很难看.3)移植文件 
 我们必须保证客户端服务端都有对应的.aidl和.java文件. 
 直接复制aidl包就可以了.4)编写服务端代码 
 文件移植之后,假如我们clean,编译器就会根据AIDL文件生成.java文件.在服务端实现具体的方法,然后客户端调用方法接口.AIDL文件的结构: 
 1. 初始化 
 2. 重写Stub类中的方法,这其中有AIDL的方法接口的具体逻辑,可以说是引入AIDL文件生成的对象. 
 3. OnBind(),返回Stub代理类5)编写客户端代码. 
 1. 初始化AIDL生成的java类对象 
 2. 通过Intent进行bindService绑定. 
 3. Conn就利用Stub作为对象类.调用其中的方法.AIDL本质工作:
 1) AIDL目的是为了让编译器帮我们生成一个.java文件 
 2) 生成的.java文件会有一个类似Stub的代理类,服务端重写了之前AIDL中定义的方法,就是这个Stub中的方法,并且通过OnBind()返回. 
 3) 客户端捕获这个对象然后调用.我们的分析从应用开始: 
 1. 使用的是.java文件,但是它是一个接口类.实际我们调用的是它的一个实现类.获取的方法是通过BookManager.Stub.asInterface(BinderProxy 对象)方法获取. 
 2. BinderProxy是实现了BookManager接口的一个类,也就是我们上文使用的这么一个类.它是经过搜查得到的.也是我们最终需要进行交互的一个类.而Proxy的方法工作流程: 
 1,生成 _data 和 _reply 数据流,并向 _data 中存入客户端的数据。 
 2,通过 transact() 方法将它们传递给服务端,并请求服务端调用指定方法。 
 3,接收 _reply 数据流,并从中取出服务端传回来的数据。客户端–>存入_data–>transact()–>传给服务器–>reply()–>服务器返回的数据.
服务端分析
 .java文件中有个方法onTransact(),负责接收传递过来的信息. 
 工作流程: 
 1,获取客户端传过来的数据,根据方法 ID 执行相应操作。 
 2,将传过来的数据取出来,调用本地写好的对应方法。 
 3,将需要回传的数据写入 reply 流,传回客户端。总结: 
 客户端<–>代理<–>服务端 
 其中我们的过程就是一个通过代理进行交互的过程.