跨进程调用Service

作者: 安卓技术砖家 | 来源:发表于2021-07-21 00:02 被阅读0次

    一、AIDL服务简介

    Android系统中,各应用程序都运行在自己的进程中,进程之间一般无法直接进行数据交换,我们可以通过AIDL实现跨进程调用Service。

    当客户端访问service时,远程Service会通过onBInd()方法将IBinder对象的代理返回给客户端(具体是返回到客户端ServiceConnection的onServiceConnected方法的第二个参数)。当客户端获取了远程Service的IBinder对象的代理之后,就可以通过IBinder对象去回调远程Service的属性和方法了。


    二、AIDL服务端

    1. 创建AIDL文件

    AIDL只是定义两个进程之间的通信接口,其语法与java接口很相似。但存在如下几点差异:

    • AIDL定义接口的源代码必须以.aidl结尾。
    • AIDL接口中用到的数据类型,除了基本类型、String、List、Map、CharSequence之外,其他类型全部都需要导包,即使他们在同一个包中也需要导包。

    定义一个AIDL接口:

    // IUser.aidl
    package com.example1.test.aidl;
    
    // Declare any non-default types here with import statements
    interface IUser {
       String getName();
       int getId();
    }
    

    定义好上面的AIDL接口之后,ADT工具在该接口所在包的目录下生成一个IUser.java接口,在该接口里包含一个Stub内部类,该内部类实现了IBinder、IUser两个接口,这个Stub类将会作为远程Service的回调类——它实现了IBinder接口,因此可以作为Service的onBinder()方法的返回值。

    2. 将接口暴露给客户端—Service实现类

    Service实现类,其中的onBInd()方法返回的IUer.Stub的实例,供其它应用程序的调用并获取service的信息。

    public class AIDLService extends Service{
        private String name;//用户姓名
        private int id;//用户id
        public IUser.Stub userBinder=new IUser.Stub() {
            @Override
            public String getName() throws RemoteException {
                  name="服务端name";
                return name;
            }
    
            @Override
            public int getId() throws RemoteException {
                  id=1001;
                return id;
            }
        };
    
        //返回userBinder对象
        @Override
        public IBinder onBind(Intent intent) {
            /**
             * 在绑定本地Service的情况下,该userBinder对象会直接传给客户端的
             * ServiceConnection对象的onServiceConnected方法的第二个参数
             * 
             * 在绑定远程Service的情况下,只将catBinder对象的代理传给客户端的
             * ServiceConnection对象的onServiceConnected方法的第二个参数
             */
            return userBinder;
        }
    }
    

    3. 配置Service

    完成上面的之后,我们还需要在AndroidManifest.xml文件中配置该Service。如下所示:

    <!--定义一个Service组件-->
    <service android:name=".AIDLService">
        <intent-filter>
            <action android:name="com.example1.test.aidl.AIDLService"/>
        </intent-filter>
    </service>
    

    三、客户端访问AIDLService

    1. 复制AIDL接口

    AIDL定义了两个进程之间的通信接口,因此不仅服务器端需要AIDL接口,客户端同样需要前面定义的AIDL接口,我们只需要直接该接口复制到客户端程序中。

    2. 客户端绑定远程Service

    客户端绑定远程Service只需两步:

    1. 创建ServiceConnection对象
    2. 以ServiceConnection对象作为参数,调用Context的bindService()方法绑定远程Service即可。

    具体的代码如下所示,布局文件中只是添加了一个Button按钮和一个TextView文本控件,此处不展示。

    public class UserInfoActiivity extends AppCompatActivity {
        private IUser userBinder;
        private ServiceConnection sconn=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //获取远程Service的onBind方法返回的对象的代理
                userBinder=IUser.Stub.asInterface(service);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                userBinder=null;
            }
        };
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_user_info_actiivity);
    
            bindRemoteService();//开启远程服务
            final TextView tvUserInfo=findViewById(R.id.tvUserInfo);
            Button btnGetUserInfo=findViewById(R.id.btnGetUserInfo);
            //获取服务端的用户信息
            btnGetUserInfo.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    try {
                        String name=userBinder.getName();
                        int id=userBinder.getId();
                        tvUserInfo.setText("姓名:"+name+'\n'+"id:"+id);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            });
    
        }
    
        //绑定远程服务
        public void bindRemoteService(){
            Intent intent=new Intent();
            intent.setAction("com.example1.test.aidl.IUser");
            ComponentName componentName=new ComponentName("com.example1.test.aidl","com.example1.test.aidl.AIDLService");
            intent.setComponent(componentName);
            bindService(intent,sconn, Service.BIND_AUTO_CREATE);//绑定远程服务
        }
    }
    

    四、运行结果

    启动客户端和服务端的程序,然后点击客户端的获取用户信息的按钮,效果如下:

    安卓_跨进程调用Service_内容1.png

    五、总结

    总结下来就是两个部分,服务端定义AIDL接口,然后实现Service,并在AndroidManifest.xml注册服务;客户端复制服务端的AIDL接口,然后绑定远程服务。

    相关文章

      网友评论

        本文标题:跨进程调用Service

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