关闭

AndroidStudio 使用AIDL

标签: androidandroid studioaidl
8958人阅读 评论(1) 收藏 举报
分类:
  • 这个标题不是很好,因为Android Studio是一个IDE,AIDL是一种IPC通信机制。本质上没有任何的关联。但是大家都懂得,这是一个在Android Studio中写的一个AIDL的小DEMO.
  • 步骤很繁琐,本来不准备写的。但是写一下是为了记录,这一下午终于跑通了这玩意。
  • 首先,你要有3个 Module,至少两个,但是最好是3个
    • 一个是你的AIDL文件与它的Service所在的Module
    • 一个是你的客户端Module,也就是你真正调用AIDLModule
    • 最后一个是你的AIDL需要使用的Parcelable对象存放的Module.如果你要传递的只是基本的数据类型,那么这一项可以不要。如果你直接将该对象创建在你的调用AIDLModule中,这一项也可以不要。
    • 为什么我说要3个Module呢?
      • 因为:第三个Module是作为第一个和第二个的共同依赖存在的。这样,两边都可以使用其中的 对象。
  • 然后,你得先有一个Service,这个Service就是你的AIDL的具体实现。你的AIDL想要什么功能,完全取决于你的service怎么写了。

    • package com.pythoncat.aidl_libiary;
      
      import android.app.Service;
      import android.content.Intent;
      
      public class HelloService extends Service {
          public HelloService() {
          }
          @Nullable
          @Override
          public IBinder onBind(Intent intent) {
              return null;
          }
      }
  • 好了,你的Service已经有了。但是目前还没有什么意义。为了将这个AIDL做得有意思一点,我们假设你是要通过AIDL传递复杂的数据,比如Student这样类似的一个java bean
  • 既然这样,那么,我们就需要一个Student类了,注意:必须实现Parcelable,不如就不能AIDL了。差不多这个类就长这样:
    package com.pythoncat.core.model;

    import android.os.Parcel;
    import android.os.Parcelable;

    /**
     * Created by pythonCat on 2016/6/1.
     */
    public class Student implements Parcelable {

        public String name;
        public int age;
        public int sex;

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

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

        public Student() {
        }

        protected Student(Parcel in) {
            this.name = in.readString();
            this.age = in.readInt();
            this.sex = in.readInt();
        }

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

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


  • 好了,你的Student已经准备好了,现在就是真的要定义一下AIDL文件了。因为这个Student是要通过AIDL去传递的,所以这个Student也要成为一个AIDL.

这句话听起来比较费解,是因为我表达的不够好。其实说白了,就是要多创建一个名为Student.aidl的文件,这个文件差不多这样:
    // Student.aidl
    package com.pythoncat.core.model;
    parcelable Student;

注意了:这个文件所在目录,必须是在一个aidl目录下,创建一个和Student.java同包名的包。比如,我的Student.java是在package com.pythoncat.core.model;中,那么,我就要在AIDL所在Module中,创建一个aidl目录,然后在该目录下创建一个package,package名字就是package com.pythoncat.core.model。最后,在该package下,创建一个Student.aidl文件,里面就写上面3句话就好了。


  • 到这里,java bean算是真的准备好了,显示开始写你的需要被外界调用的AIDL了。这个文件位置随便写,你就在java目录下创建一个.aidl文件好了。文件名假设是IHelloInterface,文件假设是这样的:

```
// IHelloInterface.aidl
package com.pythoncat.aidl_libiary;

import com.pythoncat.core.model.Student;
// Declare any non-default types here with import statements

interface IHelloInterface {
    /**
     * 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);

    String hello();

    Student getOne();
}
```

注意一下,上面有一个import com.pythoncat.core.model.Student;就是刚才的那个Student.aidl的导入。、

  • ok,到了这里。已经完成了一小半了。然后是,build -> make project (ctrl+F9)一下。让android studio帮你一把。
  • build -> make project (ctrl+F9)之后,你会看到你的IHelloInterface .aidl自动跑到aidl目录里面去了。不过这个都不是我关心的。
  • 现在,我们完善我们的HelloService:

    package com.pythoncat.aidl_libiary;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.support.annotation.Nullable;
    
    import com.pythoncat.core.model.Student;
    
    /**
     * <action android:name="com.pythoncat.aidl_libiary.HelloService"/>
     * <hr/>
     * package="com.pythoncat.aidl_libiary"
     */
    public class HelloService extends Service {
        public HelloService() {
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return new MyBinder();
        }
    
        class MyBinder extends IHelloInterface.Stub {
    
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
    
            }
    
            @Override
            public String hello() throws RemoteException {
                return "Just Hello World";
            }
    
            @Override
            public Student getOne() throws RemoteException {
                return new Student();
            }
        }
    }
  • 发现没有,现在我们的Service,AIDL,Model已经关联起来了,接下来就是调用者的事情了。
  • ** 既然是调用者的事情了,那我们就搞一个Activity去调用试试吧。
  • 在调用处,其实和平常的绑定服务几乎没有任何的差别,都是通过ServiceConnection去获取接口的引用,然后就可以调用接口里面的方法了。[接口的实现,已经在我们的HelloService里面搞定了]。
  • 调用就一个Activity里面一个按钮的点击事件 ,布局文件就不写了,没什么意义。那么调用者差不多这样的:

    package com.pythoncat.helloaidl;
    
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    
    import com.apkfuns.logutils.LogUtils;
    import com.github.johnpersano.supertoasts.SuperToast;
    import com.pythoncat.aidl_libiary.IHelloInterface;
    import com.pythoncat.core.model.Student;
    
    public class MainActivity extends AppCompatActivity {
    
        private IHelloInterface iService;
        private ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iService = IHelloInterface.Stub.asInterface(service);
                try {
                    final String hello = iService.hello();
                    LogUtils.e("hello::::::::" + hello);
                    final Student one = iService.getOne();
                    LogUtils.e(one);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            SuperToast.cancelAllSuperToasts();
                            SuperToast.create(getApplicationContext(), hello, SuperToast.Duration.MEDIUM).show();
                        }
                    });
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                iService = null;
                LogUtils.e("iService::::::::" + iService);
            }
        };
        private boolean bindService;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            final Intent in = new Intent();
            in.setClassName(this, "com.pythoncat.aidl_libiary.HelloService");
            in.setPackage("com.pythoncat.aidl_libiary");
            in.setAction("com.pythoncat.aidl_libiary.HelloService");
            bindService = bindService(in, conn, Context.BIND_AUTO_CREATE);
            LogUtils.e("bindService=" + bindService);
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            if (conn != null) {
                unbindService(conn);
            }
        }
    
        public void clickButton(View v) {
            LogUtils.e("bindService=" + bindService);
            LogUtils.e(iService);
            if (iService == null) {
                SuperToast.cancelAllSuperToasts();
                SuperToast.create(getApplicationContext(), iService + "", SuperToast.Duration.MEDIUM).show();
            } else {
                SuperToast.cancelAllSuperToasts();
                try {
                    SuperToast.create(getApplicationContext(), iService.hello(), SuperToast.Duration.MEDIUM).show();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }
  • 这样,其实就已经完成了一个AIDL的调用的整个过程。
  • 另外,一旦项目跑不通,多弄几次build -> make project (ctrl+F9)的操作,还是跑不通,就是代码有问题了。

    不过,我必须坦白的是,我的调用者的Module还是引用了AIDL所在Module。因为我不引用就不能成功绑定远程服务。这个问题应该是可以解决的,以后解决了,再记录到这边来。

  • 项目戳我,戳我啊~…~
  • 真的彩蛋后续更新FINAL
  • 1
    0

    查看评论
    * 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
      个人资料
      • 访问:99956次
      • 积分:2318
      • 等级:
      • 排名:第16752名
      • 原创:133篇
      • 转载:2篇
      • 译文:1篇
      • 评论:19条
      最新评论