远程服务例子3
来源:互联网 发布:网络剧广告植入 编辑:程序博客网 时间:2024/06/04 17:41
本例子将会介绍远程服务回调接口的用法以及注销回调接口的方法、权限校验、远程服务挂掉后重连的方法等。
直接上代码,远程服务aidl接口及服务代码:
package com.example.aidl4.aidl;import java.util.List;import com.example.aidl4.aidl.PersionParcel;interface IAddPersionListener { void addPersion(in PersionParcel newPersion);}
package com.example.aidl4.aidl;import java.util.List;import com.example.aidl4.aidl.PersionParcel;import com.example.aidl4.aidl.IAddPersionListener;interface IPersionBinder { String getName(in PersionParcel p); List<PersionParcel> getAllPersions(); void registerListener(IAddPersionListener listener); void unregisterListener(IAddPersionListener listener);}
public class AidlService extends Service { private static final String mAllowPackages[] = { "com.example.aidl5" }; private AtomicBoolean mIsServiceRunning = new AtomicBoolean(true); private CopyOnWriteArrayList<PersionParcel> mPersionList = new CopyOnWriteArrayList<PersionParcel>(); private RemoteCallbackList<IAddPersionListener> mListenerLists = new RemoteCallbackList<IAddPersionListener>(); @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onCreate() { super.onCreate(); mPersionList.add(new PersionParcel("zhangsan", 20, "男")); new Thread() { @Override public void run() { // 每隔30秒添加一人并调用接口中定义的方法 while (mIsServiceRunning.get()) { SystemClock.sleep(30 * 1000); PersionParcel persionParcel = new PersionParcel("lili", 20, "女"); onAddPersion(persionParcel); } } }.start(); } private void onAddPersion(PersionParcel persionParcel) { mPersionList.add(persionParcel); final int N = mListenerLists.beginBroadcast(); for (int i = 0; i < N; i++) { try { mListenerLists.getBroadcastItem(i).addPersion(persionParcel); } catch (RemoteException e) { e.printStackTrace(); } } mListenerLists.finishBroadcast(); } @Override public void onDestroy() { super.onDestroy(); mIsServiceRunning.set(false); } private Binder mBinder = new IPersionBinder.Stub() { @Override public String getName(PersionParcel p) throws RemoteException { return p.getName(); } @Override public List<PersionParcel> getAllPersions() throws RemoteException { return mPersionList; } @Override public void registerListener(IAddPersionListener listener) throws RemoteException { mListenerLists.register(listener); } @Override public void unregisterListener(IAddPersionListener listener) throws RemoteException { mListenerLists.unregister(listener); }; @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { String pkgName = null; String[] packages = AidlService.this.getPackageManager() .getPackagesForUid(getCallingUid()); if (packages != null && packages.length > 0) { pkgName = packages[0]; } for (String item : mAllowPackages) { if (!item.equals(pkgName)) { System.out.println("pkgName:" + pkgName + "被拒绝访问服务"); return false; } } return super.onTransact(code, data, reply, flags); } };}
客户端调用代码:
public class MainActivity extends Activity { private IPersionBinder mBinder; private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { System.out.println("添加了新人"); }; }; private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { System.out.println("线程名1:" + Thread.currentThread().getName()); if (mBinder == null) { return; } mBinder.asBinder().unlinkToDeath(mDeathRecipient, 0); mBinder = null; // 这里重新绑定远程服务 } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bindAidlService(); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mBinder != null) { try { List<PersionParcel> list = mBinder.getAllPersions(); for (PersionParcel item : list) { System.out.println("姓名:" + item.getName() + ", 年龄:" + item.getAge() + ", 性别:" + item.getSex()); } } catch (RemoteException e) { e.printStackTrace(); } } } }); } @Override protected void onDestroy() { super.onDestroy(); unbindService(mConn); if (mBinder != null && mBinder.asBinder().isBinderAlive()) { try { mBinder.unregisterListener(mListener); } catch (RemoteException e) { e.printStackTrace(); } } } private void bindAidlService() { Intent service = new Intent("com.example.aidl4.AidlService"); bindService(service, mConn, Context.BIND_AUTO_CREATE); } private ServiceConnection mConn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { mBinder = null; System.out.println("线程名:" + Thread.currentThread().getName()); } @Override public void onServiceConnected(ComponentName name, IBinder service) { mBinder = IPersionBinder.Stub.asInterface(service); try { mBinder.registerListener(mListener); service.linkToDeath(mDeathRecipient, 0); } catch (RemoteException e) { e.printStackTrace(); } } }; private IAddPersionListener mListener = new IAddPersionListener.Stub() { @Override public void addPersion(PersionParcel newPersion) throws RemoteException { mHandler.sendEmptyMessage(0); } };}
注销自定义接口时,需要使用RemoteCallbackList,它是系统专门提供的用于删除跨进程listener接口的。
public class RemoteCallbackList<E extends IInterface>
RemoteCallbackList是一个泛型,支持任意的AIDL接口。
工作原理:它内部有一个Map结构专门用来保存所有的AIDL回调,这个Map的key是IBinder类型,value是Callback类型。
ArrayMap<IBinder, Callback> mCallbacks = new ArrayMap<IBinder, Callback>();
其中Callback中封装了真正的远程listener,当客户端注册listener时,它会把这个listener的信息存入mCallbacks中,key和value分别通过下面的方式获得:
IBinder key = listener.asBinder();
Callback value = new Callback(listener, cookie);
虽然说跨进程传输客户端的同一个对象会在服务端生成不同的对象,但是这些新生成的对象有一个共同点,那就是它们底层的Binder对象是同一个。RemoteCallbackList还有一个很有用的功能,那就是当客户端进程终止后,它能够自动移除客户端所注册的listener。
遍历RemoteCallbackList时必须按照代码中所示,其中beginBroadcast和finishBroadcast必须配对使用。
Binder运行在服务端进程,如果服务端进程由于某种原因异常终止,此时客户端到服务端的Binder连接断裂,会导致远程调用失败。为了解决这个问题,BInder提供了两个配对的方法linkToDeath和unlinkToDeath,通过linkToDeath可以给Binder设置一个死亡代理,当Binder死亡时就会收到通知,此时可以重新发起连接请求从而恢复连接。
使用方法如代码上所示。在onServiceDisconnected方法中也可以重连远程服务。另外通过Binder的isBinderAlive方法也可以判定Binder是否死亡。
区别:onServiceDisconnected在客户端的UI线程中被回调,而binderDied是在客户端的Binder线程池中被回调。也就是说,在binderDied方法中不能访问UI。
- 远程服务例子3
- 远程服务例子
- 远程服务例子2
- hessian远程服务调用例子
- 远程服务
- 远程服务
- 服务之远程服务
- 服务(service)-----远程服务
- 9.5.3远程服务协议-Mina协议
- laravel5.3 绑定服务容器例子
- windows2003服务---远程访问服务
- 绑定服务&绑定远程服务
- python pexpect和argparse模块用法例子之确保一批远程机器指定一批服务在运行
- android之旅20 服务3--本地服务与远程服务
- 移值XP远程服务
- jboss 远程访问服务
- 远程安装终端服务
- 远程连接ORACLE服务
- spring——控制反转简单例子 (Spring三种注入方式)
- 域缓存登录
- 在angular中 function中的$scope和$rootscope有什么区别
- ExtJs教程----解决ExtJS 5.1.0.107在IE 浏览器下面会自动将Combobox里面的所有值全都显示出来
- java.util.zip.ZipException: invalid LOC header (bad signature)
- 远程服务例子3
- C#输出到Release
- 锁
- swiper的基础使用(三)
- Android 之nineoldandroids ViewHelper实现动画效果
- java从控制台输出和String的替换
- Java nio 文件操作 Path,Files类详解一
- Java调用批处理文件,Runtime.getRuntime().exec参数,示例
- Kafka 安装和测试