在封装sdk的过程中,sdk是如何与app进行通信的呢?

总所周知,进程间通信,android的四大组件都是可以做到的,如果大家对其中原理有不明白的可以参照http://blog.csdn.net/toyuexinshangwan/article/details/8640709,这个博客说明得比较清楚。

下面我们主要学习的是,sdk利用aidl服务实现与app之间相互通信。
以下就举我做项目用到的一个demo作为例子,说说aidl服务的用法及使用中会遇到的问题。

demo实现的功能很简单,因为我做的是一个IM的sdk包,所以需要在IM的连接状态发生变化时,去通过app即时展示出来。

那么我们的aidl的服务可以这样设计。

创建一个IXmppConnectCallBack用来给予app实现sdk的连接状态监听。

创建一个IRemoteServiceInterface用来向sdk注册IXmppConnectCallBack的回调方法。

(可能大家对这两个接口关系不太明白,开始我也是;可以认为sdk是一个法院,IRemoteServiceInterface是我们的代表律师,IXmppConnectCallBack就是申诉人;就是申诉人委托律师去法院执行一些工作,个人愚见,哈哈)

// IRemoteServiceInterface.aidl
package com.guiyi.hsim;// Declare any non-default types here with import statementsimport com.guiyi.hsim.IXmppConnectCallBack;interface IRemoteServiceInterface {/*** Often you want to allow a service to call back to its clients.* This shows how to do so, by registering a callback interface with* the service.*/void registerCallback(IXmppConnectCallBack cb);/*** Remove a previously registered callback interface.*/void unregisterCallback(IXmppConnectCallBack cb);
}

// IXmppConnectCallBack.aidl
package com.guiyi.hsim;// Declare any non-default types here with import statementsinterface IXmppConnectCallBack {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/void connectStateChanged(int value);
}

注意点1:添加aidl的时候,如果需要引入别的类,需要手动Import,如上IRemoteServiceInterface 的

import com.guiyi.hsim.IXmppConnectCallBack;

定义两个接口之后,我们需要实现一个service类来运作。

package com.dannytree.mylibrary;import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;import java.util.Timer;
import java.util.TimerTask;/*** Created by kangsq on 2016/7/20.*/
public class RemoteService extends Service {/*** This is a list of callbacks that have been registered with the* service.  Note that this is package scoped (instead of private) so* that it can be accessed more efficiently from inner classes.*/private final static int CONNECITON_STATE_CHANGE = 101;static final RemoteCallbackList<IXmppConnectCallBack> mCallbacks= new RemoteCallbackList<IXmppConnectCallBack>();private int mValue = 0;//private static final int REPORT_MSG = 1;public int FullState = 0;private int tempint = 1;@Overridepublic void onCreate() {//mHandler.sendEmptyMessage(REPORT_MSG);
timer.schedule(task, 10000, 10000); // 10s后执行task,经过10s再次执行
    }Timer timer = new Timer();TimerTask task = new TimerTask() {@Overridepublic void run() {connectionStateChange(tempint++);}};public void connectionStateChange(int state) {/*final int N = mCallbacks.beginBroadcast();Log.d("RemoteService","before handler mCallbacks count....----.=="+N);
*/FullState = state;Log.d("RemoteService", "gettting  FullState...." + state);Message msg = new Message();msg.arg1 = state;msg.what = CONNECITON_STATE_CHANGE;mHandler.sendMessageDelayed(msg, 1000);}@Overridepublic void onDestroy() {// Tell the user we stopped.//Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show();// Unregister all callbacks.
        mCallbacks.kill();Log.d("RemoteService","mCallbacks ..kill ..");// Remove the next pending message to increment the counter, stopping// the increment loop.//mHandler.removeMessages(REPORT_MSG);
    }@Overridepublic IBinder onBind(Intent intent) {Log.d("RemoteService","IRemoteServiceInterface onbind....");return mServiceBinder;// Select the interface to return.  If your service only implements// a single interface, you can just return it here without checking// the Intent./*if (IRemoteServiceInterface.class.getName().equals(intent.getAction())) {Log.d("RemoteService","IRemoteServiceInterface onbind....");return mServiceBinder;}Log.d("RemoteService","nothing onbind....");return null;*/}/*** The IRemoteInterface is defined through IDL*/private final IRemoteServiceInterface.Stub mServiceBinder = new IRemoteServiceInterface.Stub() {public void registerCallback(IXmppConnectCallBack cb) {if (cb != null) {boolean aa = mCallbacks.register(cb);Log.d("RemoteService", "mCallbacks ..register successed.?" + aa);// int bb = mCallbacks.beginBroadcast();// Log.d("RemoteService", "mCallbacks ..count ?" + bb);
            }}public void unregisterCallback(IXmppConnectCallBack cb) {if (cb != null) mCallbacks.unregister(cb);}};@Overridepublic void onTaskRemoved(Intent rootIntent) {Toast.makeText(this, "Task removed: " + rootIntent, Toast.LENGTH_LONG).show();}/*** Our Handler used to execute operations on the main thread.  This is used* to schedule increments of our value.*/private final Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case CONNECITON_STATE_CHANGE:Log.d("RemoteService","getting mHandler....");int state_enum = (int) msg.arg1;final int N = mCallbacks.beginBroadcast();Log.d("RemoteService","mCallbacks count....----.=="+N);for (int i = 0; i < N; i++) {try {Log.d("RemoteService","mCallbacks sending....----.=="+state_enum);mCallbacks.getBroadcastItem(i).connectStateChanged(state_enum);} catch (RemoteException e) {// The RemoteCallbackList will take care of removing// the dead object for us.Log.d("RemoteService","getting mHandler. getBroadcastItem error...");}}mCallbacks.finishBroadcast();break;}}};
}

注意点2:onBind方法中必须返回一个IBinder ,否则app端bindservice的时候可能会失败。

注意点3:通过RemoteCallbackList来删除跨进程listener的接口。用于解决无法删除对应listener对象。因为是客户端传递给服务端的对象在服务端会生成一个不同的对象,但它们底层的Binder对象是同一个,利用这个特点,找出那个和解注册listener具有相同Binder对象的服务端listener并把它删除掉。另外,当客户端进程终止后,它能够自动移除客户端所注册的listener。

static final RemoteCallbackList<IXmppConnectCallBack> mCallbacks= new RemoteCallbackList<IXmppConnectCallBack>();

注意点4:上述变量最初只有final,所以mCallbacks.beginBroadcast()一直返回0,导致app无法接收到sdk端的通知。原来是因为final在类的每次调用中,都会初始化一遍。基础不扎实啊

至此,sdk封装就完成了,app端已经可以正常收到回调

package com.dannytree.testusingaidl;import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Toast;import com.dannytree.mylibrary.IRemoteServiceInterface;
import com.dannytree.mylibrary.IXmppConnectCallBack;
import com.dannytree.mylibrary.RemoteService;public class MainActivity extends Activity implements View.OnClickListener{IRemoteServiceInterface m_remoteServiceInterface =null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.btn_bind).setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.btn_bind:Intent intent = new Intent(this, RemoteService.class);//intent.setPackage("com.guiyi.hsim");//注意这里的Context.BIND_AUTO_CREATE,这意味这如果在绑定的过程中,//如果Service由于某种原因被Destroy了,Android还会自动重新启动被绑定的Service。// 你可以点击Kill Process 杀死Service看看结果
                bindService(intent,mConnection, Context.BIND_AUTO_CREATE);//mIsBound = true;//mCallbackText.setText("Binding.");break;}}@Overrideprotected void onDestroy() {super.onDestroy();if (m_remoteServiceInterface != null) {try {m_remoteServiceInterface.unregisterCallback(Act_mCallback);} catch (RemoteException e) {// There is nothing special we need to do if the service// has crashed.
            }}unbindService(mConnection);//unbindService(mcallbackConnection);
    }/*** Class for interacting with the main interface of the service.*/private ServiceConnection mConnection = new ServiceConnection() {public void onServiceConnected(ComponentName className,IBinder service) {Log.d("abrahamkang", "========= inside====onServiceConnected");// This is called when the connection with the service has been// established, giving us the service object we can use to// interact with the service.  We are communicating with our// service through an IDL interface, so get a client-side// representation of that from the raw service object.m_remoteServiceInterface = IRemoteServiceInterface.Stub.asInterface(service);//mKillButton.setEnabled(true);//mCallbackText.setText("Attached.");// We want to monitor the service for as long as we are// connected to it.try {m_remoteServiceInterface.registerCallback(Act_mCallback);Log.d("abrahamkang", "=============registerCallback");} catch (RemoteException e) {// In this case the service has crashed before we could even// do anything with it; we can count on soon being// disconnected (and then reconnected if it can be restarted)// so there is no need to do anything here.Log.d("abrahamkang", "=============registerCallback error"+e.toString());}// As part of the sample, tell the user what happened./*Toast.makeText(BindActivity.this, R.string.remote_service_connected,Toast.LENGTH_SHORT).show();*/}public void onServiceDisconnected(ComponentName className) {// This is called when the connection with the service has been// unexpectedly disconnected -- that is, its process crashed.m_remoteServiceInterface = null;Log.d("abrahamkang", "=============onServiceDisconnected ");
//            mKillButton.setEnabled(false);
//            mCallbackText.setText("Disconnected.");// As part of the sample, tell the user what happened.
//            Toast.makeText(BindActivity.this, R.string.remote_service_disconnected,
//                    Toast.LENGTH_SHORT).show();
        }};/*** 远程回调接口实现*/private IXmppConnectCallBack Act_mCallback = new IXmppConnectCallBack.Stub() {@Overridepublic void connectStateChanged(int state) throws RemoteException {Toast.makeText(MainActivity.this, "Connection state is " + state, Toast.LENGTH_SHORT).show();}};
}

注意点5:在app中的AndroidManifest.xml中需要添加与sdk中service一致的包名才能bindservice成功。

<service    android:name="com.dannytree.mylibrary.RemoteService"    ></service>

转载于:https://www.cnblogs.com/treekang/p/5715277.html

aidl实现进程间通信相关推荐

  1. Android Studio使用AIDL技术进行SDK开发

    前面我们有介绍AIDL的基本用法: Android进程间通信--AIDL Android进程间通信--AIDL Binder连接池 现在我们来介绍利用AIDL来实现一个简陋的SDK,将获取用户信息的方 ...

  2. android中进程间通信的几种方式

    进程间通信(IPC)方式 使用Bundle 使用文件共享 使用Messenger 使用AIDL 使用COntentProvider 使用Socket 一.使用Bundle 我们都知道Android中三 ...

  3. Android中进程间通信(IPC)方式总结

    IPC为进程间通信或跨进程通信,是指两个进程进行进程间通信的过程.在PC和移动设备上一个进程指的是一个程序或者一个应用,所以我们可以将进程间通信简单理解为不同应用之间的通信,当然这种说法并不严谨. 在 ...

  4. Android DeadObjectException 异常 aidl通信

    一.异常原因 在使用aidl进行进程间通信时,有时候在客户端调用服务端的接口会抛出DeadObjectException异常,原因一般是由于某种原因服务端程序崩溃重启或者服务对象由于内存紧张被回收导致 ...

  5. 使用AIDL+动态代理+运行时注解+反射 反手撸一套Android跨进程通信框架

    IPC 前言 跨进程通信方式 跨进程通信框架 涉及到的技术 使用Request-Response思想 IPCRequest IPCResponse RemoteService 服务端 客户端 附带 项 ...

  6. Android应用内多进程分析和研究

    正常情况下,一个apk启动后只会运行在一个进程中,其进程名为AndroidManifest.xml文件中指定的应用包名,所有的基本组件都会在这个进程中运行.但是如果需要将某些组件(如Service.A ...

  7. 高级Android开发面试汇总

    高级 Android 开发面试题汇总 一. Android 基础 1. Service 的两种启动方式 简单的来说就是 直接启动 和 绑定启动 两种方式. // 直接启动 Context.startS ...

  8. Android性能优化面试题,与性能优化相关面试题 - 与IPC机制相关面试题 - 《Android面试宝典》 - 书栈网 · BookStack...

    源码分析相关面试题 Activity相关面试题 与XMPP相关面试题 与性能优化相关面试题 与登录相关面试题 与开发相关面试题 与人事相关面试题 与人事相关面试题现在三四月份,金三银四最好找工作时间, ...

  9. 聊聊Service(一)

    Service作为Android中四大组件之一,拥有重要的地位.Service具有和Activity一样的级别,只是没有界面,是运行于后台的服务.这个运行"后台"是指不可见,不是指 ...

最新文章

  1. itest系统学生登录不了_四川省中小学生艺术测评管理系统登录平台https://www.soyohui.com/app/165187/...
  2. sysbench压测Oracle
  3. JPress v2.0-rc.5 发布,同时新官网上线
  4. 关于MySQL count(distinct) 逻辑的另一个bug_
  5. 简述驱动桥的动力传递路线_卡车驱动桥中的差速锁究竟有多大的作用?它是如何起作用的?...
  6. 台湾计算机读研,台湾省计算机考研_会考教育名副其实
  7. 别让自己成为一名废弃的程序员
  8. co88 sap 实际结算_SAP 物料帐的基本原理
  9. 【iOS 15】iPhone如何录屏?iPhone屏幕录制技巧分享
  10. 关于手机号不能登录微信解决办法
  11. SAP中PR/PO创建技巧之缺省值个人设置
  12. c++实现矩阵乘法关系矩阵乘法
  13. 古筝d调变降e调怎么办_为什么古筝总要调音、还总调不好?
  14. Hangfire使用MySQL出现The Command Timeout expired before the operation completed
  15. pid file /opt/zbox/tmp/apache/httpd.pid overwritten -- Unclean shutdown of previous Apache run?
  16. luogu P3324 [SDOI2015]星际战争
  17. 阿里飞猪一员工贩卖机票报销发票获利超千万被判六年
  18. 赞 ( 84 ) 微信好友 新浪微博 QQ空间 180 SSD故事会(14):怕TLC因为你不了解!【转】...
  19. 简单理解目标检测的IOU究竟是什么
  20. Java--身份证号校验

热门文章

  1. 把本地mysql备份到服务器innodb_使用mysql备份工具innobackupex将本地数据 直接恢复 到远端服务器数据目录操作实例...
  2. in the java search_Search API – Using scrolls in Java - Elasticsearch Java API 手册
  3. isdigit函数在C语言什么意思,C 库函数 isdigit() 使用方法及示例
  4. 64位游戏找call_《使命召唤16:战区》配置注册登录全攻略,三步让你极迅游戏!...
  5. java vuser脚本_loadrunner12中JavaVuser脚本的编写
  6. springboot +security +mybatis+thymeleaf 实现简单的用户 角色 权限(资源) 管理
  7. 8 iOS中KVO 的本质
  8. iOS开发业界毒瘤 Hook
  9. 绝对定位下margin的作用
  10. VMware前路难测,多个厂家群雄逐鹿