Android 进程间通信(AIDL)使用详解

作者: IT软件人 | 来源:发表于2016-12-30 15:47 被阅读123次

    AIDL简介
    AIDL是AndroidInterface definition language的缩写,它是一种Android内部进程通信接口的描述语言。

    AIDL使用场景
    例如有两个应用应用A和应用K,我们在应用A中绑定了一个Service,并且给对应的数据成员设置了一些值。而我们想要在应用K中得到应用A设置的值,Android平台是不允许不同进程间进行直接通讯的而且不同进程之间也不能通过共享内存的方式进行数据通讯,为了使其他的应用K可以访问应用A提供的服务,AIDL就应运而生。

    AIDL使用注意事项
    AIDL只支持方法,不能定义静态成员,并且方法也不能有类似public等的修饰符;AIDL运行方法有任何类型的参数和返回值,AIDL支持的数据类型有Java基本数据类型、String、Map、List。List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的Parcelable,List可以使用泛型。Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的Parcelable,Map是不支持泛型的。

    应用A创建AIDL的步骤
    1.新建aidl文件夹,如下图:

    将焦点移至app上,右键单击,然后New->Folder->AIDL
    2.新建*.aidl文件,如下图:
    将焦点移至aidl文件夹上,右键单击,然后New->AIDL->AIDL File
    3.定义生成的aidl文件内容,代码定义如下:
    interface IMyAidlInterface {  
        void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString);
        int getanInt();
        long getaLong();
        boolean getaBoolean();
        float getaFloat();
        double getaDouble();
        String getaString();
    }
    

    4.继承AIDL文件生成的Java接口Stub,并添加相应的代码实现:

    public class BaseDataType extends IMyAidlInterface.Stub {
        int anInt;
        long aLong;
        boolean aBoolean;
        float aFloat;
        double aDouble;
        String aString;
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
            this.anInt = anInt;
            this.aLong = aLong;
            this.aBoolean = aBoolean;
            this.aFloat = aFloat;
            this.aDouble = aDouble;
            this.aString = aString;
        }
        @Override
        public int getanInt() throws RemoteException {
            return anInt;
        }
        @Override
        public long getaLong() throws RemoteException {
            return aLong;
        }
        @Override
        public boolean getaBoolean() throws RemoteException {
            return aBoolean;
        }
        @Override
        public float getaFloat() throws RemoteException {
            return aFloat;
        }
        @Override
        public double getaDouble() throws RemoteException {
            return aDouble;
        }
        @Override
        public String getaString() throws RemoteException {
            return aString;
        }
    }
    

    PS:IMyAidlInterface.aidl与BaseDataType.java的包名应当是一样的。若想要不一样,请按以下修改build.gradle文件,在 android{} 中间加上下面的内容

    sourceSets {
     main { java.srcDirs = ['src/main/java', 'src/main/aidl']
     }
    }
    

    5.定义一个Service,并将其注册到AndroidManifest.xml文件中:

    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    public class MyRemoteService extends Service {
        IMyAidlInterface.Stub iStub = new BaseDataType();
        public MyRemoteService() {
        }
        @Override
        public IBinder onBind(Intent intent) {
            return iStub;
        }
    }
    
    <service android:name=".MyRemoteService"
        android:enabled="true"
        android:exported="true">
      <intent-filter>
        <action android:name="MyRemoteAIDL" > </action>
      </intent-filter>
    </service>
    

    6.在应用A内设置值:

    public class MyRemoteActivity extends AppCompatActivity {
        IMyAidlInterface iMyAidlInterface;
        View bind;
        View unbind;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_my_remote);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
            FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show();
                }
            });
            bind = findViewById(R.id.bind);
            unbind = findViewById(R.id.unbind);
            bind.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MyRemoteActivity.this, MyRemoteService.class);
                   bindService(intent, conn, Context.BIND_AUTO_CREATE);
                }
            });
        }
        ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
                if (iMyAidlInterface != null) {
                    try {
                        iMyAidlInterface.basicTypes(1024, 2048L, true, 3.14159F, 3.1415926D, "I come from MyRemoteService");
                        android.util.Log.d("RemoteValue", "Set value success!");
                    } catch (Exception e) {
                       android.util.Log.d("RemoteValue", "Set value fail!");
                    }
                } 
           } 
           @Override
            public void onServiceDisconnected(ComponentName name) {
                android.util.Log.d("RemoteValue", "onServiceDisconnected " + name);
            }
        };
    }
    

    至此,同一应用内调用已经完成。
    接下来就是被其它应用调用,也就是我们实例中的应用K调用。
    应用K访问应用A中的数据步骤
    1.将应用A的aidl文件拷贝一份到应用K的程序中(这里一定要注意,包路径要和应用A中的保持一致):

    和应用A中的一模一样,直接将其复制到应用K下边即可
    2.应用K访问应用A中的数据
    public class MainActivity extends Activity {
        IMyAidlInterface myAidlInterface;
        View bind;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            bind = findViewById(R.id.bind);
            bind.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent();
                    intent.setAction("MyRemoteAIDL");
                    //此处设置应用A的包名
                    intent.setPackage("qihoo.testcodedemo");
                    Intent newIntent = buildExplicitIntent(MainActivity.this, intent);
                    boolean isbind = getApplicationContext().bindService(newIntent, connection, Context.BIND_AUTO_CREATE);
                }
            });
        }
        public Intent buildExplicitIntent(Context context, Intent intent) {
            PackageManager pm = context.getPackageManager();
            List<ResolveInfo> resolveInfo = pm.queryIntentServices(intent, 0);
            if (resolveInfo == null || resolveInfo.size() != 1) {
                return null;
            }
            // Get component info and create ComponentName
            ResolveInfo serviceInfo = resolveInfo.get(0);
            String packageName = serviceInfo.serviceInfo.packageName;
            String className = serviceInfo.serviceInfo.name;
            ComponentName component = new ComponentName(packageName, className);
            // Create a new intent. Use the old one for extras and such reuse
            Intent explicitIntent = new Intent(intent);
            // Set the component to be explicit
            explicitIntent.setComponent(component);
            return explicitIntent;
        }
        ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                myAidlInterface = IMyAidlInterface.Stub.asInterface(service);
                if (myAidlInterface != null) {
                    try {
                        android.util.Log.e("RemoteService", " " + myAidlInterface.getanInt());
                        android.util.Log.e("RemoteService", myAidlInterface.getaString());
                    } catch (Exception e) {
                    }
                }
            }
            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        };
    }
    

    PS:将两个App同时运行在同一台手机上,可访问正确的数据值;
    至此,通过AIDL的方式进行两个不同App的数据访问已完成;
    敬请各位童鞋关注本人微信公众号“IT软件人”,或扫码关注。

    IT软件人

    热烈欢迎与各位童鞋进行技术交流。

    相关文章

      网友评论

        本文标题:Android 进程间通信(AIDL)使用详解

        本文链接:https://www.haomeiwen.com/subject/zihmvttx.html