当前位置 : 主页 > 编程语言 > java >

【Android -- 开发】轮询操作

来源:互联网 收集:自由互联 发布时间:2022-06-22
前言 什么叫轮询请求? 简单理解就是 App 端每隔一定的时间重复请求的操作就叫做轮询请求,比如:App 端每隔一段时间上报一次定位信息,App 端每隔一段时间拉去一次用户状态等,这

前言

  • 什么叫轮询请求?
    简单理解就是 App 端每隔一定的时间重复请求的操作就叫做轮询请求,比如:App 端每隔一段时间上报一次定位信息,App 端每隔一段时间拉去一次用户状态等,这些应该都是轮询请求。
  • 为何不用长连接代替轮询操作?
    长连接并不是稳定的可靠的,而执行轮询操作的时候一般都是要稳定的网络请求,而且轮询操作一般都是有生命周期的,即在一定的生命周期内执行轮询操作,而长连接一般都是整个进程生命周期的,所以从这方面讲也不太适合。

实战

1. 与长连接相关的轮训请求

public class LoopRequestService extends Service {
/**
* 是否已经绑定了推送设备id
*/
private volatile isBindDevIdEnum isBindDevId = isBindDevIdEnum.NONE;
public enum isBindDevIdEnum {
NONE, RUN, SUCCESS
}

public static final String ACTION = "LoopService";
/**
* 客户端执行轮询的时间间隔,该值由StartQueryInterface接口返回,默认设置为30s
*/
public static int LOOP_INTERVAL_SECS = 5;
/**
* 当前服务是否正在执行
*/
public static boolean isServiceRunning = false;
/**
* 定时任务工具类
*/
public static Timer timer = new Timer();

private Context context;

public LoopRequestService() {
isServiceRunning = false;
}

//-------------------------------使用闹钟执行轮询服务------------------------------------

/**
* 启动轮询服务
*/
public static void startLoopService(Context context) {
if (context == null){
return;
}
quitLoopService(context);
LogUtils.i("LoopService开启轮询服务,轮询间隔:" + LOOP_INTERVAL_SECS + "s");
AlarmManager manager = (AlarmManager) context.getApplicationContext()
.getSystemService(Context.ALARM_SERVICE);
//开启服务service
Intent intent = new Intent(context.getApplicationContext(), LoopRequestService.class);
intent.setAction(LoopRequestService.ACTION);
PendingIntent pendingIntent = PendingIntent.getService(context.getApplicationContext(),
1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
/*
* 闹钟的第一次执行时间,以毫秒为单位,可以自定义时间,不过一般使用当前时间。需要注意的是,本属性与第一个属性(type)密切相关,
* 如果第一个参数对应的闹钟使用的是相对时间(ELAPSED_REALTIME和ELAPSED_REALTIME_WAKEUP),那么本属性就得使用相对时间(相对于系统启动时间来说),
* 比如当前时间就表示为:SystemClock.elapsedRealtime();
* 如果第一个参数对应的闹钟使用的是绝对时间(RTC、RTC_WAKEUP、POWER_OFF_WAKEUP),那么本属性就得使用绝对时间,
* 比如当前时间就表示为:System.currentTimeMillis()。
*/
if (manager != null) {
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
LOOP_INTERVAL_SECS * 1000, pendingIntent);
}
}

/**
* 停止轮询服务
*/
public static void quitLoopService(Context context) {
if (context == null){
return;
}
LogUtils.i("LoopService关闭轮询闹钟服务...");
AlarmManager manager = (AlarmManager) context.getApplicationContext()
.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context.getApplicationContext(), LoopRequestService.class);
intent.setAction(LoopRequestService.ACTION);
PendingIntent pendingIntent = PendingIntent.getService(context.getApplicationContext(),
1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (manager != null) {
manager.cancel(pendingIntent);
}
// 关闭轮询服务
LogUtils.i("LoopService关闭轮询服务...");
context.stopService(intent);
}

@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.i("LoopService开始执行轮询服务... \n 判断当前用户是否已登录...");
// 若当前网络不正常或者是用户未登陆,则不再跳转
if (NetworkUtils.isConnected()) {
// 判断当前长连接状态,若长连接正常,则关闭轮询服务
LogUtils.i("LoopService当前用户已登录... \n 判断长连接是否已经连接...");
if (isBindDevId != null && isBindDevId == isBindDevIdEnum.SUCCESS) {
LogUtils.i("LoopService已经绑定id成功,退出轮询服务...");
quitLoopService(context);
} else {
if (isServiceRunning) {
return START_STICKY;
}
// 启动轮询拉取消息
startLoop();
}
} else {
LogUtils.i("LoopService没有网络时,关闭轮询服务...");
quitLoopService(context);
}
return START_STICKY;
}

@Override
public void onDestroy() {
super.onDestroy();
LogUtils.i("LoopService轮询服务退出,执行onDestroy()方法,inServiceRunning赋值false");
isServiceRunning = false;
timer.cancel();
timer = new Timer();
}

@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}

/**
* 启动轮询拉去消息
*/
private int count = 0;
private void startLoop() {
if (timer == null) {
timer = new Timer();
}
timer.schedule(new TimerTask() {
@Override
public void run() {
isServiceRunning = true;
LogUtils.i("LoopService执行轮询操作...轮询服务中请求getInstance接口...");
//开始执行轮询的网络请求操作sendLoopRequest();
//这里只是假设数据操作
if (count==5){
isBindDevId = isBindDevIdEnum.SUCCESS;
}
count++;
}
}, 0, LOOP_INTERVAL_SECS * 1000);
}
}

2. 与页面相关的轮询请求
2.1 使用 TimerTask 实现轮询
在当前 Activity 页面有一个定时的拉去订单信息的轮询请求

/**
* TimerTask对象,主要用于定时拉去服务器信息
*/
public class Task extends TimerTask {
@Override
public void run() {
L.i("开始执行执行timer定时任务...");
handler.post(new Runnable() {
@Override
public void run() {
isFirstGetData = false;
getData(true);
}
});
}
}

当用户退出这个页面的时候需要清除这里的轮询操作

@Override
public void onDestroy() {
super.onDestroy();
if (timer != null) {
timer.cancel();
timer = null;
}
if (timerTask != null) {
timerTask.cancel();
timerTask = null;
}
}

2.2 通过 Handler 对象实现轮训请求

/**
* 默认的时间间隔:1分钟
*/
private static int DEFAULT_INTERVAL = 60 * 1000;
/**
* 异常情况下的轮询时间间隔:5秒
*/
private static int ERROR_INTERVAL = 5 * 1000;
/**
* 当前轮询执行的时间间隔
*/
private static int interval = DEFAULT_INTERVAL;
/**
* 轮询Handler的消息类型
*/
private static int LOOP_WHAT = 10;
/**
* 是否是第一次拉取数据
*/
private boolean isFirstRequest = false;
/**
* 第一次请求数据是否成功
*/
private boolean isFirstRequestSuccess = false;

/**
* 开始执行轮询,正常情况下,每隔1分钟轮询拉取一次最新数据
* 在onStart时开启轮询
*/
private void startLoop() {
L.i("页面onStart,需要开启轮询");
loopRequestHandler.sendEmptyMessageDelayed(LOOP_WHAT, interval);
}

/**
* 关闭轮询,在界面onStop时,停止轮询操作
*/
private void stopLoop() {
L.i("页面已onStop,需要停止轮询");
loopRequestHandler.removeMessages(LOOP_WHAT);
}

/**
* 处理轮询的Handler
*/
private Handler loopRequestHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 如果首次请求失败,
if (!isFirstRequestSuccess) {
L.i("首次请求失败,需要将轮询时间设置为:" + ERROR_INTERVAL);
interval = ERROR_INTERVAL;
} else {
interval = DEFAULT_INTERVAL;
}

L.i("轮询中-----当前轮询间隔:" + interval);

loopRequestHandler.removeMessages(LOOP_WHAT);

// 首次请求为成功、或者定位未成功时执行重定位,并加载网点数据
if (!isFirstRequestSuccess || !Config.locationIsSuccess()) {
isClickLocationButton = false;
doLocationOption();
} else {
loadData();
}
System.gc();
loopRequestHandler.sendEmptyMessageDelayed(LOOP_WHAT, interval);
}
};


网友评论