Android实现组件之间同步的回调通信

Android开发中,有时会遇到组件之间相互通信回调的问题。一般都是通过Android提供的ResultReceiver来实现(ResultReceiver的使用方法很简单,这里就不多提了)。

但之前在工作中,遇到了一个组件间回调的问题,ResultReceiver无法满足需求。简单描述一下问题:service中打开了一个activity,activity需要将一个变量值回调给service,而且这个回调必须是同步的。也就是说activity在确认service接收到了这个变量值后,才能继续向下执行代码。众所周知ResultReceiver的send方法是异步的,send方法执行后,接收方可能还没有收到消息。这样"不及时"的回调在我的项目中可能会造成状态不同步。

那么,只能自己实现一个同步的回调通信。

同步的回调通信代码如下:

github地址:https://github.com/yuhaiyang89/yhy-utils

1.定义一个AIDL

package com.yhy.utils;
interface IChannel {
     void send(int code, in Bundle data);
}

2.定义一个类,实现Parcelable(实现Parcelable是为了能让该类在组件中传递),并在此类中实现第一步定义的AIDL(通过这个AIDL完成回调)

package com.yhy.utils.demo;

import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import com.yhy.utils.IChannel;

public class SyncResultReceiver implements Parcelable {

    public static final Parcelable.Creator<SyncResultReceiver> CREATOR = new Parcelable.Creator<SyncResultReceiver>() {

        public SyncResultReceiver createFromParcel(Parcel in) {
            return new SyncResultReceiver(in);
        }

        public SyncResultReceiver[] newArray(int size) {
            return new SyncResultReceiver[size];
        }
    };

    // 是本地回调还是远程回调
    final boolean mLocal;

    IChannel mBridge;

    public SyncResultReceiver() {
        mLocal = true;
    }

    SyncResultReceiver(Parcel in) {
        mLocal = false;
        mBridge = IChannel.Stub.asInterface(in.readStrongBinder());
    }

    public void send(int code, Bundle data) {
        if (mLocal) {
            onReceiveResult(code, data);
            return;
        }

        if (mBridge != null) {
            try {
                mBridge.send(code, data);
            } catch (Exception e) {
                Log.e("", "",e);
            }
        }
    }

    protected void onReceiveResult(int code, Bundle bundle) {
        // 等待子类去实现此方法,接收消息
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel out, int flags) {
        synchronized (this) {
            if (mBridge == null) {
                mBridge = new MyChannel();
            }
            out.writeStrongBinder(mBridge.asBinder());
        }
    }

    class MyChannel extends IChannel.Stub {
        public void send(int code, Bundle data) {
            onReceiveResult(code, data);
        }
    }
}

实现完毕!

下面就可以使用SyncResultReceiver来实现同步回调了

例:MainActivity中打开Activity2,Activity2将一些消息同步的回调给MainActivity

MainActivity代码:

package com.yhy.utils.demo;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private int value = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 重写SyncResultReceiver的onReceiveResult方法接收返回值
        SyncResultReceiver mResultReceiver = new SyncResultReceiver(){
            @Override
            protected void onReceiveResult(int code, Bundle bundle) {

                value = bundle.getInt("value");
                Log.d("TEST", "code=" + code + " | value = " + value);
            }
        };

        // 开启Activity2
        Intent intent = new Intent(this, Activity2.class);
        intent.putExtra("callback", mResultReceiver);
        startActivity(intent);
    }
}

Activity2代码:

package com.yhy.utils.demo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class Activity2 extends AppCompatActivity {

    SyncResultReceiver mReceiver = null;

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

        mReceiver = getIntent().getParcelableExtra("callback");

        // 给MainActivity回调值
        Bundle bundle = new Bundle();
        bundle.putInt("value", 1);
        mReceiver.send(1, bundle);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // 给MainActivity回调值
        Bundle bundle = new Bundle();
        bundle.putInt("value", 2);
        mReceiver.send(1, bundle);
    }

    @Override
    protected void onDestroy() {
        // 给MainActivity回调值
        Bundle bundle = new Bundle();
        bundle.putInt("value", 3);
        mReceiver.send(1, bundle);
        super.onDestroy();
    }
}

LOG输出:

03-03 11:50:28.780 2790-2790/? D/TEST: code=1 | value = 1
03-03 11:50:28.782 2790-2790/? D/TEST: code=1 | value = 2
03-03 11:53:07.588 2790-2790/? D/TEST: code=1 | value = 3

				
时间: 2024-10-12 09:26:52

Android实现组件之间同步的回调通信的相关文章

深入分析:Android中app之间的交互(二,使用ComponentName)

在前一篇相关主题的博文中我们了解了如何使用Action来启动当前应用之外的Activity处理我们的业务逻辑,在本篇笔记中我在简单介绍一下使用ComponentName来与当前应用之外的应用进行交互. 在介绍Component之前,我们首先来了解ComponentName这个类:ComponentName与Intent同位于android.content包下,我们从Android官方文档中可以看到,这个类主要用来定义可见一个应用程序组件,例如:Activity,Service,Broadcast

使用Broadcast实现android组件之间的通信

android组件之间的通信有多种实现方式.Broadcast就是当中一种. 在activity和fragment之间的通信,broadcast用的很多其它本文以一个activity为例. 效果如图: 布局文件: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" andro

Android业务组件化之子模块SubModule的拆分以及它们之间的路由Router实现

前言: 前面分析了APP的现状以及业务组件化的一些探讨(Android业务组件化之现状分析与探讨),以及通信的桥梁Schema的使用(Android业务组件化之URL Schema使用),今天重点来聊下子模块SubModule的拆分以及它们之间的路由Router实现.本篇涉及的相关知识比较多,阅读本篇之间需要大致了解一下Java的注解(Java学习之注解Annotation实现原理).Java的动态代理机制(Java设计模式之代理模式(Proxy))等.业务组件化是一个循序渐进的过程,一开始很难

Android应用程序组件之间的通信Intent和IntentFilter

Android应用程序的基本组件,这些基本组建除了Content Provider之外,几乎全部都是依靠Intent对象来激活和通信的. 下面介绍Intent类,并通过例子来说明Intent一般用法 1.1 Intent类简介 Intent类的对象是组件间通信的载体,组件之间进行通信就是一个个Intent对象在不断地传递.Intent对象主要作用于运行在相同或不同应用程序的Activity,Service和Broadcast Receiver组件之间,对于这3种组件,其作用机制也不相同 一,对于

EventBus作为组件之间通信

1.为何要使用EventBus? 一般我们在不同activty等组件之间通信的时候,都用到了如下的模式: 就是定义一个接口,需要关注该事件的地方来实现这个接口.然后事件触发的地方来注册/取消注册这些对该事件感兴趣的控件,比如如下文章描述的情况: 使用Event Bus模式解耦Android App组件间通信 这样做的问题也是显而易见的,就是不同组件之间往往耦合的比较厉害,越来越多的接口也维护很麻烦,这样就需要用到EventBus模式来解决组件之低耦合的间通信 2.EventBus类库介绍 Eve

Vue2.0组件之间通信

Vue中组件这个特性让不少前端er非常喜欢,我自己也是其中之一,它让前端的组件式开发更加合理和简单.笔者之前有写过一篇Vue2.0子父组件通信,这次我们就来聊一聊平级组件之间的通信. 首先我们先搭好开发环境,我们先得装好git和npm这两个工具(如果有不清楚的同学请自行百度哦) 环境搭建步骤: 打开git ,运行 npm install --global vue-cli 这是安装vue的命令行 vue init webpack vue-demo 这是vue基于webpack的模板项目 cd vu

组件之间的通信

react推崇的是单向数据流,自上而下进行数据的传递,但是由下而上或者不在一条数据流上的组件之间的通信就会变的复杂.解决通信问题的方法很多,如果只是父子级关系,父级可以将一个回调函数当作属性传递给子级,子级可以直接调用函数从而和父级通信. 组件层级嵌套到比较深,可以使用上下文Context来传递信息,这样在不需要将函数一层层往下传,任何一层的子级都可以通过this.context直接访问. 兄弟关系的组件之间无法直接通信,它们只能利用同一层的上级作为中转站.而如果兄弟组件都是最高层的组件,为了能

vue2.0嵌套组件之间的通信($refs,props,$emit)

vue的一大特色就是组件化,所以组件之间的数据交互是非常重要,而我们经常使用组件之间的通信的方法有:props,$refs和emit. 初识组件之间的通信的属性和方法 props的使用 子组件使用父组件的数据,使用vue的属性props. 当我们在父组件parent里面嵌套一个子组件son的时候,如果我们需要使用父组件的数据的时候,我们可以在子组件标签上面绑定一个属性,然后在子组件里面通过props来调用这个属性,就可以使用这个数据了. //父组件 <sonPart :list="list

Android组件之间的信使——Intent

从一个Activity启动到另一个Activity可以使用startActivity()方法或者是startActivityForResult()方法 第一种:直接启动一个ActivityIntent intent = new Intent(Main.this, SecondActivity.class);startActivity(intent); 第二种:启动另一个Activity并返回结果作用:当从第二个Activity回跳到前一个Activity的时候,就不再需要使用startActiv