标签:oschina源码 android 轮询 aidl service
主要以OSChina Android客户端源码中Notice的轮询机制进行解读。
一般IM(即使通讯)的实现有两种方式:推送和轮询,推送就是服务器主动向客户端发送消息,用特定的协议比如XMPP、MQTT。另一种是轮询,实时性并不高,而且比较耗电。这种有分为两种情况:一段时间发起一次查询和死循环进行查询。
参考: http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0401/1609.html
远端Service调用:
a.服务端:
0.自定义接口 (AIDL定义接口文件),然后自动生成对应的java类。
1.继承Stub类,复写接口中定义的方法
2.将1中的类对象作为Service中onBind方法的返回值,也就是将来信息交流的使者。
b.客户端
3.在Activity或其他工具类中,创建ServiceConnection 对象,在onServiceConnected回调方法中,将第二个参数转化赋值给本地变量,通过这个变量进行与远端服务交互(通信)。
以上总结很简陋,后面我会结合OSChina的Android源码详细为大家解读。
参考:http://blog.csdn.net/guolin_blog/article/details/9797169
首先在MainActivity中绑定了服务(开启了服务)
MainActivity初始化init()中
NoticeUtils.bindToService(this);
其中bindToService实现
public staticboolean bindToService(Context context,
ServiceConnection callback) {
//直接开启本地NoticeService服务,(注:startService方式并不能进行进行通信)
context.startService(new Intent(context, NoticeService.class));
//绑定远程NoticeService 服务,
//csp:为什么同一个服务用两种不同的方式开启?
//answer: 可能是先开启本地服务,然后把绑定本地服务当做远程服务来处理,目的可能是为了创造不同的进程,提高效率?
ServiceBinder sb = new ServiceBinder(callback);
sConnectionMap.put(context, sb);
return context.bindService(
(newIntent()).setClass(context, NoticeService.class), sb, 0);
}
//最后,总之开启了服务NoticeService
在NoticeService中的onCreate方法中用AlarmManager的方式,每隔2分钟执行一次(轮询)请求,看是否有新的消息通知(这种方式适合通信实时性不高的情况,比如论坛的回复,你并不需要立马知道别人的回复,晚个1-2分钟是可以接受的。)
mAlarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
startRequestAlarm();
private voidstartRequestAlarm() {
cancelRequestAlarm();
// 从1秒后开始,每隔2分钟执行getOperationIntent()
mAlarmMgr.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis()+ 1000, INTERVAL,
getOperationIntent());
}
其中getOperationIntent()实现如下:
/**
* OSC采用轮询方式实现消息推送<br>
* 每次被调用都去执行一次{@link #AlarmReceiver}onReceive()方法
*
* @return
*/
privatePendingIntent getOperationIntent() {
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent operation = PendingIntent.getBroadcast(this,0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
return operation;
}
在AlarmReceiver类中调用NoticeUtils.requestNotice方法如下
该方法首先判断远端Service的onBind返回来的sService对象是否为空,如果连接上了,不为空,则调用该sService对象的方法requestNotice(),否则发送广播,请求访问服务器更新Notice
publicstatic void requestNotice(Context context) {
if (sService != null) {
try {
TLog.log("requestNotice...");
//这里的sService,在下面进行详细的解读
sService.requestNotice();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
context.sendBroadcast(new Intent(
NoticeService.INTENT_ACTION_REQUEST));
TLog.log("requestNotice,service is null");
最后就是requestNotice的实现了:
publicstatic void getNotices(AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", AppContext.getInstance().getLoginUid());
ApiHttpClient.get("action/api/user_notice", params, handler);
}
还是先上源码,以下是调用远程Service的步骤:
(0)用AIDL自定义一 个接口文件INoticeService.aidl
package net.oschina.app.service;
interface INoticeService
{
void scheduleNotice();
void requestNotice();
void clearNotice(int uid,int type);
}
然后点击保存之后,gen目录下就会生成一个对应的Java文件:INoticeService.java
然后,我们打开看一下里面的代码:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: E:\\oschina-android-app-v2.2.1\\android-app\\osc-android-app\\src\\net\\oschina\\app\\service\\INoticeService.aidl
*/
package net.oschina.app.service;
public interface INoticeService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements net.oschina.app.service.INoticeService
{
...//Stub类的内容较长,我在此省略
}
public void scheduleNotice() throws android.os.RemoteException;
public void requestNotice() throws android.os.RemoteException;
public void clearNotice(int uid, int type) throws android.os.RemoteException;
}
ADT自带工具aidl.exe生成的代码的看点在于,生成了一个Stub类,该类1.继承了Binder(Binder是IBinder接口的一个实现类)因此将来可以作为Service的onBind方法的返回值,2.实现了自定义的接口(INoticeService.aidl),将来可以复写或调用。
(1)定义一个Stub的子类:ServiceStub,复写自定义接口中的三个方法。
private static class ServiceStub extends INoticeService.Stub {
WeakReference<NoticeService> mService;
ServiceStub(NoticeService service) {
mService = new WeakReference<NoticeService>(service);
}
@Override
public void clearNotice(int uid, int type) throws RemoteException {
mService.get().clearNotice(uid, type);
}
@Override
public void scheduleNotice() throws RemoteException {
mService.get().startRequestAlarm();
}
@Override
public void requestNotice() throws RemoteException {
mService.get().requestNotice();
}
}
(2)在NoticeService中将(1)的对象作为onBind方法的返回值返回。
private final IBinder mBinder = new ServiceStub(this);
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
(3)创建ServiceConnection 对象
源码在NoticeUtils中定义了一个ServiceBinder 类实现ServiceConnection 接口,复写了两个回调函数(当连接远端服务成功和连接远端服务失败)
private static class ServiceBinder implements ServiceConnection {
ServiceConnection mCallback;
ServiceBinder(ServiceConnection callback) {
mCallback = callback;
}
@Override
public void onServiceConnected(ComponentName className,
android.os.IBinder service) {
//第二个参数service:获取远程Service的onBind方法返回的对象的代理
//下面一句是将代理转换为对象
sService = INoticeService.Stub.asInterface(service);
if (mCallback != null) {
mCallback.onServiceConnected(className, service);
}
}
@Override
public void onServiceDisconnected(ComponentName className) {
if (mCallback != null) {
mCallback.onServiceDisconnected(className);
}
sService = null;
}
}
上面的代码告诉我们,如果连接远端服务(NoticeService)成功,则可以通过远端onBind方法返回的对象(即onServiceConnected方法的第二个参数)来进行通信,这里值得一说的是远端服务返回来的只是对象的代理,这一点区别于绑定本地服务,所以要进行转换,转化的方法就是这一句: sService = INoticeService.Stub.asInterface(service)。
至此,我们已经彻底知道了sService的由来。
最后,欢迎拍砖。。。
作者:项昂之
时间:2015.7.20
转载注明出处:http://blog.csdn.net/csp277?viewmode=list
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:oschina源码 android 轮询 aidl service
原文地址:http://blog.csdn.net/csp277/article/details/46970559