美文网首页
Service的总结

Service的总结

作者: fastcv | 来源:发表于2019-06-22 17:03 被阅读0次

    前言

    Service作为Android中最神秘的四大组件之一,它的中文意思是服务,在手机中,代表着手机的后台,许多耗时的操作,可以在里面运行,为用户交互提供了更便捷的方法,那么,对于Service,我们应该掌握哪些基本知识呢?(结合大佬们的博客总结的,如有侵权,麻烦联系我删除此文章))

    生命周期

    生命周期图

    image

    生命周期调用解析

    从图中可以看出,service有两种启动方式

    首先,我们新建一个Service

    public class TestService extends Service {
    
        @Override
        public void onCreate() {
            super.onCreate();
            show("onCreate");
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            show("onBind");
            return null;
        }
    
        @Override
        public void onStart(Intent intent, int startId) {
            super.onStart(intent, startId);
            show("onStart");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            show("onStartCommand");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            show("onDestroy");
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            show("onUnbind");
            return super.onUnbind(intent);
        }
    
        @Override
        public void onRebind(Intent intent) {
            super.onRebind(intent);
            show("onRebind");
        }
    
        private void show(String mes){
            LogUtil.log("Service1:"+mes);
        }
    }
    

    1、StartService()启动Service

    实例代码如下:

    //启动Service
    intent.setClass(this, TestService.class);
    startService(intent);
    
    //停止Service
    stopService(intent);
    

    点击3次start和1次stop的执行结果

    2019-06-22 16:23:03.955 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onCreate
    2019-06-22 16:23:03.958 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onStartCommand
    2019-06-22 16:23:03.958 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onStart
    2019-06-22 16:23:09.098 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onStartCommand
    2019-06-22 16:23:09.098 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onStart
    2019-06-22 16:23:10.268 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onStartCommand
    2019-06-22 16:23:10.269 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onStart
    2019-06-22 16:23:13.553 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onDestroy
    

    从这次试验中,我们可以看出,直接启动Service时,第一次会调用

    graph LR
    onCreate-->onStartCommand
    

    然后再次点击启动时,只会调用 onStartCommand , 而其中的onBinder则未被调用,点击stop后,服务则停止了。

    2、BindService()启动Service

    在生命周期中,我们看到了,onbind属于另外一种启动方式,那我们现在来看下这个如何实现。

    实例代码如下:

    //绑定Service
    intent.setClass(this, TestService.class);
    bindService(intent,connection,BIND_AUTO_CREATE);
    
    //接触绑定
    unbindService(connection);
    

    同样的,点击3次bind和1次unbind的执行结果为:

    2019-06-22 16:27:53.066 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onCreate
    2019-06-22 16:27:53.074 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onBind
    2019-06-22 16:27:59.028 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onUnbind
    2019-06-22 16:27:59.030 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onDestroy
    

    从这次试验中,我们可以看出,直接绑定Service时,第一次会调用

    graph LR
    onCreate-->onBind
    

    然后再次点击bind时,不会再调用任何方法, 而其中的onStartCommand则未被调用,点击unbind后,服务则接触绑定且停止了。

    3、先启动,后绑定

    有时候,需要中途去绑定到某个服务,这个时候就是先启动再绑定的情况了。

    我们先点击启动,然后绑定,然后停止,最后解绑的执行结果为:

    2019-06-22 16:33:12.994 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onCreate
    2019-06-22 16:33:12.996 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onStartCommand
    2019-06-22 16:33:12.996 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onStart
    2019-06-22 16:33:15.221 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onBind
    /**  点击停止无效  **/
    2019-06-22 16:33:19.512 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onUnbind
    2019-06-22 16:33:19.513 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onDestroy
    

    我们先点击启动,然后绑定,然后解绑,最后停止的执行结果为:

    2019-06-22 16:34:02.135 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onCreate
    2019-06-22 16:34:02.137 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onStartCommand
    2019-06-22 16:34:02.137 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onStart
    2019-06-22 16:34:03.755 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onBind
    2019-06-22 16:34:05.044
    /**  点击解绑   **/
    21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onUnbind
    /**  点击停止  **/
    2019-06-22 16:34:06.469 21356-21356/sayhallo.cn.ilikeandroid E/LOG_: Service1:onDestroy
    

    从这次试验中,我们可以看出,在绑定的情况下,是无法直接停止Service的,只能先解绑再停止.

    附加说明

    1、多线程、线程、程序和进程的区别

    • 程序:为了完成特定任务,用某种语言编写的一组指令集合(一组静态代码)
    • 进程:运行中的程序,系统调度与资源分配的一个独立单位,操作系统会 为每个进程分配一段内存空间!程序的依次动态执行,经历代码的加载,执行, 执行完毕的完整过程!
    • 线程:比进程更小的执行单元,每个进程可能有多条线程,线程需要放在一个 进程中才能执行,线程由程序负责管理,而进程则由系统进行调度!
    • 多线程的理解:并行执行多个条指令,将CPU时间片按照调度算法分配给各个 线程,实际上是分时执行的,只是这个切换的时间很短,用户感觉到"同时"而已!

    2、Service和线程的区别

    Thread是线程,程序执行的最小单元,分配CPU的基本单位! 而Service则是Android提供一个允许长时间留驻后台的一个组件,最常见的 用法就是做轮询操作!或者想在后台做一些事情,比如后台下载更新,并且Service是运行在主线程上的,做耗时任务时,还是需要开启子线程去做。Service不是一个单独的进程,它和它的应用程序在同一个进程中;Service不是一个线程,这样也意味着我们应该避免在Service中进行耗时操作

    这里,就出现了IntentService

    IntentService

    如果我们直接把 耗时线程放到Service中的onStart()方法中,虽然可以这样做,但是很容易 会引起ANR异常(Application Not Responding)

    工作流程

    客户端通过startService(Intent)来启动IntentService; 我们并不需要手动地区控制IntentService,当任务执行完后,IntentService会自动停止; 可以启动IntentService多次,每个耗时操作会以工作队列的方式在IntentService的 onHandleIntent回调方法中执行,并且每次只会执行一个工作线程,执行完一,再到二这样!

    如:

    public class TestIntentService extends IntentService {
       
        public TestIntentService() {
            super("HAHAHA");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            String param = intent.getExtras().getString("param");
            switch (param){
                case "s1":{
                    XhLogUtil.i("启动1");
                }
                break;
                case "s2":{
                    XhLogUtil.i("启动2");
                }
                break;
                case "s3":{
                    XhLogUtil.i("启动3");
                }
                break;
            }
    
            //让服务休眠2秒
            try{
                Thread.sleep(2000);
            }catch(InterruptedException e){e.printStackTrace();}
        }
    
        //重写其他方法,用于查看方法的调用顺序
        @Override
        public IBinder onBind(Intent intent) {
            XhLogUtil.i("onBind");
            return super.onBind(intent);
        }
    
        @Override
        public void onCreate() {
            XhLogUtil.i("onCreate");
            super.onCreate();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            XhLogUtil.i("onStartCommand");
            return super.onStartCommand(intent, flags, startId);
        }
    
    
        @Override
        public void setIntentRedelivery(boolean enabled) {
            super.setIntentRedelivery(enabled);
            XhLogUtil.i("setIntentRedelivery");
        }
    
        @Override
        public void onDestroy() {
            XhLogUtil.i("onDestroy");
            super.onDestroy();
        }
    }
    

    MainActivity

    Intent intent1 = new Intent(this, TestIntentService.class);
                    Bundle b1 = new Bundle();
                    b1.putString("param", "s1");
                    intent1.putExtras(b1);
    
                    Intent intent2 = new Intent(this, TestIntentService.class);
                    Bundle b2 = new Bundle();
                    b2.putString("param", "s2");
                    intent2.putExtras(b2);
    
                    Intent intent3 = new Intent(this, TestIntentService.class);
                    Bundle b3 = new Bundle();
                    b3.putString("param", "s3");
                    intent3.putExtras(b3);
    
                    //接着启动多次IntentService,每次启动,都会新建一个工作线程
                    //但始终只有一个IntentService实例
                    startService(intent1);
                    startService(intent2);
                    startService(intent3);
    

    执行结果

    11-27 02:49:36.109 12916-12916/com.example.mywidget I/HeiBug: onCreate
    11-27 02:49:36.112 12916-12916/com.example.mywidget I/HeiBug: onStartCommand
    11-27 02:49:36.112 12916-12976/com.example.mywidget I/HeiBug: 启动1
    11-27 02:49:36.112 12916-12916/com.example.mywidget I/HeiBug: onStartCommand
    11-27 02:49:36.113 12916-12916/com.example.mywidget I/HeiBug: onStartCommand
    11-27 02:49:38.115 12916-12976/com.example.mywidget I/HeiBug: 启动2
    11-27 02:49:40.116 12916-12976/com.example.mywidget I/HeiBug: 启动3
    11-27 02:49:42.118 12916-12916/com.example.mywidget I/HeiBug: onDestroy
    

    从运行结果可以看出:

    当一个后台的任务,需要分成几个子任务,然后按先后顺序执行,子任务 (简单的说就是异步操作),此时如果我们还是定义一个普通Service然后 在onStart方法中开辟线程,然后又要去控制线程,这样显得非常的繁琐; 此时应该自定义一个IntentService然后再onHandleIntent()方法中完成相关任务!

    3、待补充...

    学完了它的生命周期的调用之后,我们发现,这里面有个绑定的操作,还有个叫做bind的东西,它们到底是用来做什么的呢?我们去学习一下(一下是转载某位大佬的文章的内容,如需删除,请联系我删除)

    Binder机制

    IBinder是远程对象的基本接口,是为了高性能而设计的轻量级远程调用机制的核心部分。但它不仅用于远程调用,也用于进程内调用。该接口定义了与远程对象间交互的协议。但不要直接实现 这个接口,而是继承(extends)Binder。

    IBinder主要的API是transact(),与之对应的API是Binder.onTransact()。通过前者,你能 想远程IBinder对象发送发出调用,后者使你的远程对象能够响应接收到的调用。IBinder的API都是 Syncronous(同步)执行的,比如transact()直到对方的Binder.onTransact()方法调用玩 后才返回。 调用发生在进程内时无疑是这样的,而在进程间时,在IPC的帮助下,也是同样的效果。

    通过transact()发送的数据是Parcel,Parcel是一种一般的缓冲区,除了有数据外还带有 一些描述它内容的元数据。元数据用于管理IBinder对象的引用,这样就能在缓冲区从一个进程移动 到另一个进程时保存这些引用。这样就保证了当一个IBinder被写入到Parcel并发送到另一个进程中, 如果另一个进程把同一个IBinder的引用回发到原来的进程,那么这个原来的进程就能接收到发出的 那个IBinder的引用。这种机制使IBinder和Binder像唯一标志符那样在进程间管理。

    系统为每个进程维护一个存放交互线程的线程池。这些交互线程用于派送所有从另外进程发来的IPC 调用。例如:当一个IPC从进程A发到进程B,A中那个发出调用的线程(这个应该不在线程池中)就阻塞 在transact()中了。进程B中的交互线程池中的一个线程接收了这个调用,它调用 Binder.onTransact(),完成后用一个Parcel来做为结果返回。然后进程A中的那个等待的线程在 收到返回的Parcel后得以继续执行。实际上,另一个进程看起来就像是当前进程的一个线程, 但不是当前进程创建的。

    Binder机制还支持进程间的递归调用。例如,进程A执行自己的IBinder的transact()调用进程B 的Binder,而进程B在其Binder.onTransact()中又用transact()向进程A发起调用,那么进程A 在等待它发出的调用返回的同时,还会用Binder.onTransact()响应进程B的transact()。 总之Binder造成的结果就是让我们感觉到跨进程的调用与进程内的调用没什么区别。

    作用

    Binder能干什么?Binder可以提供系统中任何程序都可以访问的全局服务。这个功能当然是任何系统都应该提供的,下面我们简单看一下Android的Binder的框架

    Android Binder框架分为服务器接口、Binder驱动、以及客户端接口;简单想一下,需要提供一个全局服务,那么全局服务那端即是服务器接口,任何程序即客户端接口,它们之间通过一个Binder驱动访问。

    服务器端接口:实际上是Binder类的对象,该对象一旦创建,内部则会启动一个隐藏线程,会接收Binder驱动发送的消息,收到消息后,会执行Binder对象中的onTransact()函数,并按照该函数的参数执行不同的服务器端代码。

    Binder驱动:该对象也为Binder类的实例,客户端通过该对象访问远程服务。

    客户端接口:获得Binder驱动,调用其transact()发送消息至服务器

    实现

    说这么多,我们先写个小demo来实验下

    1、程序内,拿到bind对象,调用bind对象的方法

    首先,我们新建我们的bind类

    public class MessageBind extends Binder implements ChatListener {
    
        public WebClient webClient = null;
        Gson gson = new Gson();
    
        public MessageBind() {
            webClient = WebClient.getInstance();
            LogUtil.d("WebClient---->得到连接");
        }
    
        @Override
        public void sendMessage(Message message){
            webClient.send(gson.toJson(message));
            LogUtil.d("发送消息:"+message.toString());
        }
    
        public void close(int code){
            webClient.close(code);
        }
    }
    

    然后,我们在onbind中得到它

     public IBinder onBind(Intent intent) {
            LogUtil.d("绑定聊天服务....成功");
            bind = new MessageBind();
            return bind;
        }
    

    最后,我们在Activity中去调用bind的方法

     private MessageBind binder;
    
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            binder = (MessageBind) service;
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
    }
    };
      
    //调用  
    binder.sendMessage(message);
    

    2、依赖AIDL实现程序间通讯

    首先在as中新建一个AIDL文件

    interface ICalcAIDL
    {
        int add(int x , int y);
        int min(int x , int y );
    }
    

    然后,写个Service

    public class CalcService extends Service {
        private static final String TAG = "server";
    
        public void onCreate()
        {
            Log.e(TAG, "onCreate");
        }
    
        public IBinder onBind(Intent t)
        {
            Log.e(TAG, "onBind");
            return mBinder;
        }
    
        public void onDestroy()
        {
            Log.e(TAG, "onDestroy");
            super.onDestroy();
        }
    
        public boolean onUnbind(Intent intent)
        {
            Log.e(TAG, "onUnbind");
            return super.onUnbind(intent);
        }
    
        public void onRebind(Intent intent)
        {
            Log.e(TAG, "onRebind");
            super.onRebind(intent);
        }
    
        private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub()
        {
    
            @Override
            public int add(int x, int y) throws RemoteException
            {
                return x + y;
            }
    
            @Override
            public int min(int x, int y) throws RemoteException
            {
                return x - y;
            }
    
        };
    }
    

    记得注册

    <service android:name="com.example.aidlserver.CalcService" >
                <intent-filter>
                    <action android:name="com.zhy.aidl.calc" />
    
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </service>
    

    这样,我们的服务端就写好了,接下来写客户端

    <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" >
    
        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:onClick="bindService"
            android:text="BindService" />
    
        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:onClick="unbindService"
            android:text="UnbindService" />
    
        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:onClick="addInvoked"
            android:text="12+12" />
    
        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:onClick="minInvoked"
            android:text="50-12" />
    
    </LinearLayout>
    

    MainActivity

    public class MainActivity extends AppCompatActivity {
    
        private ICalcAIDL mCalcAidl;
    
        private ServiceConnection mServiceConn = new ServiceConnection()
        {
            @Override
            public void onServiceDisconnected(ComponentName name)
            {
                Log.e("client", "onServiceDisconnected");
                mCalcAidl = null;
            }
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service)
            {
                Log.e("client", "onServiceConnected");
                mCalcAidl = ICalcAIDL.Stub.asInterface(service);
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
        }
    
        /**
         * 点击BindService按钮时调用
         * @param view
         */
        public void bindService(View view)
        {
            Intent intent = new Intent();
            intent.setAction("com.zhy.aidl.calc");
            intent.setPackage(this.getPackageName());   //兼容Android 5.0
            bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
    
        }
        /**
         * 点击unBindService按钮时调用
         * @param view
         */
        public void unbindService(View view)
        {
            unbindService(mServiceConn);
        }
        /**
         * 点击12+12按钮时调用
         * @param view
         */
        public void addInvoked(View view) throws Exception
        {
    
            if (mCalcAidl != null)
            {
                int addRes = mCalcAidl.add(12, 12);
                Toast.makeText(this, addRes + "", Toast.LENGTH_SHORT).show();
            } else
            {
                Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT)
                        .show();
    
            }
    
        }
        /**
         * 点击50-12按钮时调用
         * @param view
         */
        public void minInvoked(View view) throws Exception
        {
    
            if (mCalcAidl != null)
            {
                int addRes = mCalcAidl.min(58, 12);
                Toast.makeText(this, addRes + "", Toast.LENGTH_SHORT).show();
            } else
            {
                Toast.makeText(this, "服务端未绑定或被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT)
                        .show();
    
            }
    
        }
    }
    

    这样,就完成了,如图:

    image

    我们来分析下:

    服务端

    private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub()
        {
    
            @Override
            public int add(int x, int y) throws RemoteException
            {
                return x + y;
            }
    
            @Override
            public int min(int x, int y) throws RemoteException
            {
                return x - y;
            }
        };
    

    可以看到ICalcAIDL.Stub,我们点击查看

    public static abstract class Stub extends android.os.Binder implements com.zhy.calc.aidl.ICalcAIDL
    

    清楚的看到这个类是Binder的子类,是不是符合我们文章开通所说的服务端其实是一个Binder类的实例

    再来看看它的onTransact方法

     public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
                java.lang.String descriptor = DESCRIPTOR;
                switch (code) {
                    case INTERFACE_TRANSACTION: {
                        reply.writeString(descriptor);
                        return true;
                    }
                    case TRANSACTION_add: {
                        data.enforceInterface(descriptor);
                        int _arg0;
                        _arg0 = data.readInt();
                        int _arg1;
                        _arg1 = data.readInt();
                        int _result = this.add(_arg0, _arg1);
                        reply.writeNoException();
                        reply.writeInt(_result);
                        return true;
                    }
                    case TRANSACTION_min: {
                        data.enforceInterface(descriptor);
                        int _arg0;
                        _arg0 = data.readInt();
                        int _arg1;
                        _arg1 = data.readInt();
                        int _result = this.min(_arg0, _arg1);
                        reply.writeNoException();
                        reply.writeInt(_result);
                        return true;
                    }
                    default: {
                        return super.onTransact(code, data, reply, flags);
                    }
                }
            }
    

    开头也说到服务端的Binder实例会根据客户端依靠Binder驱动发来的消息,执行onTransact方法,然后由其参数决定执行服务端的代码。

    我们这里看到,这里有4个参数

    int code, android.os.Parcel data, android.os.Parcel reply, int flags
    

    我们来分别看下它们的作用

    字段 作用
    code 是一个整形的唯一标识,用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法
    data 客户端传递过来的参数
    reply 服务器返回回去的值
    flags 标明是否有返回值,0为有(双向),1为没有(单向)

    我们仔细看case TRANSACTION_min中的代码

    data.enforceInterface(DESCRIPTOR);与客户端的writeInterfaceToken对用,标识远程服务的名称

    int _arg0;
    _arg0 = data.readInt();
    int _arg1;
    _arg1 = data.readInt();

    接下来分别读取了客户端传入的两个参数

    int _result = this.min(_arg0, _arg1);
    reply.writeNoException();
    reply.writeInt(_result);

    然后执行this.min,即我们实现的min方法;返回result由reply写回。

    add同理,可以看到服务端通过AIDL生成Stub的类,封装了服务端本来需要写的代码

    客户端
    客户端主要通过ServiceConnected与服务端连接

    private ServiceConnection mServiceConn = new ServiceConnection()
        {
            @Override
            public void onServiceDisconnected(ComponentName name)
            {
                Log.e("client", "onServiceDisconnected");
                mCalcAidl = null;
            }
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service)
            {
                Log.e("client", "onServiceConnected");
                mCalcAidl = ICalcAIDL.Stub.asInterface(service);
            }
        };
    

    如果你比较敏锐,应该会猜到这个onServiceConnected中的IBinder实例,其实就是我们文章开通所说的Binder驱动,也是一个Binder实例

    在ICalcAIDL.Stub.asInterface中最终调用了:

    return new com.zhy.calc.aidl.ICalcAIDL.Stub.Proxy(obj);
    

    这个Proxy实例传入了我们的Binder驱动,并且封装了我们调用服务端的代码,文章开头说,客户端会通过Binder驱动的transact()方法调用服务端代码

    直接看Proxy中的add方法

    public int add(int x, int y) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    int _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(x);
                        _data.writeInt(y);
                        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
    

    首先声明两个Parcel对象,一个用于传递数据,一个用户接收返回的数据

    _data.writeInterfaceToken(DESCRIPTOR);与服务器端的enforceInterfac对应

    _data.writeInt(x);
    _data.writeInt(y);写入需要传递的参数

    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);

    终于看到了我们的transact方法,第一个对应服务端的code,_data,_repay分别对应服务端的data,reply,0表示是双向的

    _reply.readException();
    _result = _reply.readInt();

    最后读出我们服务端返回的数据,然后return。可以看到和服务端的onTransact基本是一行一行对应的。

    到此,我们已经通过AIDL生成的代码解释了Android Binder框架的工作原理。Service的作用其实就是为我们创建Binder驱动,即服务端与客户端连接的桥梁。

    3、不依赖AIDL实现程序间通讯

    服务器端

    public class CalcService extends Service {
        private static final String DESCRIPTOR = "CalcPlusService";
        private static final String TAG = "CalcPlusService";
    
        public void onCreate()
        {
            Log.e(TAG, "onCreate");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId)
        {
            Log.e(TAG, "onStartCommand");
            return super.onStartCommand(intent, flags, startId);
        }
    
        public IBinder onBind(Intent t)
        {
            Log.e(TAG, "onBind");
            return mBinder;
        }
    
        public void onDestroy()
        {
            Log.e(TAG, "onDestroy");
            super.onDestroy();
        }
    
        public boolean onUnbind(Intent intent)
        {
            Log.e(TAG, "onUnbind");
            return super.onUnbind(intent);
        }
    
        public void onRebind(Intent intent)
        {
            Log.e(TAG, "onRebind");
            super.onRebind(intent);
        }
    
        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 0x110:
                    {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        int _arg1;
                        _arg1 = data.readInt();
                        int _result = _arg0 * _arg1;
                        reply.writeNoException();
                        reply.writeInt(_result);
                        return true;
                    }
                    case 0x111:
                    {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        int _arg1;
                        _arg1 = data.readInt();
                        int _result = _arg0 / _arg1;
                        reply.writeNoException();
                        reply.writeInt(_result);
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    
        };
    }
    

    客户端:

    <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" >
    
        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:onClick="bindService"
            android:text="BindService" />
    
        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:onClick="unbindService"
            android:text="UnbindService" />
    
        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:onClick="mulInvoked"
            android:text="50*12" />
    
        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:onClick="divInvoked"
            android:text="36/12" />
    
    </LinearLayout>
    

    MainActivity

    public class MainActivity extends AppCompatActivity {
    
        private IBinder mPlusBinder;
        private ServiceConnection mServiceConnPlus = new ServiceConnection()
        {
            @Override
            public void onServiceDisconnected(ComponentName name)
            {
                Log.e("client", "mServiceConnPlus onServiceDisconnected");
            }
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service)
            {
    
                Log.e("client", " mServiceConnPlus onServiceConnected");
                mPlusBinder = service;
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
        }
    
        public void bindService(View view)
        {
            Intent intentPlus = new Intent();
            intentPlus.setAction("com.zhy.aidl.calcplus");
            intentPlus.setPackage(this.getPackageName());
            boolean plus = bindService(intentPlus, mServiceConnPlus,
                    Context.BIND_AUTO_CREATE);
            Log.e("plus", plus + "");
        }
    
        public void unbindService(View view)
        {
            unbindService(mServiceConnPlus);
        }
    
        public void mulInvoked(View view)
        {
    
            if (mPlusBinder == 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();
                int _result;
                try
                {
                    _data.writeInterfaceToken("CalcPlusService");
                    _data.writeInt(50);
                    _data.writeInt(12);
                    mPlusBinder.transact(0x110, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                    Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show();
    
                } catch (RemoteException e)
                {
                    e.printStackTrace();
                } finally
                {
                    _reply.recycle();
                    _data.recycle();
                }
            }
    
        }
    
        public void divInvoked(View view)
        {
    
            if (mPlusBinder == 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();
                int _result;
                try
                {
                    _data.writeInterfaceToken("CalcPlusService");
                    _data.writeInt(36);
                    _data.writeInt(12);
                    mPlusBinder.transact(0x111, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                    Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show();
    
                } catch (RemoteException e)
                {
                    e.printStackTrace();
                } finally
                {
                    _reply.recycle();
                    _data.recycle();
                }
            }
    
        }
    }
    

    运行 效果是一样的。

    相关文章

      网友评论

          本文标题:Service的总结

          本文链接:https://www.haomeiwen.com/subject/mojvqctx.html