博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Remote Service 和 Local App的交互
阅读量:4544 次
发布时间:2019-06-08

本文共 5445 字,大约阅读时间需要 18 分钟。

名词解释:

Remote Service   -- 远程服务,此服务运行在独立进程。

Local App -- 本地应用,其他想要使用远程服务的app,运行在另外的线程。

远程服务的使用,涉及到进程间通信IPC(Inter-Process Communication),在android中就需要用到AIDL(Android Interface Definition Language) ,关于AIDL的介绍可以参考下面几篇帖子:

官方文档:

博友文档:

               

既然讲到交互,那必须要分为两部分进行:

首先是Local App调用Remote Service

关于这一点,网上已经有大量的说明和范例,简单说明如下:

1,在Remote Service工程中创建aidl接口文件IRemoteService.aidl:

 

package com.walkbin.drill.aidl;interface IRemoteService{    boolean doSomething(String thing);}

在gen目录下,sdk会自动生成对应的java文件。

 

2,新建类RemoteService继承于Service,创建成员mBinder并实现之前在IRemoteService.aidl中定义的接口。

private final IRemoteService.Stub mBinder = new IRemoteService.Stub(){		@Override		public boolean doSomething(String thing) throws RemoteException {			Log.i(TAG, "~~~~i'm doing [" + thing + "]");			return false;		}		};

在onBind方法中返回该mBinder。

 

 

@Override	public IBinder onBind(Intent intent) {		// TODO Auto-generated method stub		Log.i(TAG, "~~~~onBind");		return mBinder;	}

3,在对应的Androidmenifest.xml中注册RemoteService:

android:process=":rmtser" 提示系统将RemoteService放到进程com.walkbin.drill.remoteservice:rmtser中运行,这是一个独立的进程。
<action android:name="com.walkbin.drill.remote_service"/>是对外暴露的名称,外部可以通过这个名字来访问service。

 

4,创建ClientApp项目,将RemoteService中定义的aidl文件复制过来,我们在Activity的onCreate中绑定RemoteService,并设置按键回调,在onDestroy中注意unBindRemoteService。

@Override	protected void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		setContentView(R.layout.activity_main);				Intent i = new Intent("com.walkbin.drill.remote_service");		bindService(i, mSerConn,  BIND_AUTO_CREATE);				Button btn = (Button)findViewById(R.id.btn_do_smt);		btn.setOnClickListener(this);	}	@Override	protected void onDestroy() {		// TODO Auto-generated method stub		unbindService(mSerConn);		super.onDestroy();	}

创建ServiceConnection
        

private IRemoteService mRemoteService;	private static final String TAG = "ClientApp";		private ServiceConnection mSerConn = new ServiceConnection(){		@Override		public void onServiceConnected(ComponentName name, IBinder service) {			// TODO Auto-generated method stub			Log.i(TAG, "~~~~onServiceConnected");			mRemoteService = IRemoteService.Stub.asInterface(service);		}		@Override		public void onServiceDisconnected(ComponentName name) {			// TODO Auto-generated method stub			Log.i(TAG, "~~~~onServiceDisconnected");			mRemoteService = null;		}			};

在按键的回调用,我们调用RemoteService中定义的doSomething方法:

@Override	public void onClick(View v) {		// TODO Auto-generated method stub		switch(v.getId()){			case R.id.btn_do_smt:{				try {					mRemoteService.doSomething("show me!!!");				} catch (RemoteException e) {					// TODO Auto-generated catch block					e.printStackTrace();				}			}break;		}	}

这样第一部分就完成了,ClientApp成功调用了RemoteService中的doSomething方法。
其次让Remote Service能够调用Local App中的方法
因为仍然是跨进程的调用,所以依然要使用aidl方式来实现。
1,同样我们需要定义一个aidl文件来描述,新建IRemoteCB.aidl文件

package com.walkbin.drill.aidl;interface IRemoteCB{    void callSomething(String thing);}

在ClientApp项目中的Activity类中实现如下:

private final IRemoteCB.Stub mCB = new IRemoteCB.Stub(){		@Override		public void callSomething(String thing) throws RemoteException {			// TODO Auto-generated method stub			Log.i(TAG, "~~~~call back  [" +thing +"]");		}	};

2,在IRemoteService.aidl中增加两个方法,用来注册和取消回调,更新如下:

package com.walkbin.drill.aidl;import com.walkbin.drill.aidl.IRemoteCB;interface IRemoteService{    boolean doSomething(String thing);    void regCB(IRemoteCB cb);    void unregCB(IRemoteCB cb);}

相应的要在RemoteService中实现新增的这两个接口。

将更新后的aidl文件同步到两个项目中,这里必须要保证aidl文件的包路径在两个项目中一致,否则运行时会抛异常。

@Override		public void regCB(IRemoteCB cb) throws RemoteException {			// TODO Auto-generated method stub			Log.i(TAG, "~~~~regCB");			mCBList.register(cb);		}		@Override		public void unregCB(IRemoteCB cb) throws RemoteException {			// TODO Auto-generated method stub			Log.i(TAG, "~~~~unregCB");			mCBList.unregister(cb);		}

其中mCBList是RemoteService新增的一个成员,定义为:

private RemoteCallbackList
mCBList = new RemoteCallbackList
();

在ClientApp的activity中获取到mService之后调用regCB来注册回调方法。

@Override		public void onServiceConnected(ComponentName name, IBinder service) {			// TODO Auto-generated method stub			Log.i(TAG, "~~~~onServiceConnected");			mRemoteService = IRemoteService.Stub.asInterface(service);			try {				mRemoteService.regCB(mCB);			} catch (RemoteException e) {				// TODO Auto-generated catch block				e.printStackTrace();			}		}		@Override		public void onServiceDisconnected(ComponentName name) {			// TODO Auto-generated method stub			Log.i(TAG, "~~~~onServiceDisconnected");			try {				mRemoteService.unregCB(mCB);			} catch (RemoteException e) {				// TODO Auto-generated catch block				e.printStackTrace();			}			mRemoteService = null;		}

再对mCBList的使用进行一次封装

 

private void doCB(String str) {         int n = mCBList.beginBroadcast();         try {             for (int i = 0; i < n; i++) {            	 mCBList.getBroadcastItem(i).callSomething(str);             }         } catch (RemoteException e) {            e.printStackTrace();         }         mCBList.finishBroadcast();	 }

 

这样RemoteService中就可以通过doCB来调用到ClientApp中的callSomething方法了!

我们暂且将doCB放到doSomething方法中去调用

@Override		public boolean doSomething(String thing) throws RemoteException {			Log.i(TAG, "~~~~i'm doing [" + thing + "]");			doCB(thing);			return false;		}

看一下log信息:

OK,我们已经看到call back的输出了,这表明ClientApp中的指定方法被成功调用。

 

转载于:https://www.cnblogs.com/richiewang/archive/2013/05/21/3130191.html

你可能感兴趣的文章
腾讯 AI Lab 计算机视觉中心人脸 & OCR团队近期成果介绍(3)
查看>>
课堂练习-增加信息
查看>>
A little issue in Mathematical Thought from Ancient to Modern Times, Vol. 3
查看>>
Zabbix对接AD域
查看>>
django 将view视图中的对象传入forms表单验证模块中
查看>>
log4net配置
查看>>
中文词频统计及词云制作
查看>>
python面试题No5
查看>>
BeanShell PreProcessor数据base64加密
查看>>
10条建议帮助你创建更好的jQuery插件
查看>>
setPreferredSize和setSize的区别及用法
查看>>
Python简介及编码
查看>>
[转]Android:Layout_weight的深刻理解
查看>>
监听键盘弹出 隐藏
查看>>
iOS开发 - NSBundle, NSDevice, NSLocale
查看>>
innerHtml安全问题
查看>>
UVA 11992,。。。伪-二维线段树
查看>>
[原创]通过函数指针实现事件消息处理
查看>>
IE下JS保存图片
查看>>
293.Flip Game
查看>>