服务端代码:
- AIDL接口:IAIDLConfigService.aidl
package com.android.aidl;
interface IAIDLConfigService {
int setHomePage(String homepage);
}
- Android.mk中增加对AIDL文件编译的支持
LOCAL_SRC_FILES += \ $(call all-Iaidl-files-under, src)
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src/
模块编译过程中AIDL文件会生成IAIDLConfigService.java
AIDLConfigService.java
package com.android.aidl;
import com.android.aidl.IAIDLConfigService;
import android.content.Context;
import android.content.Intent;
import android.app.Service;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.android.browser.BrowserSettings;
import com.android.browser.UrlUtils;
public class AIDLConfigService extends Service {
static final String TAG = "AIDLConfigService";
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "====>onBind().");
IBinder binder = new ImplAIDLConfigService();
Log.d(TAG, "====>onBind().binder = " + binder);
return binder;
}
public class ImplAIDLConfigService extends IAIDLConfigService.Stub{
@Override
public int setHomePage(String homepage) throws RemoteException {
Log.d(TAG, "setHomePage(), homepage = " + homepage);
if (homepage != null) {
BrowserSettings.getInstance().setHomePage(UrlUtils.smartUrlFilter(homepage,false));
}
return 123;
}
}
}
- AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.browser">
......
<service android:name="com.android.aidl.AIDLConfigService">
<intent-filter>
<action android:name="com.andorid.aidl.BrowserDataConfig" />
</intent-filter>
</service>
</application>
</manifest>
客户端代码:
- AIDL接口:IAIDLConfigService.aidl
package com.android.aidl;
interface IAIDLConfigService {
int setHomePage(String homepage);
}
Note:
客户端IAIDLConfigService.aidl跟服务端文件需要完全一样, 包括目录结构也需要一样,都在src\com\android\aidl\目录下
- Android.mk中增加对AIDL文件编译的支持
LOCAL_SRC_FILES += \ $(call all-Iaidl-files-under, src)
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src/
模块编译过程中AIDL文件会生成IAIDLConfigService.java
接口层AIDLBrowserImpl.java
import android.content.Context;
import android.app.Service;
import android.content.Intent;
import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import com.android.aidl.IAIDLConfigService;
import android.util.Log;
public class AIDLBrowserImpl {
public final String TAG = "AIDLBrowserImpl";
public final static String AIDL_BROWSER_ACTION = "com.andorid.aidl.BrowserDataConfig";
private boolean mIsBound;
private IAIDLConfigService mBoundService = null;
private void bindService(Context context) {
Log.e(TAG, "bindService(): enter");
Intent i = new Intent();
i.setAction(AIDL_BROWSER_ACTION);
i.setPackage("com.android.browser");
context.bindService(i, mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
private void unbindService(Context context) {
if (mIsBound) {
context.unbindService(mConnection);
mIsBound = false;
}
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(TAG, "-->> onServiceConnected() enter.");
mBoundService = IAIDLConfigService.Stub.asInterface(service);
Log.d(TAG, "-->> onServiceConnected(), boundService = " + mBoundService);
}
@Override
public void onServiceDisconnected(ComponentName className) {
mBoundService = null;
Log.d(TAG, "-->> onServiceDisconnected()");
}
};
public void init(Context context) {
bindService(context);
}
public void free(Context context) {
unbindService(context);
}
public boolean setHomePage(Context context, String link, String name){
Log.d(TAG, "setHomePage(): enter, link = " + link + ", name = " + name);
int result = -1;
try {
if(mBoundService == null) return false;
result = mBoundService.setHomePage(link);
Log.e(TAG,"mBoundService.setHomePage() result = " + result);
} catch (RemoteException e) {
e.printStackTrace();
return false;
}
if(result != 0) return false;
return true;
}
}
- MainActivity.java
package com.android.aidltest;
import android.os.Bundle;
import android.widget.Button;
import android.view.View;
import android.content.Context;
import android.widget.Toast;
import android.app.Activity;
import android.util.Log;
import com.sprd.aidl.adapter.porting.AIDLBrowserImpl;
public class MainActivity extends Activity {
public static final String TAG = "AIDLTest";
AIDLBrowserImpl mAIDLBrowserImpl;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button btnTestBrowser = (Button) findViewById(R.id.btnTestBrowser);
btnTestBrowser.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
testBrowserDataConfig(true);
}
});
mAIDLBrowserImpl = new AIDLBrowserImpl();
}
@Override
protected void onStart() {
super.onStart();
Log.i(TAG, "onStart: this=" + this);
if(mAIDLBrowserImpl != null) {
mAIDLBrowserImpl.init(this);
}
}
@Override
protected void onStop() {
Log.i(TAG, "onStop");
mAIDLBrowserImpl.free(this);
super.onStop();
}
private void testBrowserDataConfig(boolean isNormalTest) {
Log.d(TAG, "Test aidl browser data config beging ... isNormalTest = " + isNormalTest);
//Test homepage
{
String link = "cn.bing.com";
String name = "BingBing";
mAIDLBrowserImpl.setHomePage(this, link, name);
}
Toast.makeText(this, "Test aidl browser data config end", Toast.LENGTH_SHORT).show();
return;
}
}
小结
- 至此实现了一个应用程序进程(apk)对另一个应用程序进程(apk)的同步调用就完成了;
- 至于AIDL通讯原理,网上很多资料,这里都不多讲了;总结一下期间遇到的问题:
- 客户端bindService时Intent的setAction需要跟服务端AndroidManifest.xml中intent-filter/action一致:
<intent-filter> <action android:name="com.andorid.aidl.BrowserDataConfig" /> </intent-filter>
- 客户端bindService时Intent的setPackage设置的是服务端的包名
- 客户端bindService的过程是异步过程,并且onServiceConnected回调函数运行在主线程中,所以当我们的同步调用接口AIDLBrowserImpl.setHomePage也运行在主线程时;bindService如果在AIDLBrowserImpl.setHomePage接口内调用;onServiceConnected回调函数会一直等到AIDLBrowserImpl.setHomePage运行完成,才能得到调用;因为同一线程不可能前一个消息没处理完毕的情况下,就去处理后面的消息。所以,目前的解决方法就是,在客户端的onStart方法中先去bindService;然后客户端就可以直接同步调用AIDL实现的所有接口了;
官方文档:Interface for monitoring the state of an application service. Like many callbacks from the system, the methods on this class are called from the main thread of your process.
- 客户端bindService的动作建议放在主线程中;
- 为什么同步调用接口AIDLBrowserImpl.setHomePage不放在其他线程中?因为这样就失去了同步的意义了。
- 客户端bindService时Intent的setAction需要跟服务端AndroidManifest.xml中intent-filter/action一致: