项目源码:https://github.com/liaozhoubei/StudyService
前文:
https://www.jianshu.com/p/0dfc6e9d82b3 (浅析Android服务中的startService和bindService)
https://www.jianshu.com/p/5789c59095cb (AIDL跨进程通信的使用)
最近由于业务需求的缘故,需要做到Service调用activity的方法,而且是跨进程间的调用。说起来activity调用service的方法大家都熟,但是反过来还真没遇到过。如果说使用回调,但是service似乎不太支持啊!
无奈之下只好面向搜索引擎编程了,找了找,还真有,而且也是基于回调的!
创建回调的aidl
方法很简单,如下:
public interface Iservice {
public void calleat();
}
创建需要被service使用的aidl
如下:
interface IService {
void start();
void registerCallback(ICallback cb);
void unregisterCallback(ICallback cb);
}
需要注意的是,必须要手动导入 Iservice 的包,否则就会报错,这是个小坑,感觉android studio还是有不完善的地方啊!
如此之后,点击 sync project 之后就能够自动生产 aidl 的使用类了。
Service执行任务
public class TestMyService extends Service {
private static final String TAG = TestMyService.class.getSimpleName();
// 提供远程调用的回调
private RemoteCallbackList<ICallback> mCallbacks = new RemoteCallbackList<ICallback>();
private IService.Stub mBinder = new IService.Stub() {
@Override
public void unregisterCallback(ICallback cb){
if(cb != null) {
// 取消注册
mCallbacks.unregister(cb);
}
}
@Override
public void start() throws RemoteException {
}
@Override
public void registerCallback(ICallback cb){
if(cb != null) {
// 注册回调对象
mCallbacks.register(cb);
}
}
};
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return mBinder;
}
@Override
public void onCreate() {
Log.d(TAG, "onCreate");
doingBack();
super.onCreate();
}
@Override
public void onDestroy() {
mCallbacks.kill();
super.onDestroy();
}
// 回调,通知每个注册的对象
private void callBack(int j) {
int N = mCallbacks.beginBroadcast();
try {
for (int i = 0; i < N; i++) {
// 给每个回调对象发送通知
mCallbacks.getBroadcastItem(i).showResult(j);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
// 结束发送通知
mCallbacks.finishBroadcast();
}
private int index = 0;
private void doingBack(){
new Thread(new Runnable() {
@Override
public void run() {
// 一些耗时操作,操作完后调用activity方法
SystemClock.sleep(3000);
while (true){
callBack(index);
index++;
SystemClock.sleep(1000);
}
}
}).start();
}
}
上面的是service的全部代码。
RemoteCallbackList.java的定义
负责维护远程接口列表,特别是用于执行service 跟 clients之间回调的。
具体的讲:
1. 保持跟踪 注册的IInterface 回调,通过这些回调的 unique IBindler(通过调用IInterface.asBindler())。
2. 将每一个注册的借口通过IBindler.DeathRecipient绑定,这样若进程被清楚就可以清除list。
3. 锁定 interfaces列表处理多线程的调用,然后不需要持有lock的方式,用线程安全的方式遍历列表。
用这个类,可以简单的创建一个实例,通过其register(E)和unregister(E)函数注册或注销clients。
通过beginBroadcast(), getBroadcastItem(int), finishBroadcast().回调给client。
如果一个注册了callback的进程消失了,这个类会自动将其从list中清除。
可以通过onCallbackDied(E)对这个注册的callback进行额外处理。
详情请看: https://blog.csdn.net/wangxueming/article/details/51189751
对于我的理解而言 RemoteCallbackList 就是设计模式中观察者的一种使用,每个绑定并且注册到这个服务中的 activity 对象都会接收到这个service 回调的数据。
activity 中的使用
代码如下:
public class SecondActiivty extends AppCompatActivity {
private static final String TAG = SecondActiivty.class.getSimpleName();
private IService mService;
/**
* service的回调方法
*/
private ICallback.Stub mCallback = new ICallback.Stub() {
@Override
public void showResult(int result) {
Log.d(TAG, " result : " + result);
final String r = "result:"+result;
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_s_view.setText(r);
}
});
}
};
private TextView tv_s_view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_actiivty);
tv_s_view = (TextView) findViewById(R.id.tv_s_view);
bindService(new Intent(this, TestMyService.class),
new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IService.Stub.asInterface(service);
try {
mService.registerCallback(mCallback);
mService.start();
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
}
在 Activity 中的使用也非常简单,类似与普通的绑定服务,在 onServiceConnected 中注册监听,然后在监听回调中做操作。
需要注意的是必须要在 onServiceDisconnected 注销监听,又或者在onDestroy中注销。
参考文章:
https://blog.csdn.net/h3c4lenovo/article/details/7885514
网友评论