AIDL(Android 接口定义语言)与您可能使用过的其他 IDL 类似。 您可以利用它定义客户端与服务使用进程间通信 (IPC) 进行相互通信时都认可的编程接口。 在 Android 上,一个进程通常无法访问另一个进程的内存。 尽管如此,进程需要将其对象分解成操作系统能够识别的原语,并将对象编组成跨越边界的对象。 编写执行这一编组操作的代码是一项繁琐的工作,因此 Android 会使用 AIDL 来处理。

实现AIDL有下面几个步骤

1、定义.aidl文件,您开发每个包含 .aidl 文件的应用时,Android SDK 工具都会生成一个基于该 .aidl 文件的 IBinder 接口,并将其保存在项目的 gen/ 目录中。服务必须视情况实现 IBinder 接口。然后客户端应用便可绑定到该服务,并调用 IBinder 中的方法来执行 IPC。aidl支持的类型有string、charSequence、list、map等。
定义服务接口时,请注意:方法可带零个或多个参数,返回值或空值。所有非原语参数都需要指示数据走向的方向标记。可以是 in、out 或 inout(见以下示例)。原语默认为 in,不能是其他方向
示例:

interface Data {    //查询数据    List<String> getData();    //添加数据    void setData(String s);}

2、定义一个服务,用户绑定返回一个IBinder

class MyService : Service() {    //返回IBinder、DataAiDl    override fun onBind(intent: Intent): IBinder? {        return DataAiDl()    }}

DataAiDl.kt的代码实现,注意看注释

/** * Created by aiiage on 2018/8/9. * DataAiDl继承Data.Stub()实现AIDL */class DataAiDl : Data.Stub(){    //设置数据    override fun setData(s: String) {        Log.e("MainActivity",s)        list.add(s)    }    var list= ArrayList()    //添加数据    override fun getData(): MutableList {        return list    }}

3、在activity中连接并绑定服务,代码如下

class MainActivity : BaseActivity(),View.OnClickListener {    private var TAG="MainActivity"    private var i=0    //由AIDL文件生成的Java类    private var data: Data? = null    //标志当前与服务端连接状况的布尔值,false为未连接,true为连接中    private var mBound=false    //定义数据链表    var list= ArrayList<String>()   //控件点击事件    override fun onClick(p0: View) {       //如果与服务端的连接处于未连接状态,则尝试连接        if (!mBound) {            attemptToBindService()            Toast.makeText(this, "当前与服务端处于未连接状态,正在尝试重连,请稍后再试", Toast.LENGTH_SHORT).show()            return        }        if(data==null)            return        when(p0.id){            R.id.addDataBty->{                data!!.setData("data"+i)                i++            }            R.id.seeDataBty->{                 list= data!!.data as ArrayList<String>                var sb=StringBuffer()                for (d in list)                {                    sb.append(d).append("\n")                }                textView.text=sb            }        }    }   //获取布局文件id    override fun getContentViewLayoutID(): Int {        return R.layout.activity_main    }    //初始化控件    override fun initView(savedInstanceState: Bundle?) {        addDataBty.setOnClickListener(this)        seeDataBty.setOnClickListener(this)    }    //连接服务器    private fun attemptToBindService() {        val intent = Intent()        Log.e(TAG, " connected now")        intent.action = "com.andream.aiiage.Data" //在AndroidManifest.xml进行配置隐形启动action        intent.`package` = "com.andream.aiiage.aidlkotlin" //你的包名        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)    }    private val mServiceConnection = object : ServiceConnection {        override fun onServiceConnected(name: ComponentName, service: IBinder) {            Log.e(TAG, "service connected")            data = Data.Stub.asInterface(service)            mBound = true            if (data != null) {                try {                    list = data!!.data as ArrayList<String>                } catch (e: RemoteException) {                    e.printStackTrace()                }            }        }        override fun onServiceDisconnected(name: ComponentName) {            Log.e(TAG, "service disconnected")            mBound = false        }    }    override fun onStart() {        super.onStart()        attemptToBindService()    }    override fun onStop() {        super.onStop()        unbindService(mServiceConnection)    }}

4、记得在在AndroidManifest.xml进行配置隐形启动action来启动service

  <service            android:name=".MyService"            android:enabled="true"            android:exported="true">            <intent-filter>                <action android:name ="com.andream.aiiage.Data"/>            intent-filter>        service>

5、总结:AIDL可以进行跨进程通讯,配置和使用起来简单。如果你想把某个类跨进程传递的话,该类必须支持 Parcelable 接口。支持 Parcelable 接口很重要,因为 Android 系统可通过它将对象分解成可编组到各进程的原语。

6、注意:AIDL 接口的调用是直接函数调用。 您不应该假设发生调用的线程。 视调用来自本地进程还是远程进程中的线程,实际情况会有所差异。 具体而言:

来自本地进程的调用在发起调用的同一线程内执行。如果该线程是您的主 UI 线程,则该线程继续在 AIDL 接口中执行。 如果该线程是其他线程,则其便是在服务中执行您的代码的线程。 因此,只有在本地线程访问服务时,您才能完全控制哪些线程在服务中执行(但如果真是这种情况,您根本不应该使用 AIDL,而是应该通过实现 Binder 类创建接口)。
来自远程进程的调用分派自平台在您的自有进程内部维护的线程池。 您必须为来自未知线程的多次并发传入调用做好准备。 换言之,AIDL 接口的实现必须是完全线程安全实现。
oneway 关键字用于修改远程调用的行为。使用该关键字时,远程调用不会阻塞;它只是发送事务数据并立即返回。接口的实现最终接收此调用时,是以正常远程调用形式将其作为来自 Binder 线程池的常规调用进行接收。 如果 oneway 用于本地调用,则不会有任何影响,调用仍是同步调用。

7、工程目录和效果图

8、附录
baseactivity.java代码

  abstract class BaseActivity : AppCompatActivity() {    /**     * 获取布局id     */    protected abstract fun getContentViewLayoutID(): Int    /**     * 初始化控件     */    protected abstract fun initView(savedInstanceState: Bundle?)    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        if (getContentViewLayoutID()!=0)        {            setContentView(getContentViewLayoutID())            initView(savedInstanceState)        }    }    protected fun showToast(desc: String) {        Toast.makeText(this,desc,Toast.LENGTH_SHORT).show()    }}

更多相关文章

  1. Android怎样绕开Camera打开手电筒的LED
  2. 第三部分:Android(安卓)应用程序接口指南---第三节:应用程序资源--
  3. andorid ANR keyDispatchingTimedOut的原因和解决之道
  4. 备战面试旺季:2019年Android面试题整理(组件+View+线程+面经)
  5. Android(安卓)Nougat多窗口简析
  6. Android(安卓)任务、进程和线程
  7. Android(安卓)Service解析解析再解析
  8. Android开发之旅(二)服务生命周期和广播接收者生命周期
  9. Android(安卓)AsyncTask与handler

随机推荐

  1. Android插件开发初探——基础篇
  2. Android中Textview和图片同行显示(文字超
  3. 【Android】说做就做:带图标的list item
  4. 侧边栏(使用Support Library 4提供的扩展
  5. 旅行的青蛙Unity游戏逆向修改Android&iOS
  6. 如何成功在android设备上连接pc端共享的
  7. Android(安卓)8.0刘海屏适配
  8. Android内核开发:从源码树中删除出厂的app
  9. 给Android的应用换个图标(桌面快捷图标)sSh
  10. MIUI Launcher – 超逼真的仿 MIUI 启动