AIDL(Android Interface Definition Language),翻译成中文就是安卓接口定义语言的意思,是用于定义服务端和客户端通信接口的一种描述语言。其主要作用是IPC(Android进程间通讯),简单的来说就是AIDL可以让一个APP使用另外一个APP的Service,使得两个或者多个APP之间可以信息交互,使得多个APP之间只需要使用一套代码,这样对于同一个功能就不用在多个APP中都写一遍逻辑了,减少了重复代码。 AIDL的语法十分简单,与Java语言基本保持一致,需要记住的规则有以下几点: AIDL文件以 .aidl 为后缀名 下面我举例使用AIDL实现一个APP访问另外一个APP创建的数据库。 首先我们创建一个新的项目作为服务端APP,创建一个database,这里我使用Room框架。自定义类型User,直接上代码 实体类User,注意要在AIDL中使用自定义类型,实体类必须实现Parcelable接口来进行序列化。而且这个类必须添加一个无参的构造方法,通常无参的构造方法即使不写编译器也会帮我们自动生成,但是这里必须手动加上。 创建UserDao: Room数据库支持直接返回LiveData对象的查询结果,AIDL这个例子没有用到,有兴趣可以看我这篇博客 UserDatabase: 数据库相关的逻辑已经编写完毕,可以通过 来给数据库添加数据。 下面是AIDL相关: 将视图切换到Project目录下,右键点击项目创建AIDL文件。 basicTypes这个方法是自动生成的,可以删除,这个方法只是告诉你哪些基本类型可以直接在AIDL中使用。 List getUsers()是我们自己创建的方法,表示需要返回一个List< User>类型的的结果。 注意AIDL文件目前并不能自动导包,所以import信息需要你自己敲上去。 因为我们用到了自定义类型User,所以在这个AIDL文件同包下我们还需要新建一个AIDL文件用来帮助AIDL找到这个User类,这部必不可少,否则会报找不到类的错误。 文件名必须和自定义类型名称相同。这里我们的自定义类型是User,那么这个AIDL文件就需要命名为User.aidl. sycn project以下以生成AIDL相关代码。 此时build文件下下就生成了相关文件DBAidlInterface 这个代码都是自动生成的,贴出来看一哈 OK,服务端app的最后一步就是创建Service了,和普通Service类似,只是我们的IBinder对象改为继承刚才生成代码中的内部静态抽象类 Stub。 清单文件里注册一下service 给service添加一个隐式意图的action,以方便另外一个app可以找到这个service。 到这里服务端APP搞定了,下面编写客户端APP的代码。 新建工程,将aidl整个包拷贝到新app的对应位置,包名必须一致。同样需要拷贝的还有数据bean User.java。这里同样这个类所在的包必须和服务端User类所在的包名一模一样。比如我服务端User类在com.example.testapp.database包下,那么我就需要在客户端app下也创建一个一样的包把User类放进去。 现在我们就可以去调用服务端的Service了。 简单编写一个Activity,在Activity中使用TextView显示数据库中所有User的name。 将两个APP都安装到手机上,在服务端APP上添加数据库数据,切换到客户端app上点击按钮就能拿到最新的数据了。 想到这个例子主要是之前看Content Provider的时候发现网上操作Content Provider的例子几乎都是使用的原生SQLiteOpenHelper的,并没有结合GreenDao,Room这种sqlite框架或者Realm数据库来使用,使用起来不是很方便。ContentProvider也是Android跨进程数据共享方案,和AIDL一样底层都是Binder机制,就想着能不能用AIDL来跨进程访问数据库,现在看来是可以的。但是有一个问题,客户端在绑定Service的时候需要服务端的进程是活着的。所以在启动前需要先唤醒服务端进程或者给服务端做保活才稳定。还是Content Provider好用~
什么是AIDL:
语法
AIDL支持的数据类型分为如下几种:
八种基本数据类型:byte、char、short、int、long、float、double、boolean
String,CharSequence
实现了Parcelable接口的数据类型
List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
AIDL文件可以分为两类。一类用来声明实现了Parcelable接口的数据类型,以供其他AIDL文件使用那些非默认支持的数据类型。还有一类是用来定义接口方法,声明要暴露哪些接口给客户端调用,定向Tag就是用来标注这些方法的参数值
定向Tag。定向Tag表示在跨进程通信中数据的流向,用于标注方法的参数值,分为 in、out、inout 三种。其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。此外,如果AIDL方法接口的参数值类型是:基本数据类型、String、CharSequence或者其他AIDL文件定义的方法接口,那么这些参数值的定向 Tag 默认是且只能是 in,所以除了这些类型外,其他参数值都需要明确标注使用哪种定向Tag。定向Tag具体的使用差别后边会有介绍
明确导包。在AIDL文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同个包名下举例使用:
build.gradle中引入room支持 androidTestImplementation "android.arch.persistence.room:testing:1.1.1" implementation 'android.arch.persistence.room:runtime:1.1.1' annotationProcessor 'android.arch.persistence.room:compiler:1.1.1' androidTestImplementation "android.arch.persistence.room:testing:1.1.1"
package com.example.testapp.database; import android.os.Parcel; import android.os.Parcelable; import androidx.room.ColumnInfo; import androidx.room.Entity; import androidx.room.PrimaryKey; @Entity(tableName = "user") public class User implements Parcelable { public User() { //无参构造 } protected User(Parcel in) { id = in.readLong(); name = in.readString(); sex = in.readString(); age = in.readInt(); } public static final Creator<User> CREATOR = new Creator<User>() { @Override public User createFromParcel(Parcel in) { return new User(in); } @Override public User[] newArray(int size) { return new User[size]; } }; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @PrimaryKey @ColumnInfo(name = "id") private long id; @ColumnInfo(name = "name") private String name; @ColumnInfo(name = "sex") private String sex; @ColumnInfo(name = "age") private int age; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(id); dest.writeString(name); dest.writeString(sex); dest.writeInt(age); } }
package com.example.testapp.database; import java.util.List; import androidx.lifecycle.LiveData; import androidx.room.Dao; import androidx.room.Delete; import androidx.room.Insert; import androidx.room.Query; import androidx.room.Update; @Dao public interface UserDao { @Query("SELECT * FROM user") LiveData<List<User>> getUserLiveData(); @Query("SELECT * FROM user") List<User> getAll(); @Insert void insert(User user); @Delete void delect(User user); @Update void update(User user); }
LiveData结合Room数据库使用以及线程问题
package com.example.testapp.database; import android.content.Context; import androidx.annotation.NonNull; import androidx.room.Database; import androidx.room.Room; import androidx.room.RoomDatabase; import androidx.sqlite.db.SupportSQLiteDatabase; @Database(entities = {User.class},version = 1,exportSchema = false) public abstract class UserDatabase extends RoomDatabase { public static final String DB_NAME = "UserDataBase.db"; private static volatile UserDatabase instance; public static synchronized UserDatabase getInstance(Context context){ if (instance == null){ instance = createDatabase(context); } return instance; } private static UserDatabase createDatabase(Context context) { return Room.databaseBuilder(context,UserDatabase.class,DB_NAME).allowMainThreadQueries().addCallback(new RoomDatabase.Callback(){ @Override public void onCreate(@NonNull SupportSQLiteDatabase db) { super.onCreate(db); } @Override public void onOpen(@NonNull SupportSQLiteDatabase db) { super.onOpen(db); } }).build(); } public abstract UserDao getUserDao(); }
UserDatabase.getInstance(mContext).getUserDao().insert(user);
文件名称自定义就好,创建完成后可以看到默认生成的代码。// DBAidlInterface.aidl package com.example.testapp.database; import com.example.testapp.database.User; // Declare any non-default types here with import statements interface DBAidlInterface { /** * 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); List<User> getUsers(); }
内容只需要两行package com.example.testapp.database;//设置User所在包名 parcelable User;//声明User为parcelable类型
/* * This file is auto-generated. DO NOT MODIFY. */ package com.example.testapp.database; // Declare any non-default types here with import statements public interface DBAidlInterface extends android.os.IInterface { /** Default implementation for DBAidlInterface. */ public static class Default implements com.example.testapp.database.DBAidlInterface { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException { } @Override public java.util.List<com.example.testapp.database.User> getUsers() throws android.os.RemoteException { return null; } @Override public android.os.IBinder asBinder() { return null; } } /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.example.testapp.database.DBAidlInterface { private static final java.lang.String DESCRIPTOR = "com.example.testapp.database.DBAidlInterface"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.testapp.database.DBAidlInterface interface, * generating a proxy if needed. */ public static com.example.testapp.database.DBAidlInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.testapp.database.DBAidlInterface))) { return ((com.example.testapp.database.DBAidlInterface)iin); } return new com.example.testapp.database.DBAidlInterface.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_basicTypes: { data.enforceInterface(descriptor); int _arg0; _arg0 = data.readInt(); long _arg1; _arg1 = data.readLong(); boolean _arg2; _arg2 = (0!=data.readInt()); float _arg3; _arg3 = data.readFloat(); double _arg4; _arg4 = data.readDouble(); java.lang.String _arg5; _arg5 = data.readString(); this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5); reply.writeNoException(); return true; } case TRANSACTION_getUsers: { data.enforceInterface(descriptor); java.util.List<com.example.testapp.database.User> _result = this.getUsers(); reply.writeNoException(); reply.writeTypedList(_result); return true; } default: { return super.onTransact(code, data, reply, flags); } } } private static class Proxy implements com.example.testapp.database.DBAidlInterface { 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; } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(anInt); _data.writeLong(aLong); _data.writeInt(((aBoolean)?(1):(0))); _data.writeFloat(aFloat); _data.writeDouble(aDouble); _data.writeString(aString); boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().basicTypes(anInt, aLong, aBoolean, aFloat, aDouble, aString); return; } _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public java.util.List<com.example.testapp.database.User> getUsers() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<com.example.testapp.database.User> _result; try { _data.writeInterfaceToken(DESCRIPTOR); boolean _status = mRemote.transact(Stub.TRANSACTION_getUsers, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getUsers(); } _reply.readException(); _result = _reply.createTypedArrayList(com.example.testapp.database.User.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } public static com.example.testapp.database.DBAidlInterface sDefaultImpl; } static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_getUsers = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); public static boolean setDefaultImpl(com.example.testapp.database.DBAidlInterface impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static com.example.testapp.database.DBAidlInterface getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException; public java.util.List<com.example.testapp.database.User> getUsers() throws android.os.RemoteException; }
package com.example.testapp.database; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import java.util.List; public class DBService extends Service { public DBService() { } @Override public IBinder onBind(Intent intent) { return new DBBinder(); } class DBBinder extends DBAidlInterface.Stub{ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public List<User> getUsers() throws RemoteException { //为了方便我的Room配置允许主线程操作,数据很少不会造成ANR List<User> all = UserDatabase.getInstance(getApplicationContext()).getUserDao().getAll(); return all; } } }
<service android:name=".database.DBService" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.example.testapp.aidl"/> </intent-filter> </service>
package com.example.test2app; import androidx.appcompat.app.AppCompatActivity; import android.content.ComponentName; import android.content.ContentValues; 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.view.View; import android.widget.TextView; import android.widget.Toast; import com.example.testapp.database.DBAidlInterface; import com.example.testapp.database.User; import java.util.List; public class MainActivity extends AppCompatActivity { private DBAidlInterface aidlInterface; private TextView textView; private Context mContext; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { aidlInterface = DBAidlInterface.Stub.asInterface(service); Toast.makeText(mContext,"已连接",Toast.LENGTH_LONG).show(); } @Override public void onServiceDisconnected(ComponentName name) { aidlInterface = null; Toast.makeText(mContext,"断开连接",Toast.LENGTH_LONG).show(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.text_view); mContext = this; } @Override protected void onStart() { super.onStart(); Intent intent =new Intent(); //Android现在对隐式意图管理严格,除了要setAction包名也需要设置,这里包名是服务端app的包名 intent.setAction("com.example.testapp.aidl"); intent.setPackage("com.example.testapp"); //绑定服务 bindService(intent,mConnection,Context.BIND_AUTO_CREATE); } @Override protected void onResume() { super.onResume(); } @Override protected void onDestroy() { super.onDestroy(); //解绑服务 unbindService(mConnection); } //Button OnClick方法 public void getData(View view) { if (aidlInterface!=null){ try { List<User> users = aidlInterface.getUsers(); String str = ""; for (User user: users){ str = str + user.getName()+" "; } textView.setText(str); } catch (RemoteException e) { e.printStackTrace(); } }else { } } }
扩展
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算