教你看懂aidl究竟怎么用?

平常我们开发的过程中,涉及到aidl的应用特别少,但是他却是Android开发进阶中必须要掌握的一项知识点,下面我就来简单的介绍一下aidl
1 为什么要引入AIDL?
我们知道,每一个app都拥有一个独立的进程,那么如果在一个app里需要访问另外一个app的数据该怎么办呢?那么就要涉及到跨进程通信了,而Android是通过AIDL来实现跨进程通信的。
2 那么什么是AIDL?
AIDL:Android Interface Definition Language,即Android接口定义语言;用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。由此可见,AIDL是为了解决跨进程之间的通讯问题。
3 AIDL的运用场景:在多进程通信中,存在两个进程角色(以最简单的为例):服务器端和客户端,那么既然说到服务端,我们可以反思一下Service的基本知识点,如本地服务、远程服务等,其二者最大的区别是:远程Service与调用者不在同一个进程里(即远程Service是运行在另外一个进程);而本地服务则是与调用者运行在同一个进程里
那么具体的步骤是什么样的呢?就以我写的demo为例子(客户端如何访问远程服务端的例子),先以服务端为例,代码结构如下:
教你看懂aidl究竟怎么用?_第1张图片
其截图如下:
教你看懂aidl究竟怎么用?_第2张图片

代码片段如下:

// IMyAidlInterface.aidl
package com.example.lbs06.aidlserver;

// Declare any non-default types here with import statements

interface IMyAidlInterface {
    void callfromClient();
}
//AIDL中支持以下的数据类型
//1. 基本数据类型
//2. String 和CharSequence
//3. List 和 Map ,List和Map 对象的元素必须是AIDL支持的数据类型;
//4. AIDL自动生成的接口(需要导入-import)
//5. 实现android.os.Parcelable 接口的类(需要导入-import)

Service里的代码片段如下:

/**
 * Created by lbs06 on 2017/10/24.
 */

public class MyService extends Service{
     public String TAG="MyService";
    // 实例化AIDL的Stub类(Binder的子类)
     IMyAidlInterface.Stub mbinder=new IMyAidlInterface.Stub() {
        //重写接口里定义的方法
         @Override
         public void callfromClient() throws RemoteException {
             Log.d(TAG,"客户端调用了服务端的callfromClient方法");
         }
     };



    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG,"onBind方法被调用");
        return mbinder;
    }
}

清单文件里的内容如下所示:


        ".MyService"
            android:process=":remote"
            android:exported="true"
            >
            //android:process=":remote"  设置服务为远程服务,拥有一个独立的进程
            //android:exported="true"   设置服务可以被其他进程访问
            //MyService可以响应带有com.lbs.aidl.server.IMyAidlInterface这个action的Intent。
            
                "com.example.lbs06.aidlserver.IMyAidlInterface"/>
            

        

客户端的项目的结构如下:
教你看懂aidl究竟怎么用?_第3张图片

xml文件很简单:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <TextView
        android:id="@+id/tv_bind_service"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#e3e3e3"
        android:gravity="center"
        android:text="绑定服务"
         />

LinearLayout>

那么在activity里面的代码块是这样的,如下图:

public class MainActivity extends AppCompatActivity {

    public String TAG="客户端的进程";
    //定义aidl接口变量
    private IMyAidlInterface myinterface;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.tv_bind_service).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //通过Intent指定服务端的服务名称和所在包,与远程Service进行绑定
                //参数与服务器端的action要一致,即"服务器包名.aidl接口文件名"
                Intent intent=new Intent("com.example.lbs06.aidlserver.IMyAidlInterface");
                //Android5.0后无法只通过隐式Intent绑定远程Service
                //需要通过setPackage()方法指定包名
                intent.setPackage("com.example.lbs06.aidlserver");
               //绑定服务,传入intent和ServiceConnection对象
                bindService(intent,connection, Context.BIND_AUTO_CREATE);
            }
        });
    }


    //创建ServiceConnection的匿名类
    ServiceConnection  connection=new ServiceConnection() {

        //重写onServiceConnected()方法和onServiceDisconnected()方法
        //在Activity与Service建立关联和解除关联的时候调用


        //在Activity与Service建立关联时调用
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //IMyAidlInterface.Stub.asInterface()方法将传入的IBinder对象传换成了mAIDL_Service对象
            myinterface=IMyAidlInterface.Stub.asInterface(iBinder);
            try {
                //通过该对象调用在IMyAidlInterface.aidl文件中定义的接口方法,从而实现跨进程通信
                myinterface.callfromClient();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        //在Activity与Service解除关联时调用
        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

分别运行客户端和服务端的代码,点击客户端的按钮,会发现log日志如下:

10-25 08:55:06.472 19892-19892/com.example.lbs06.aidlserver:remote D/MyService: onBind方法被调用
10-25 08:55:06.475 19892-19905/com.example.lbs06.aidlserver:remote D/MyService: 客户端调用了服务端的callfromClient方法

在此,客户端向服务端通信成功。
不过在此,曾遇到过两个坑,第一,在代码中,当新建aidl文件夹后,创建相应包下的aidl后,无法引用IMyAidlInterface的问题,如下截图所示:教你看懂aidl究竟怎么用?_第4张图片

就因为这个问题后困扰了好久,后来通过在网上查找资料,发现clean一下项目即可。
还有一个问题,看下截图:
教你看懂aidl究竟怎么用?_第5张图片

最开始我把1和2处的包名定义成不一样的,也不能通信成功,后来改成一样的,通信成功,也不知道是什么问题所导致的,还请有知道的告知下,谢谢。最后,放上源码的地址,有需要的可以去下载:http://download.csdn.net/download/u010667468/10038464

你可能感兴趣的:(aidl,android开发,通信,android)