深入浅出Android我的Kotlin之旅Java 核心技术

跨进程调用Service

2021-07-21  本文已影响0人  安卓技术砖家

一、AIDL服务简介

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

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


二、AIDL服务端

1. 创建AIDL文件

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

定义一个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接口,然后绑定远程服务。

上一篇下一篇

猜你喜欢

热点阅读