AIDL全称是Android Interface Define Language。即android接口定义语言。使用AIDL可以从一个应用内启动外部应用的服务。下面我们通过具体的例子来看看怎么使用:在AndroidStudio的工程中建立两个module,从一个module中启动另一个的定时器服务。
1. 首先在AndroidStudio中创建一个项目,再在项目中创建另一个module称为timer。
2. 在module名上点击右键选择新建AIDl file 创建好后rebuild一下project。
3. 这是AIDL的代码
// ITimerServiceAidlInterface.aidl
package com.chaoyang805.timer;
// Declare any non-default types here with import statements
import com.chaoyang805.timer.ITimerCallback;
interface ITimerServiceAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void startTimer(int value);
void registerCallback(ITimerCallback callback);
void unregisterCallback();
}
方法registerCallback依赖于另一个AIDL文件,下面是这个AIDL的代码
// ITimerCallback.aidl
package com.chaoyang805.timer;
// Declare any non-default types here with import statements
interface ITimerCallback {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void onUpdate(int value);
}
很明显,这是一个回调方法,定时器更新时将最新的时间传递出去。下面我们来看看怎么在service里实现这个回调。在timer中创建一个定时器的service,在service类中的onBind方法返回这个接口的stub对象。下面是service的代码
package com.chaoyang805.timer;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class TimerService extends Service {
/**
* 默认从100开始倒计时
*/
private int mInitialValue = 100;
/**
* 是否在运行
*/
private boolean isRunning = false;
/**
* 倒计时的线程
*/
private Thread mTimerThread;
private ITimerCallback mCallback;
private ITimerServiceAidlInterface.Stub mTimerBinder = new ITimerServiceAidlInterface.Stub() {
/**
* 启动线程来开启定时器
* @param value
*/
@Override
public void startTimer(int value) {
if (!mTimerThread.isAlive()) {
mInitialValue = value;
mTimerThread.start();
isRunning = true;
}
}
/**
* 注册回调
* @param callback
* @throws RemoteException
*/
@Override
public void registerCallback(ITimerCallback callback) throws RemoteException {
mCallback = callback;
}
/**
* 注销回调
* @throws RemoteException
*/
@Override
public void unregisterCallback() throws RemoteException {
mCallback = null;
}
};
@Override
public IBinder onBind(Intent intent) {
return mTimerBinder;
}
/**
* 服务绑定时初始化标志位和线程
*/
@Override
public void onCreate() {
super.onCreate();
isRunning = true;
mTimerThread = new Thread(mTimerRunnable);
}
/**
* 服务销毁时停止定时器
*/
@Override
public void onDestroy() {
isRunning = false;
}
/**
* 在runnable里实现定时器功能
*/
private Runnable mTimerRunnable = new Runnable() {
@Override
public void run() {
try {
while (isRunning && mInitialValue > 0) {
if (mCallback != null) {
mCallback.onUpdate(mInitialValue);
}
Thread.sleep(1000);
mInitialValue--;
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
}
在service的onBind()
方法返回值我们返回了ITimerServiceAidlInterface的对象,并且实现了这个接口的方法,里面的public void registerCallback(ITimerCallback callback)
和unregisterCallback()
就是用来注册和取消回调的,在runnable中通过调用回调方法来将数据传递出去。从上面的过程我们可以看出如果在AIDL中想要实现回调,必须要再定义一个AIDL接口来定义回调的方法,通过在原AIDL文件中添加一个注册和注销回调的方法来实现,需要注意的是,AIDL中用到的对象类必须手动进行导入。
4. 下面我们来看看如何在另一个app中来启动这个广播并添加回调。
第一步要做的就是要将之前定义的两个AIDL文件连同所在的包拷贝到当前module中去,如图
两个module的包名和文件名必须一致。
5. 然后rebuild project,来看看MainActivity的代码
package com.chaoyang805.useexternaltimerservice;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.chaoyang805.timer.ITimerCallback;
import com.chaoyang805.timer.ITimerServiceAidlInterface;
public class MainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection {
/**
* 远程服务所在包名
*/
private static final String PKG_NAME = "com.chaoyang805.timer";
/**
* 远程服务的类名
*/
private static final String CLASS_NAME = "com.chaoyang805.timer.TimerService";
/**
* 显示倒计时的textview
*/
private TextView mTvTimer;
/**
* 获取起始时间的输入框
*/
private EditText mEtGetValue;
/**
* 是否绑定服务的标志位
*/
private boolean isServiceBinded = false;
/**
* 与远程㐏进行通信的binder对象
*/
private ITimerServiceAidlInterface mTimerBinder;
/**
* 远程服务数据更新时的回调
*/
private ITimerCallback mCallback;
/**
* 更新UI的handler
*/
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mTvTimer.setText(msg.what + "");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
/**
* 初始化view
*/
private void initViews() {
mEtGetValue = (EditText) findViewById(R.id.et_get_value);
mTvTimer = (TextView) findViewById(R.id.tv_timer);
findViewById(R.id.btn_start_external_timer).setOnClickListener(this);
findViewById(R.id.btn_stop_external_timer).setOnClickListener(this);
}
/**
* 按键的监听事件
*
* @param v
*/
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setComponent(new ComponentName(PKG_NAME, CLASS_NAME));
switch (v.getId()) {
case R.id.btn_start_external_timer:
if (TextUtils.isEmpty(mEtGetValue.getText())) {
Toast.makeText(this,"请输入倒计时的时间",Toast.LENGTH_SHORT).show();
return;
}
//绑定远程服务
bindService(intent, this, Context.BIND_AUTO_CREATE);
break;
case R.id.btn_stop_external_timer:
//接触绑定服务
unbindService();
break;
}
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
//取得binder对象
mTimerBinder = ITimerServiceAidlInterface.Stub.asInterface(service);
isServiceBinded = true;
//实例化回调
mCallback = new ITimerCallback.Stub() {
@Override
public void onUpdate(int value) throws RemoteException {
//通过handler来更新UI
mHandler.sendEmptyMessage(value);
}
};
//注册回调
mTimerBinder.registerCallback(mCallback);
//开启定时器
startTimer();
} catch (RemoteException e) {
e.printStackTrace();
}
}
/**
* 启动远程定时器
*/
private void startTimer() {
try {
int value = Integer.parseInt(mEtGetValue.getText().toString());
mTimerBinder.startTimer(value);
} catch (RemoteException e) {
e.printStackTrace();
}
}
/**
* 服务断开时对标志位进行更改
*
* @param name
*/
@Override
public void onServiceDisconnected(ComponentName name) {
isServiceBinded = false;
}
/**
* activity销毁时注销回调并取消绑定服务
*/
@Override
protected void onDestroy() {
super.onDestroy();
unbindService();
}
/**
* 销毁时注销回调并取消绑定服务
*/
private void unbindService() {
if (isServiceBinded) {
try {
mTimerBinder.unregisterCallback();
unbindService(this);
isServiceBinded = false;
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
在MainActivity中我们通过声明显示intent Intent intent = new Intent();
实现了绑定外部service,但怎么与其进行通信呢?这就要用到AIDL了。来看一下
intent.setComponent(new ComponentName(PKG_NAME, CLASS_NAME));onServiceConnected
的代码
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
//取得binder对象
mTimerBinder = ITimerServiceAidlInterface.Stub.asInterface(service);
isServiceBinded = true;
//实例化回调
mCallback = new ITimerCallback.Stub() {
@Override
public void onUpdate(int value) throws RemoteException {
//通过handler来更新UI
mHandler.sendEmptyMessage(value);
}
};
//注册回调
mTimerBinder.registerCallback(mCallback);
//开启定时器
startTimer();
} catch (RemoteException e) {
e.printStackTrace();
}
}
通过mTimerBinder = ITimerServiceAidlInterface.Stub.asInterface(service);
来获得ITimerServiceAidlInterface
对象,这样我们就可以调用其中的方法来实现回调或是启动定时器。这就和同一app中service通信相差无几了。