Android应用开发Android 中AIDL的使用与理解
白羽 2019-04-15 来源 :网络 阅读 1034 评论 0

摘要:本文将带你了解Android应用开发Android 中AIDL的使用与理解,希望本文对大家学Android有所帮助。

    本文将带你了解Android应用开发Android 中AIDL的使用与理解,希望本文对大家学Android有所帮助。


Android应用开发Android 中AIDL的使用与理解


AIDL的使用:
    最常见的aidl的使用就是Service的跨进程通信了,那么我们就写一个Activity和Service的跨进程通信吧。
   
    首先,我们就在AS里面新建一个aidl文件(ps:现在AS建aidl不要求和java包名相同了):
   
 
    package aidl;
    interface IMyInterface {
        String getInfor(String s);
    }
    可以看到,在这里面我们就一个方法getInfor(String s),接受一个字符串参数,然后返回一个字符串,相当的简单。
   
    接着你sync   project一下就可以在app/generated/source/aidl/debug/aidl里面发现由aidl文件生成的java文件了。
   
    然后就看看Service:
   

    public class MyService extends Service {
     
    public final static String TAG = MyService;
     
    private IBinder binder = new IMyInterface.Stub() {
            @Override     
            public String getInfor(String   s) throws RemoteException {
                Log.i(TAG, s);
                return 我是 Service   返回的字符串;
           }
        };
    @Overrid
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, onCreat);  
    }     
    @Override  
    public IBinder onBind(Intent intent) {
        return binder;
        }
    }
      这里我们写了一个Service,看一下也比较简单。先new了一IMyInterface.Stub()并把它向上转型成了IBinder,最后在onBind方法中返回回去。可能你注意到了,在IMyInterface.Stub()的内部我们重写getInfor(String   s) 方法,没错这就是我们 aidl文件中定义的接口。
    对了,因为我们希望看到的是跨进程通信,所以我们把MyService定义成新启动一个进程:
   

    定义为启动在新进程中,只需要在AndroidMainfest.xml中声明是加上一个process属性即可,不过这里有两个地方值得注意:
    1.组件默认的进程名就是包名;
    2.定义新的进程名的时候需要以包的形式(eg: com.xu.aidl)。
   
    接着,我们继续向下看:

    public class MainActivity extends AppCompatActivity {
        public final static String TAG = MainActivity;
        private IMyInterface   myInterface;
        private ServiceConnection   serviceConnection = new ServiceConnection() {
            @Override
            public void   onServiceConnected(ComponentName name, IBinder service) {
                myInterface = IMyInterface.Stub.asInterface(service);
                Log.i(TAG, 连接Service   成功);
                try {
                    String s = myInterface.getInfor(我是Activity传来的字符串);
                    Log.i(TAG,   从Service得到的字符串: + s);
                } catch (RemoteException   e) {
                      e.printStackTrace();
                }
            }
            @Override
            public void   onServiceDisconnected(ComponentName name) {
                Log.e(TAG,   连接Service失败);
            }
        };
        @Override
        protected void onCreate(Bundle   savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
            startAndBindService();
        }
        private void   startAndBindService() {
            Intent service = new   Intent(MainActivity.this, MyService.class);
              //startService(service);
            bindService(service,   serviceConnection, Context.BIND_AUTO_CREATE);
        }
    }
    由于主要是Service和Activity间的通信,所以为了让代码整洁就没有写UI了。
   
    在onCreate(Bundle   savedInstanceState)中,我们调用了自己定义的一个方法startAndBindService(),这个方法里面我们生成了一个Intent,然后   bindService了这个Intent传入了三个参数分别是Intent、ServiceConnection、Flag。
   
    Intent我们就不用说了,我们看看后面两个参数:
    在Activity中,我们new了一个ServiceConnection并实现了他的两个方法onServiceConnected、onServiceDisconnected。在onServiceConnected中我们通过IMyInterface.Stub.asInterface(service)把传来的IBinder转换成了我们定义的IMyInterface。然后我们调用了getInfor方法,传递了个字符串和获取从MyService传来的字符串,并且打印了Log。
   
    对于我们传的Context.BIND_AUTO_CREATE的意思就是说:如果绑定Service的时候,Service还没有被创建,就创建它。当然,这里还有很多Flag,我也不一一说了。
   
    然后,我们的编码就完成了,开始运行测试一下把!
   
     
   
    看一下运行结果,在这两个不同的进程中都得到了我们想要的结果,所以,一个用aidl实现的跨进程通信就这样完成了。
   
    AIDL的理解:
    现在我们会使用aidl了,那我们还不去掀开它神秘的面纱。
   
    Service中的IBinder
    还记得我们在MyService中利用new   IMyInterface.Stub()向上转型成了IBinder然后在onBind方法中返回的。那我们就看看IMyInterface.Stub吧:

    public static abstract class Stub extends android.os.Binder implements   aidl.IMyInterface {
    ..........
    }
      可以看到,Stub是IMyInterface中的一个静态抽象类,继承了Binder,并且实现了IMyInterface接口。这也就解释了我们定义IMyInterface.Stub的时候为什么需要实现IMyInterface中的方法了,也说明了为什么我们可以把IMyInterface.Stub向上转型成IBinder了。
   
    Activity中的IMyInterface
   
      在Activity中,通过ServiceConnection连接MyService并成功回调onServiceConnected中我们把传回来的IBinder通过IMyInterface.Stub.asInterface(service)转换成为IMyInterface,那就来看看这里是如何转换的吧:
   


    public static abstract class Stub extends android.os.Binder implements   aidl.IMyInterface {
     
    ..........
     
    public static aidl.IMyInterface asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        //检查Binder是不是在当前进程
        android.os.IInterface iin =   obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) &&   (iin instanceof aidl.IMyInterface))) {
            return ((aidl.IMyInterface)   iin);
        }
        return new   aidl.IMyInterface.Stub.Proxy(obj);
    }
    }
    首先,我们因该明白的是,传回来的IBinder就是我们在Service的onBind(   )方法所return的IBinder,然后我们调用Stub中的静态方法asInterface并把返回来的IBinder当参数传进去。
      在asInterface方法中,首先判断了传进来的IBinder是不是null,如果为null就返回一个null;接着就判断传进来的IBinder是不是就在当前进程里面,如果是的话就直接返回IMyInterface,不是的话就返回IMyInterface.Stub.Proxy(obj)。这里我觉得需要明白的是:直接返回的IMyInterface是实现了定义的接口方法getInfor的。因为在IMyInterface.Stub中所实现的。当然如果是在同一进程中,那么我们调用IMyInterface的方法时就是在本地调用方法,直接调用就可以了。
   
    如果没在同一进程,就会返回IMyInterface.Stub.Proxy(obj):

    private static class Proxy implements aidl.IMyInterface {
            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   getInfor(java.lang.String s) 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.writeString(s);
                   //传送数据到远程的
                    mRemote.transact(Stub.TRANSACTION_getInfor,   _data, _reply, 0);
                      _reply.readException();
                  //接受从远端传回的数据
                    _result =   _reply.readString();
                } finally {
                      _reply.recycle();
                      _data.recycle();
                }
                return _result;
            }
       }
        static final int   TRANSACTION_getInfor = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }
    在Proxy中,我们首先把Service连接成功返回的IBinder它的内部变量mRemote,这里在提一下   


本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!

本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程