Activity与Service通信之AIDL远程服务

原创 2016年06月01日 16:45:55
一、原理
其实简单来说,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:
import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

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:
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

import testndk.testserviceaidl.ICountService;

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);
}
}

}
TestServiceAIDL.zip
TestService.zip

源码下载地址:

http://download.csdn.net/detail/lu1024188315/9537991

效果图:


版权声明:请尊重劳动成果,转载请注明来处:Abang的博客 http://blog.csdn.net/lu1024188315,如果您有不同意见,请尽情留言

相关文章推荐

Android四大组件之Service(二)远程服务(AIDL进程间通信)

在Android中, 每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢? 显然, Java中是不支持跨进程内存共享的。因此要传递对象, 需要把对象解析成操作系统能够理解...

Android进阶之Service远程通信AIDL

Service的远程通信AIDL先解释下什么是AIDL,AIDL (Android Interface Definition Language)是一种IDL 语言,用于生成可以在Android设备上两...

AIDL demo 远程服务通信

  • 2016-07-15 12:40
  • 15.99MB
  • 下载

Android:远程服务Service(含AIDL & IPC讲解)

前言 Service作为Android四大组件之一,应用非常广泛 本文将介绍Service其中一种常见用法:远程Service 如果你对Service还未了解,建议先阅读我写的另外一篇文章: ...

Android Service学习之AIDL, Parcelable和远程服务

AIDL的作用     由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象。在Android平台,一个进程通常不能访问另一个进...

android_58_service_remote_AIDL调用远程服务

AIDL: 安卓接口定义语言,用于进程间通信 步骤: 1.来到提供远程服务的project的文件目录, 将抽取的接口OpenInterface.java直接改成.aidl后缀 2.来到项...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)