六、AIDL(三)实现回调

一、Service 开启和停止
二、Service 执行耗时工作
三、IPC常用方式
四、AIDL(一)同一应用中使用AIDL及原理
五、AIDL(二)不同应用中使用、自定义数据类型及定向Tag
六、AIDL(三)实现回调
七、AIDL(四)获取服务及绑定和Binder传递流程


AIDL(三)实现回调

前面AIDL中,都是客服端主动向服务端请求数据,那可不可以注册回调函数,让服务端主动向客户端发送数据呢?分析AIDL特点,可以有两种方式实现服务端主动向客户端传递数据:

  1. 客户端通过绑定服务端的Service,进而与服务端通信,那么反客为服,客户端也可以定义Service,而后服务端通过绑定客户端,进而调用客户端的接口,主动给客户端传递消息。
  2. 客户端绑定了服务端的Service,两者之间就能够通信。实际上服务端传递了Binder给客户端,客户端拿到Binder之后就可以进行通信了,这就说明了Binder对象本身能够跨进程传输。 于是改造之前的接口:客户端调用服务端接口的时候将自己生成的Binder传递给服务端,那么服务端发生变化的时候就可以通过这个Binder来通知客户端了。

通过比对第一和第二种方式,第一种方式过于复杂,对于客户端、服务端的角色容易搞混。 第二种方式符合我们认知中的“回调”,也就是说跨进程的回调和同一个进程里的回调理解上是一致的。

6.1 AIDL回调实现

6.1.1 服务端声明回调接口

代码1

com/ieening/server/ScoreChangedCallback.aidl

// ScoreChangedCallback.aidl
package com.ieening.server;

// Declare any non-default types here with import statements
import com.ieening.server.Student; // 注释1

interface ScoreChangedCallback {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    oneway void onCallback(in Student student); // 注释2
}
  1. 注释1:Student是信息类,实现了Parcelable接口;
  2. 注释2:onCallback调用回调函数,in表示数据从服务端传递客户端,oneway表示调用onCallback方法的线程立即返回,不阻塞等待方法调用结果。

6.1.2 服务端暴露注册回调函数接口

服务端定义了回调接口函数,客户端需要给服务端传递接口的实现。因此服务端还需要将注册回调的接口暴露给客户端。 定义AIDL 文件如下:

代码2

com/ieening/server/IStudentInfo.aidl

// IStudentInfo.aidl
package com.ieening.server;

// Declare any non-default types here with import statements
import com.ieening.server.Student;
import com.ieening.server.ScoreChangedCallback;

interface IStudentInfo {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    // 主动获取信息
    Student getStudentInfo();
    // 注册回调函数
    oneway void register(in ScoreChangedCallback callback);
}

至此,服务端提供了两个方法:

  1. getStudentInfo:客户端调用此方法主动获取学生信息。
  2. register:客户端调用此方法注册回调实例。

6.1.3 服务端调用回调函数机制

代码3

com.ieening.server.StudentService

package com.ieening.server;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

import java.util.Objects;

public class StudentService extends Service {
    private Student student;
    private ScoreChangedCallback remoteCallback;
    private boolean serviceThreadStopFlag = false;

    public StudentService() {
    }

    private final IStudentInfo.Stub studentInfoBinder = new IStudentInfo.Stub() { // 注释1
        @Override
        public Student getStudentInfo() {
            return student;
        }

        @Override
        public void register(ScoreChangedCallback callback) {
            remoteCallback = callback;
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        student = new Student("ieening", 28);
        new Thread(() -> { // 注释2
            while (!serviceThreadStopFlag) {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                student.setScore((int) (Math.random() * 100));
                try {
                    if (!Objects.isNull(remoteCallback)) {
                        remoteCallback.onCallback(student);
                    }
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            stopSelf();
        }).start();
    }

    @Override
    public void onDestroy() {
        serviceThreadStopFlag = true;
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return studentInfoBinder;
    }
}
  1. 注释1:传递给客户端Binder
  2. 注释2:每秒更新分数,并在更新后主动调用remoteCallback.onCallback,进行回调操作,回调接口Binder是客户端传递给服务端;

6.1.4 客户端调用逻辑

客户端需要完成的工作:

  1. 注释1:绑定服务;
  2. 注释2:发送getStudentInfo请求,手动更新Student信息;
  3. 注释3:自定义ServiceConnection,并创建实例,在onServiceConnected中,接收服务端传递过来的IStudentInfo Binder ,并调用其中register函数,注册回调,原理是将ScoreChangedCallback.Stub传递给服务端,服务端每次更新studen info后,主动调用,将结果反馈至客户端,实现自动更新Student信息。

代码4

com.ieening.androidipccallback.MainActivity

package com.ieening.androidipccallback;

......

public class MainActivity extends AppCompatActivity {
    ......

    private IStudentInfo studentServiceRemoteBinder = null;

    Handler studentInfoHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            if (msg.what == 1) {
                Student student = (Student) Objects.requireNonNull(msg.getData().getParcelable("student"));
                binding.studentInfoAutoUpdateEditText.setText(student.toString());
            }
        }
    };
    ServiceConnection serviceConnection = new ServiceConnection() { // 注释3

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            studentServiceRemoteBinder = IStudentInfo.Stub.asInterface(service);
            try {
                studentServiceRemoteBinder.register(new ScoreChangedCallback.Stub() {
                    @Override
                    public void onCallback(Student student) {
                        //在子线程中创建一个消息对象
                        Message studentInfoMessage = new Message();
                        studentInfoMessage.what = 1;
                        Bundle bundle = new Bundle();
                        bundle.putParcelable("student", student);
                        studentInfoMessage.setData(bundle);
                        //将该消息放入主线程的消息队列中
                        studentInfoHandler.sendMessage(studentInfoMessage);
                    }

                });
            } catch (RemoteException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            studentServiceRemoteBinder = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ......

        setBindUnbindButtonOnClickListener();

        binding.getStudentInfoButton.setOnClickListener(v -> { // 注释2
            try {
                binding.studentInfoEditText.setText(studentServiceRemoteBinder.getStudentInfo().toString());
            } catch (RemoteException e) {
                throw new RuntimeException(e);
            }
        });
    }

    private void setBindUnbindButtonOnClickListener() {
        binding.bindStudentServiceButton.setOnClickListener(v -> { // 注释1
            Intent bindIntent = new Intent(this, StudentService.class);
            boolean bindResult = bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
            if (bindResult) {
                binding.bindStudentServiceButton.setEnabled(false);
                binding.unbindStudentServiceButton.setEnabled(true);
                binding.getStudentInfoButton.setEnabled(true);
                Toast.makeText(this, "bind student service success", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "bind student service failed", Toast.LENGTH_SHORT).show();
            }

        });
        binding.unbindStudentServiceButton.setOnClickListener(v -> {
            unbindService(serviceConnection);
            binding.bindStudentServiceButton.setEnabled(true);
            binding.unbindStudentServiceButton.setEnabled(false);
            binding.getStudentInfoButton.setEnabled(false);
        });
    }

    @Override
    protected void onDestroy() {
        if (!Objects.isNull(studentServiceRemoteBinder) && studentServiceRemoteBinder.asBinder().isBinderAlive()) {
            unbindService(serviceConnection);
        }
        super.onDestroy();
    }
}

6.2 实现效果

测试代码 – AndroidIPCCallback

aidlCallbackApplicationDemo

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值