Android实现跨进程接口回掉的方法

前言

同一个进程内实现接口回掉很简单,这里不做叙述,本文主要讲的是跨进程的接口回掉实现方式。有一种跨进程通信的方式就是使用AIDL,但是单纯的AIDL通信只可以实现客户端访问服务端主动获取Binder对象,如果服务端有变化无法及时通知客户端。现在可以通过AIDL跨进程接口回掉来解决服务端发生变化通知客户端的问题。

谷歌提供了RemoteCallbackList来实现对IInterface的管理。public class RemoteCallbackList<E extends IInterface>

首先定义两个AIDL文件:

1.ITestCallBack.aidl

interface ITestCallBack {
 /**
  * Demonstrates some basic types that you can use as parameters
  * and return values in AIDL.
  */
 void onTagValid(in String tag);

}

2.ITestInterface.aidl    在注册和反祖册方法中,需要传入ITestCallBack的对象

interface ITestInterface {
 /**
  * Demonstrates some basic types that you can use as parameters
  * and return values in AIDL.
  */
  boolean isTagValid(in String tag);

  void registerCallback(in String tag, in ITestCallBack callback);

  void unRegisterCallback(in String tag, in ITestCallBack callback);
}

服务端:

创建Service,并且在service中定义RemoteCallbackList集合,实现ITestInterface.Stub,在registerCallback,和unRegisterCallback中,分别将ITestCallBack对象注册和反注册进RemoteCallbackList中。RemoteCallbackList提供了获取注册进去的IInterface对象方法

//其实RemoteCallbackList类似于java中{@link java.util.Observable},用来批量处理接口回调对象,
//其实如果确保只有一个客户端会bind到这个服务,只需要保存一个IMyAidlInterfaceCallback即可。
//但是如果有多个,强烈推荐使用其实RemoteCallbackList

public void callBack() {
 if (mCallBacks == null) {
  return;
 }
 int num = mCallBacks.beginBroadcast();
 for (int i = 0; i < num; i++) {
  try {
   mCallBacks.getBroadcastItem(i).onTagValid("congratulation callback success " + tag);
  } catch (RemoteException e) {
   e.printStackTrace();
  }
 }
 //结束后一定要使用finsh,否则下次执行beginBroadcast会抛出IllegalStateException异常
 mCallBacks.finishBroadcast();
}

在isTagValid中可以调用callBack方法去遍历注册的接口对象,也可以当服务端有变化时主动调用callBack方法去通知客户端,这样就实现了服务端变化主动通知客户端。可根据实际方法修改。

在service的onBind方法中,返回ITestInterface.Stub的对象即可,等待客户端绑定服务端。

下面是服务端Service的代码:

public class TestService extends Service {

 private RemoteCallbackList<ITestCallBack> mCallBacks = new RemoteCallbackList<>();
 private String tag = "hy";

 public TestService() {
 }

 @Override
 public IBinder onBind(Intent intent) {
  // TODO: Return the communication channel to the service.
  return iTestInterface;
 }

 @Override
 public boolean onUnbind(Intent intent) {
  return super.onUnbind(intent);
 }

 ITestInterface.Stub iTestInterface = new ITestInterface.Stub() {
  @Override
  public boolean isTagValid(String tag) throws RemoteException {
   if (tag.equals(TestService.this.tag)) {
    callBack();
    return true;
   }
   return false;
  }

  @Override
  public void registerCallback(String tag, ITestCallBack callback) throws RemoteException {
   if (null != mCallBacks && null != callback) {
    mCallBacks.register(callback);
   }
  }

  @Override
  public void unRegisterCallback(String tag, ITestCallBack callback) throws RemoteException {
   if (null != mCallBacks && null != callback) {
    mCallBacks.unregister(callback);
   }
  }
 };

 public void callBack() {
  if (mCallBacks == null) {
   return;
  }
  int num = mCallBacks.beginBroadcast();
  for (int i = 0; i < num; i++) {
   try {
    mCallBacks.getBroadcastItem(i).onTagValid("congratulation callback success " + tag);
   } catch (RemoteException e) {
    e.printStackTrace();
   }
  }
  mCallBacks.finishBroadcast();
 }
}

客户端:

客户端首先要做的是绑定服务端,实现AIDL的通信,在客户端创建绑定按钮,解绑按钮,和主动获取信息的通信按钮。在主动获取信息的通信按钮中实现iTestInterface对象的isTagValid方法可以主动去获取服务端的信息(服务端在isTagValid方法中调用了callBack方法)。

客户端代码:

public class MainActivity extends AppCompatActivity {

 private String tag = "hy";
 private ITestInterface iTestInterface;
 private ServiceConnection connection = new ServiceConnection() {
  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   iTestInterface = ITestInterface.Stub.asInterface(service);
  }

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

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  bindService();
  ((Button) findViewById(R.id.buttonregister)).setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    try {
     iTestInterface.registerCallback(tag, new ITestCallBack.Stub() {
      @Override
      public void onTagValid(String tag) throws RemoteException {
       Log.e("test", "registerCallback: " + tag);
      }
     });
    } catch (RemoteException e) {
     e.printStackTrace();
    }
   }
  });

  ((Button) findViewById(R.id.buttonunregister)).setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    try {
     iTestInterface.unRegisterCallback(tag, new ITestCallBack.Stub() {
      @Override
      public void onTagValid(String tag) throws RemoteException {

      }
     });
    } catch (RemoteException e) {
     e.printStackTrace();
    }
   }
  });

  ((Button) findViewById(R.id.buttonisvalid)).setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    try {
     iTestInterface.isTagValid(tag);
    } catch (RemoteException e) {
     e.printStackTrace();
    }
   }
  });
 }

 private void bindService() {
  Intent intent = new Intent();
  intent.setAction("com.example.heyang.myapplication.TestService");
  intent.setPackage("com.example.heyang.myapplication");
  boolean success = bindService(intent, connection, Context.BIND_AUTO_CREATE);
  if (success) {
   Log.e("test ", "bindService OK");
  } else {
   Log.e("test ", "bindService Fail");
  }
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
  unBindeService();
 }

 private void unBindeService() {
  try {
   unbindService(connection);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • Android AIDL实现两个APP间的跨进程通信实例

    本文为大家分享了Android AIDL实现两个APP间的跨进程通信实例,供大家参考,具体内容如下 1 Service端创建 首先需要创建一个Android工程然后创建AIDL文件,创建AIDL文件主要为了生成继承了Binder的Stub类,以便应用Binder进行进程间通信 servier端结构如下 AIDL代码如下 // IBookManager.aidl package com.example.bookserver.aidl; // Declare any non-default type

  • Android 跨进程SharedPreferences异常详解

    Android 跨进程SharedPreferences异常详解 Context c = null; try { c = context.createPackageContext(PREFERENCE_PACKAGE, Context.CONTEXT_IGNORE_SECURITY); } catch (NameNotFoundException e) { e.printStackTrace(); } if (c != null) { SharedPreferences infoSp = c.g

  • Android 跨进程通Messenger(简单易懂)

    不需要AIDL也不需要复杂的ContentProvider,也不需要SharedPreferences或者共享存储文件! 只需要简单易懂的Messenger,它也称为信使,通过它可以在不同进程中传递message对象,在message中放入我们需要传递的数据你就可以实现跨进程通讯和传递数据.废话不多说,直接上代码. 首先是服务端: public class Ser extends Service{ @Override public IBinder onBind(Intent intent) {

  • Android应用程序四大组件之使用AIDL如何实现跨进程调用Service

    一.问题描述 Android应用程序的四大组件中Activity.BroadcastReceiver.ContentProvider.Service都可以进行跨进程.在上一篇我们通过ContentProvider实现了不同应用之间的跨进程调用,但ContentProvider主要是提供数据的共享(如sqlite数据库),那么我们希望跨进程调用服务(Service)呢?Android系统采用了远程过程调用(RPC)方式来实现.与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言

  • Android IPC机制利用Messenger实现跨进程通信

    写作原因:跨进程通信的实现和理解是Android进阶中重要的一环.下面博主分享IPC一些相关知识.操作及自己在学习IPC过程中的一些理解.这一章使用Messenger实现跨进程通信,其中bindService基础部分参见Android IPC机制绑定Service实现本地通信. 跨进程简介 在介绍使用Messenger跨进程通信之前先要了解以下问题:为什么需要跨进程通信?只有有了需求才有学习的价值.我个人将不同进程简单的理解为不同的应用程序(当然也有例外,比如可以在同一个应用程序中开启两个或多个

  • Android通过RemoteViews实现跨进程更新UI示例

    一.概述 前面一篇文章Android通过AIDL实现跨进程更新UI我们学习了aidl跨进程更新ui,这种传统方式实现跨进程更新UI是可行的,但有以下弊端: View中的方法数比较多,在IPC中需要增加对应的方法比较繁琐. View的每一个方法都会涉及到IPC操作,多次IPC带来的开销问题不容小觑. View中方法的某些参数可能不支持IPC传输.例如:OnClickListener,它仅仅是个接口没有序列化. 接下来我们通过RemoteViews实现跨进程更新UI 二.实现效果图 在同一个应用中有

  • 详解Android跨进程IPC通信AIDL机制原理

    简介 AIDL:Android Interface Definition Language,即Android接口定义语言,用于生成Android不同进程间进行进程通信(IPC)的代码,一般情况下一个进程是无法访问另一个进程的内存的.如果某些情况下仍然需要跨进程访问内存数据,这时候Android系统就要将其对象分解成能够识别的原数据,编写这一组操作的代码是一项繁琐的工作,但是AIDL对底层进行了抽象的封装,简化了跨进程操作. AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量

  • Android编程实现AIDL(跨进程通信)的方法详解

    本文实例讲述了Android编程实现AIDL(跨进程通信)的方法.分享给大家供大家参考,具体如下: 一. 概述: 跨进程通信(AIDL),主要实现进程(应用)间数据共享功能. 二. 实现流程: 1. 服务器端实现: (1)目录结构,如下图: (2)实现*.aidl文件: A. IAIDLService.aidl实现: package com.focus.aidl; import com.focus.aidl.Person; interface IAIDLService { String getN

  • Android 跨进程模拟按键(KeyEvent )实例详解

      Android 解决不同进程发送KeyEvent 的问题 最近在做有关于Remote Controller 的功能,该功能把手机做成TV的遥控器来处理.在手机的客户端发送消息到TV的android 服务端,服务端接收到客户端的请求消息,模拟KeyEvent命令,发送Key值. 最简单的发送命令为如下代码: public static void simulateKeystroke(final int KeyCode) { new Thread(new Runnable() { public v

  • Android跨进程抛异常的原理的实现

    今天接到了个需求,需要用到跨进程抛异常. 怎样将异常从服务端抛到客户端 也就是说在Service端抛出的异常需要可以在Client端接收.印象中binder是可以传异常的,所以aidl直接走起: // aidl文件 interface ITestExceptionAidl { boolean testThrowException(); } // service端实现 public class AidlService extends Service { @Nullable @Override pu

随机推荐