Activity与Service通信之AIDL远程服务

一、原理
其实简单来说,AIDL可以实现应用程序之间进行通信。
二、使用Android studio创建AIDL
 如何创建可以查看Android Studio 创建AIDL》,这里就不再累述了。
其中:AIDL文件
package testndk.testserviceaidl;

// Declare any non-default types here with import statements

interface ICountService {
/**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
int getCount();
}
注意:
        Service 和Client中AIDL文件所在的包名必须一致,记得创建后要记得Rebuild 一下,不然没有办法使用;
Rebuild后,系统会自动生成类似xxx.Stub的类。
        这样我们就可以在Service端使用了如下:
class AIDLServerBinder extends ICountService.Stub{
@Override
public int getCount() throws RemoteException {
return i;
}
}
在Client端使用如下:
private ServiceConnection serConn = new ServiceConnection() {

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

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iCountService = ICountService.Stub.asInterface(service);
}
};
二、使用隐式意图启动服务
在Service端我们注册服务是这样的:
<service android:name="AIDLServer"
android:process=":remote">
    <intent-filter>
        <action android:name="testndk.testserviceaidl.AIDLServer" />
    </intent-filter>
</service>
在client端启动该服务时,我们需要action如下:
Intent intent = new Intent("testndk.testserviceaidl.AIDLServer");
但是,在这里有个问题就是Android 5.0以后不支持隐式意图启动服务(会报参数异常)。那么我们怎么才能够启动该远程服务?
   解决方案,使用如下的方法把隐式意图转为显示意图,然后才启动服务就好了。
/***
 * Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent,
 * "java.lang.IllegalArgumentException: Service Intent must be explicit"
 *
 * If you are using an implicit intent, and know only 1 target would answer this intent,
 * This method will help you turn the implicit intent into the explicit form.
 *
 * Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466
 * @param context
* @param implicitIntent - The original implicit intent
 * @return Explicit Intent created from the implicit original intent
 */
public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);

// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}

// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);

// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);

// Set the component to be explicit
explicitIntent.setComponent(component);

   return explicitIntent;
}
三、核心代码:
Service端:
public class AIDLServer extends Service {
	private static final int TIME = 1;
	private Timer mTimer = null;
	private int i = 0;
	
	private AIDLServerBinder serviceBinder = new AIDLServerBinder();

	class AIDLServerBinder extends ICountService.Stub{
		@Override
		public int getCount() throws RemoteException {
			return i;
		}
	}
	
	@Override
	public void onCreate() {
		super.onCreate();
		mTimer = new Timer();
		mTimer.schedule(new MyTimerTask(), 0,TIME * 1000);
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		if(mTimer!=null){
			mTimer.cancel();
			mTimer = null;
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		return serviceBinder;
	}
	
	class MyTimerTask extends TimerTask{

		@Override
		public void run() {
			if(i==100){
				i=0;
			}
			i++;
		}
	}
}
其中MainActivity没有处理,记得要先运行该程序才可以。
Client端:
public class AIDLClientActivity extends Activity {
    private static final int TIME = 1;
    private Button startBtn = null;
    private Button stopBtn = null;
    private TextView mTextView = null;
    private ProgressBar mProgressBar = null;
    private boolean mIsBind;
    private Timer mTimer = null;
	/**获取ICountService实例*/
    private ICountService iCountService = null;
	/**开启服务的显示意图*/
	private Intent eintent;

	Handler mHandler = new Handler(){
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			try {
				int count =  iCountService.getCount();
				mTextView.setText(count+"%");
				mProgressBar.setProgress(count);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}
    };
	private ServiceConnection serConn = new ServiceConnection() {

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

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			iCountService = ICountService.Stub.asInterface(service);
		}
	};

	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        mTimer = new Timer();
		Intent intent = new Intent("testndk.testserviceaidl.AIDLServer");
		//把隐式意图转为显示意图
		eintent = new Intent(createExplicitFromImplicitIntent(this,intent));
		mTextView = (TextView)findViewById(R.id.loading_Tv);
        mProgressBar = (ProgressBar)findViewById(R.id.myProgressBar);
        mProgressBar.setMax(100);
        startBtn = (Button)findViewById(R.id.start_Btn);
        stopBtn = (Button)findViewById(R.id.stop_Btn);
        startBtn.setOnClickListener(new ButtonClickListener());
        stopBtn.setOnClickListener(new ButtonClickListener());

    }

    class ButtonClickListener implements OnClickListener{

		@Override
		public void onClick(View v) {
			if(startBtn==v){
				mIsBind = bindService(eintent, serConn, BIND_AUTO_CREATE);
				if (mTimer == null){
					mTimer = new Timer();
				}
				mTimer.schedule(new MyTimerTask(), 1000 ,TIME * 1000);
			}else if (stopBtn==v) {
				if(mIsBind){
					unbindService(serConn);
					if(mTimer!=null){
						mTimer.cancel();
						mTimer = null;
					}
					mIsBind = false;
				}
			}
		}
    	
    }
    
    class MyTimerTask extends TimerTask{
		@Override
		public void run() {
			mHandler.sendMessage(mHandler.obtainMessage());
		}
    }

	/***
	 * Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent,
	 * "java.lang.IllegalArgumentException: Service Intent must be explicit"
	 *
	 * If you are using an implicit intent, and know only 1 target would answer this intent,
	 * This method will help you turn the implicit intent into the explicit form.
	 *
	 * Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466
	 * @param context
	 * @param implicitIntent - The original implicit intent
	 * @return Explicit Intent created from the implicit original intent
	 */
	public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
		// Retrieve all services that can match the given intent
		PackageManager pm = context.getPackageManager();
		List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);

		// Make sure only one match was found
		if (resolveInfo == null || resolveInfo.size() != 1) {
			return null;
		}

		// Get component info and create ComponentName
		ResolveInfo serviceInfo = resolveInfo.get(0);
		String packageName = serviceInfo.serviceInfo.packageName;
		String className = serviceInfo.serviceInfo.name;
		ComponentName component = new ComponentName(packageName, className);

		// Create a new intent. Use the old one for extras and such reuse
		Intent explicitIntent = new Intent(implicitIntent);

		// Set the component to be explicit
		explicitIntent.setComponent(component);

		return explicitIntent;
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		if(mTimer!=null){
			mTimer.cancel();
			mTimer = null;
		}
		if (mIsBind){
			unbindService(serConn);
		}
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值