Android知识体系梳理笔记一:Android跨进程通信:AIDL

前言

毕业已经有一个多月了,Android也自学了2年多了(都是晚上学一点),因为自己的木讷,不自信,最近很迷茫,再加上公司给自己的定位是Android前端开发,还有一部分C#中间层代码的编写(嘴贱说自己大学用c#做过网页-o-),工作因为同事出差很忙,让我变得很闲(不知道干啥),更让我对未来产生了很大的恐惧;于是今天就决定梳理下自己的Android知识体系,让自己认识到真实的自己,对未来不在迷茫;同时这也应该是对Android各个知识(使用?)方面的总结,我之所以分享出来也是因为这方面的考虑;这都是网上资料+我自己的感悟及补充,有什么不足的地方请指正,也请宽容(毕竟也算是新人了,哈哈-0-)! 不多说了,看正文!!!

AIDL作用

  • AIDL (Android Interface Definition Language) 是一种IDL 语言,是安卓系统接口定义语言。 在 Android 上,一个进程通常无法访问另一个进程的内存。 要想如此,进程需要将其对象分解成操作系统能够识别的原语,并将对象编组成跨越边界的对象。 编写执行这一编组操作的代码是一项繁琐的工作,因此 Android 会使用 AIDL 来处理。
  • AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据。
  • AIDL的作用是让你可以在自己的APP里绑定一个其他APP的service,这样你的APP可以和其他APP交互

AIDL的使用场合

  • 只有允许不同应用的客户端用 IPC 方式访问服务,并且想要在服务中处理多线程时,才有必要使用 AIDL。 如果您不需要执行跨越不同应用的并发 IPC,就应该通过实现一个 Binder 创建接口;或者,如果您想执行 IPC,但根本不需要处理多线程,则使用 Messenger 类来实现接口。无论如何,在实现 AIDL 之前,请您务必理解绑定服务。

在Android Studio 上使用AIDL

常用类型AIDL的创建
  • 在Module上右键,如下图:
    这里写图片描述

  • 输入名称后,sutido就帮我们创建了一个AIDL文件。

// IMyAidlInterface.aidl
package com.example.happyghost.studytest;

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

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

在这个aidl文件里可以定义任何基于上面类型的方法,要想自定义类型,自定义的类型需实现Parcelable接口,下面和细节一块讲;

定义一个基本类型方法

// IMyAidlInterface.aidl
package com.example.happyghost.studytest;

// Declare any non-default types here with import statements
interface IMyAidlInterface {

    String getName();
}
  • 在StudyTest Module内创建一个服务类,继承Service,然后在这个类中写一个继承IMyAidlInterface.Stub的内部类,实现其方法!
public class MyAidlService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBind();
    }
    class MyBind extends IMyAidlInterface.Stub{
        @Override
        public String getName() throws RemoteException {
            return "I am aidl in the ipc";
        }
    }
}

而这个服务就是自己的APP里绑定一个其他APP(其他进程)中的service

  • 然后将你的AIDL文件夹Copy到另一个工程AidlTest Module中,放到同级目录下,包命不要改,看下图:

这里写图片描述

  • 接下来就是在Module中绑定服务:
public class MainActivity extends AppCompatActivity {

    private IMyAidlInterface iMyAidlInterface;
    private TextView tvAidl;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         //这个“com.example.happyghost.studytest.MyAidlService”是在AndroidManifest.xml中声明的Service
         //的过滤意图action 具体样式如下:
         /**
         *<service android:name=".MyAidlService"
         *   android:enabled="true"
         *   android:exported="true">
         *   <intent-filter >
         *       <action *android:name="com.example.happyghost.studytest.MyAidlService"/>
         *   </intent-filter>
         * </service>
         */
        Intent intent = new Intent("com.example.happyghost.studytest.MyAidlService");
        //显示启动服务
        //intent.setComponent(new ComponentName("com.example.happyghost.studytest", "com.example.happyghost.studytest.MyAidlService"));

        //隐式启动服务===》转成显示启动服务
        Intent implicitIntent = createExplicitFromImplicitIntent(this, intent);
        MyAidlServiceConnection conn = new MyAidlServiceConnection();
        bindService(implicitIntent,conn,BIND_AUTO_CREATE);

        tvAidl = (TextView) findViewById(R.id.aidl);
        tvAidl.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    tvAidl.setText(iMyAidlInterface.getName());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private class MyAidlServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
    public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
        //检索所有的服务,以匹配给定的意图
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);

        //确保只进来一次
        if (resolveInfo == null || resolveInfo.size() != 1) {
            return null;
        }

        //获取组件信息并创建ComponentName
        ResolveInfo serviceInfo = resolveInfo.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);

        //创建一个新的目的
        Intent explicitIntent = new Intent(implicitIntent);

        //将组件设置为显式
        explicitIntent.setComponent(component);

        return explicitIntent;
    }
}

注意:在这里有个坑,在5.0系统以下,隐式,显式开启服务都可以,但是在5.0系统以上隐式开启服务会让程序崩溃掉,具体有原因请看这篇博客。所以我们需要用工具方法createExplicitFromImplicitIntent()将隐式意图转成显式意图,代码中有详细的注释;

看结果:

这里写图片描述

自定义类型
  • 自定义一个类型,使其实现Parcelable接口
public class Student implements Parcelable{
    String name;

    int age;
    public  Student(){}

    public Student(Parcel in) {
        name = in.readString();
        age = in.readInt();
    }

    public static final Creator<Student> CREATOR = new Creator<Student>() {
        @Override
        public Student createFromParcel(Parcel in) {
            return new Student(in);
        }

        @Override
        public Student[] newArray(int size) {
            return new Student[size];
        }
    };

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
    }
}

注意:如果你在原始目录下又新建了一个包,而自定义类型放在了这个包中,你需要在AIDL文件原始目录下同样需要建一个包名相同的包,看下图:

这里写图片描述

  • 新建一个Aidl文件,文件名为我们自定义的类名,放入到我们新建的包中
// Student.aidl
package com.example.happyghost.studytest.aidldemo;

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

parcelable Student ;
  • 修改原来的IMyAidlInterface.aidl文件,将我们的自定义类型导入进去(import…),然后创建我们想要实现的方法。
// IMyAidlInterface.aidl
package com.example.happyghost.studytest;

// Declare any non-default types here with import statements
import com.example.happyghost.studytest.aidldemo.Student;
interface IMyAidlInterface {
   List<Student> getStudent();
   void addStudent(in Student student);
}

记得每次修改aidl文件需要同步一下。。。。

  • 修改MyAidlService类
public class MyAidlService extends Service {
    private List<Student> mStudents = new ArrayList<Student>();
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBind();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Student student = new Student();
        for (int i = 0; i < 10; i++) {
            student.setName("xiao ming"+i);
            student.setAge(10+i);
            mStudents.add(student);
        }
    }

    class MyBind extends IMyAidlInterface.Stub{

        @Override
        public List<Student> getStudent() throws RemoteException {
            return mStudents;
        }

        @Override
        public void addStudent(Student student) throws RemoteException {
            mStudents.add(student);
        }
    }
}
  • 将AIDL文件夹及自定义类型类文件Copy到另一个AidlTest module中,包名路径要和原工程中的包名路径相同。看下图:

这里写图片描述

  • 绑定服务,这里就看一下较上面改变的代码
 tvAidl.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    List<com.example.happyghost.studytest.aidldemo.Student> student = iMyAidlInterface.getStudent();
                    Student student1 = student.get(0);
                    tvAidl.setText(student1.getName()+"\n"+"\r"+student1.getAge());
//                    tvAidl.setText(iMyAidlInterface.getName());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });

这里看结果:
这里写图片描述

若有错误,敬请指正!!!

拼搏在技术道路上的一只小白And成长之路

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值