在上一篇文章《AIDL解析(一)两个应用之间使用AIDL进行通信的例子》中,我们学会了Activity如何向Service传递数据,但是Service却不能主动向Activity传递数据,比如说我们想让Service开启一个线程,每隔五秒传递一个消息给Activity,应该怎么做呢?这就要用到回调机制了。
效果图:
如图所示,我们要的效果是Client客户端会主动接收到Service的消息
搭建Client项目
1 首先,我们新建一个IService.aidl的文件,代码如下:
package com.viii.aidlclient;
import com.viii.aidlclient.MessageCenter;
interface IService {
void registerCallback(MessageCenter cb);
void unregisterCallback(MessageCenter cb);
}
2 新建一个CallBackActivity,布局和代码如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="150dp"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="200dp"
android:text="发送"/>
<TextView
android:id="@+id/tv_modify"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="服务端发来的内容:"
android:layout_below="@+id/editText"
/>
</RelativeLayout>
通过 mService.registerCallback(mCallback)去绑定回调
package com.viii.aidlclient;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import java.util.List;
public class CallBackActivity extends AppCompatActivity implements View.OnClickListener {
private EditText editText;
private TextView tv_modify;
//标志当前与服务端连接状况的布尔值,false为未连接,true为连接中
private boolean mBound = false;
private IService mService;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
String str = (String) msg.obj;
tv_modify.setText(str);
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_call_back);
editText = (EditText) findViewById(R.id.editText);
tv_modify = (TextView) findViewById(R.id.tv_modify);
findViewById(R.id.button).setOnClickListener(this);
}
/**
* 跨进程绑定服务
*/
private void attemptToBindService() {
Intent intent = new Intent();
intent.setAction("com.vvvv.callbackaidl");
intent.setPackage("com.iiiv.aidlserver");
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStart() {
super.onStart();
if (!mBound) {
attemptToBindService();
}
}
@Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mServiceConnection);
mBound = false;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mService != null) {
try {
mService.unregisterCallback(mCallback);
} catch (RemoteException e) {
Log.e(getClass().getSimpleName(), "", e);
}
}
}
/**
* service的回调方法
*/
private MessageCenter.Stub mCallback = new MessageCenter.Stub() {
@Override
public List<Info> getInfo() throws RemoteException {
return null;
}
@Override
public Info addInfo(Info info) throws RemoteException {
Message message = new Message();
message.obj = info.getContent();
handler.sendMessage(message);
return null;
}
};
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(getLocalClassName(), "完成绑定aidlserver的AIDLService服务");
mService = IService.Stub.asInterface(service);
try {
mService.registerCallback(mCallback);
} catch (RemoteException e) {
Log.e(getClass().getSimpleName(), "", e);
}
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(getLocalClassName(), "无法绑定aidlserver的AIDLService服务");
mBound = false;
}
};
@Override
public void onClick(View view) {
String content;
switch (view.getId()) {
case R.id.button:
content = editText.getText().toString();
break;
}
}
}
搭建Service项目
1、拷贝IService.aidl文件到aidi目录下,新建一个CallbackAIDLService的文件
mCallbacks.register(cb)绑定回调之后,通过mCallbacks.beginBroadcast(), mCallbacks.getBroadcastItem(i).addInfo(info),mCallbacks.finishBroadcast()3个步骤来进行发送
package com.iiiv.aidlserver.service;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import com.viii.aidlclient.IService;
import com.viii.aidlclient.Info;
import com.viii.aidlclient.MessageCenter;
import java.util.ArrayList;
import java.util.List;
/**
* 服务端的AIDLService.java
*/
public class CallbackAIDLService extends Service {
public final String TAG = this.getClass().getSimpleName();
private boolean quit = false;
private int count;
private Handler timeHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.i(getClass().getSimpleName(), "发送消息:" + msg.what);
Info info = new Info();
info.setContent("来自服务器的消息:"+msg.what);
callBack(info);
super.handleMessage(msg);
}
};
private RemoteCallbackList<MessageCenter> mCallbacks = new RemoteCallbackList<MessageCenter>();
private IService.Stub mBinder = new IService.Stub() {
@Override
public void unregisterCallback(MessageCenter cb){
if(cb != null) {
mCallbacks.unregister(cb);
}
}
@Override
public void registerCallback(MessageCenter cb){
if(cb != null) {
mCallbacks.register(cb);
}
}
};
private void callBack(Info info) {
int N = mCallbacks.beginBroadcast();
try {
for (int i = 0; i < N; i++) {
mCallbacks.getBroadcastItem(i).addInfo(info);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
mCallbacks.finishBroadcast();
}
/**
* 初始化一个定时器
*/
private void initTimer() {
new Thread() {
@Override
public void run() {
while (!quit) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = new Message();
message.what = count++;
timeHandler.sendMessage(message);
}
}
}.start();
}
@Override
public void onCreate() {
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(getClass().getSimpleName(), String.format("on bind,intent = %s", intent.toString()));
initTimer();
return mBinder;
}
@Override
public void onDestroy() {
quit = true;
mCallbacks.kill();
super.onDestroy();
}
}
2 在AndroidManifest中注册
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.iiiv.aidlserver">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service
android:name=".service.AIDLService"
android:exported="true">
<intent-filter>
<action android:name="com.vvvv.aidl"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
<service
android:name=".service.CallbackAIDLService"
android:exported="true">
<intent-filter>
<action android:name="com.vvvv.callbackaidl"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
</application>
</manifest>
现在,我们可以随时向Client发送消息了!