Remote Service 和 Local App的交互

本文详细介绍如何在Android中利用AIDL实现远程服务RemoteService与本地应用LocalApp之间的交互,包括进程间通信、服务绑定及回调机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

名词解释:

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

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


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

官方文档:http://developer.android.com/guide/components/aidl.html

博友文档:http://blog.youkuaiyun.com/saintswordsman/article/details/5130947

                http://blog.youkuaiyun.com/android_tutor/article/details/6427680


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

首先是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:

<service android:name="com.walkbin.drill.remoteservice.RemoteService"
            android:enabled="true"
            android:process=":rmtser"
            android:exported="true">
            <intent-filter >
                <action android:name="com.walkbin.drill.remote_service"/>
            </intent-filter>
        </service>


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<IRemoteCB> mCBList = new RemoteCallbackList<IRemoteCB>();

在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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值