一个超简单的android任务列队(排队)2
上一篇稍微粗略的写了一个任务列队的框框,这一篇主要实现任务列队中的任务超时设置,我们可以为每一个任务设置不同的超时时长。先注明本列队方法完全脱离业务,不关心你的业务怎么写,按照要求将需要的参数设置正确即可。
我们跟着上一篇文章继续扩展,LineUpTaskHelp类增加setTimeOut方法。 下面是具体实现。
package com.example.lineuppoject;
import android.text.TextUtils;
import android.util.Log;
import java.util.Iterator;
import java.util.LinkedList;
/**
* @param <T> 任务 任务/ 需要排队的任务, 支持扩展
* @author gongjiebin
*/
public class LineUpTaskHelp<T extends ConsumptionTask> {
/**
* 排队容器, 需要排队的才会进入此列表
*/
private LinkedList<T> lineUpBeans;
/**
* 执行下一个任务
*/
private OnTaskListener onTaskListener;
public LineUpTaskHelp<T> setOnTaskListener(OnTaskListener<T> onTaskListener) {
this.onTaskListener = onTaskListener;
return this;
}
private static LineUpTaskHelp lineUpTaskHelp;
private LineUpTaskHelp() {
// app 只会执行一直,知道释放
lineUpBeans = new LinkedList<>();
}
public static LineUpTaskHelp getInstance() {
if (lineUpTaskHelp == null) {
lineUpTaskHelp = new LineUpTaskHelp();
}
return lineUpTaskHelp;
}
/**
* 加入排队
*
* @param task 一个任务
*/
public void addTask(T task) {
if (lineUpBeans != null) {
Log.e("Post", "任务加入排队中" + task.taskNo);
if (!chackTask()) {
if (onTaskListener != null) onTaskListener.exNextTask(task);
}
lineUpBeans.addLast(task);
}
}
/**
* 设置任务超时时间。
*
* @param task
*/
public void setTimeOut(T task) {
task.setOnTimeOutLinsenet(new ConsumptionTask.OnTimeOutLinsenet() {
@Override
public void timeOut(ConsumptionTask task) {
// 设置超时监听
if (onTaskListener != null) {
onTaskListener.timeOut(task);
}
}
});
task.openTime(); // 打开超时等待。如果任务在规定时间未执行完成,则抛弃该任务
}
/**
* 检查列表中是否有任务正在执行。
*
* @return true 表示有任务正在执行。false可立即执行改任务。
*/
public boolean chackTask() {
boolean isTask = false;
if (lineUpBeans != null) {
if (lineUpBeans.size() > 0) {
for (int i = 0; i < lineUpBeans.size(); i++) {
if (!lineUpBeans.get(i).isResult) {
// 是否还有未执行的任务
isTask = true;
break;
}
}
}
}
return isTask;
}
/**
* 得到下一个执行的计划,
*
* @return 返回下一个将要执行的任务, 返回null ,代表没有任务可以执行了
*/
public T getFirst() {
T task = null;
if (lineUpBeans != null) {
for (int i = 0; i < lineUpBeans.size(); i++) {
if (!lineUpBeans.get(i).isResult) {
// 找到还没有未执行的任务
task = lineUpBeans.get(i);
break;
}
}
}
return task;
}
/**
* 执行成功之后,删除排队中的任务。
*
* @param task
*/
private void deleteTask(T task) {
if (lineUpBeans != null && task != null) {
deleteTaskNoAll(task.taskNo);
}
}
/**
* 删除对应计划id的所有任务
*
* @param planNo
*/
public void deletePlanNoAll(String planNo) {
if (lineUpBeans != null) {
Iterator iterator = lineUpBeans.iterator();
if (TextUtils.isEmpty(planNo)) return;
while (iterator.hasNext()) {
ConsumptionTask task = (ConsumptionTask) iterator.next();
if (task.planNo.equals(planNo)) {
iterator.remove();
}
}
}
}
/**
* 删除对应任务id的项
*
* @param taskNo
*/
public void deleteTaskNoAll(String taskNo) {
if (lineUpBeans != null) {
Iterator iterator = lineUpBeans.iterator();
if (TextUtils.isEmpty(taskNo)) return;
while (iterator.hasNext()) {
ConsumptionTask task = (ConsumptionTask) iterator.next();
if (task.taskNo.equals(taskNo)) {
iterator.remove();
break;
}
}
}
}
/**
* 外部调用, 当执行完成一个任务调用
*/
public void exOk(T task) {
deleteTask(task); // 删除已经执行完成的任务。
if (lineUpBeans != null) {
if (chackTask()) {
// 发现还有任务
if (onTaskListener != null) {
onTaskListener.exNextTask(lineUpBeans.getFirst());
}
} else {
if (onTaskListener != null) {
onTaskListener.noTask();
}
}
}
}
/**
* 当第一个任务执行完成,发现列队中还存在任务, 将继续执行下一个任务
*/
public interface OnTaskListener<T extends ConsumptionTask> {
/**
* 执行下一个任务
*
* @param task
*/
void exNextTask(T task);
/**
* 所有任务执行完成
*/
void noTask();
/**
* 超时未执行
*
* @param task
*/
void timeOut(T task);
}
}
ConsumptionTask类的扩展
package com.example.lineuppoject;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import androidx.annotation.NonNull;
/**
*
*/
public class ConsumptionTask{
/*
子ID,在列队中保持唯一。对应的是一条数据。
*/
public String taskNo;
/**
* 父ID,通常以组的方式出现,关联一组相关的数据
*/
public String planNo;
/**
* 超时时间, 定义任务的最长执行时间,0为无效时间,不能设置为负数,毫秒
*/
public long timeOut;
/**
* false:该任务未返回结果,true:该任务已经有结果了。
*/
public boolean isResult;
/**
* 该任务是不是超时引起的任务失败
*/
public boolean isTimeOut;
public OnTimeOutLinsenet onTimeOutLinsenet;
public void setOnTimeOutLinsenet(OnTimeOutLinsenet onTimeOutLinsenet) {
this.onTimeOutLinsenet = onTimeOutLinsenet;
}
/**
* 打开超时等待
*/
public void openTime(){
// 线程在执行完之后会自动关闭
new TaskThread().setTask(ConsumptionTask.this).start();
}
/**
* 监听任务是否超时
*/
public interface OnTimeOutLinsenet{
/**
* 超时未执行
* @param task
*/
void timeOut(ConsumptionTask task);
}
}
新增TaskThread类,此线程为记录单个任务的执行时长
package com.example.lineuppoject;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
/**
* 记录任务超时线程
*/
public class TaskThread extends Thread {
private ConsumptionTask task;
/**
*
*/
private Handler handler;
public TaskThread(){
handler = new Handler(Looper.getMainLooper());
}
public TaskThread setTask(ConsumptionTask task) {
this.task = task;
return this;
}
public ConsumptionTask getTask() {
return task;
}
@Override
public void run() {
super.run();
if (task.timeOut == 0) return;
Log.e("Post", "记录当前任务,任务id:" + task.taskNo + "超时时间" + (task.timeOut / 1000) + "s");
// handler.removeCallbacks(runnable);
handler.postDelayed(runnable, task.timeOut);
}
Runnable runnable = new Runnable() {
@Override
public void run() {
if (!task.isResult) {
// 设置的超时时间到了,但是还没有结果
task.isTimeOut = true; // 是超时引起的错误。
task.onTimeOutLinsenet.timeOut(getTask());
}
// 记得移除
handler.removeCallbacks(runnable);
}
};
}
应用-Test
package com.example.lineuppoject;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
LineUpTaskHelp lineUpTaskHelp;
int index = 0;
private EditText et_time;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 文本框。
et_time = findViewById(R.id.et_time);
lineUpTaskHelp = LineUpTaskHelp.getInstance();
findViewById(R.id.btn_on).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ConsumptionTask task = new ConsumptionTask();
task.taskNo = "Task" + (index++); // 确保唯一性
task.planNo = "No9527"; // 将数据分组, 如果没有该需求的同学,可以不进行设置
// 开始执行任务之前,设置超时时间,
task.timeOut = Long.parseLong(et_time.getText().toString().trim()) * 1000; //
lineUpTaskHelp.addTask(task); // 添加到排队列表中去, 如果还有任务没完成,
et_time.setText(""); // 清空
}
});
initListener();
}
/**
* 注册任务监听
*/
private void initListener(){
lineUpTaskHelp.setOnTaskListener(new LineUpTaskHelp.OnTaskListener() {
@Override
public void exNextTask(ConsumptionTask task) {
exTask(task);
}
@Override
public void noTask() {
Log.e("Post","所有任务执行完成");
}
@Override
public void timeOut(ConsumptionTask task) {
// 超时了.
Log.e("Post","超时了,任务ID为:" + task.taskNo);
// 具体业务逻辑根据自己需求来编写,可以重新执行,也可放弃执行,继续下一条任务
// 检查列队, 发现任务并开始执行
lineUpTaskHelp.exOk(task);
}
});
}
/**
* 模拟执行任务呢
*/
public void exTask(final ConsumptionTask task){
new Thread(){
@Override
public void run() {
super.run();
Log.e("Post","开始执行任务" + task.taskNo + "设置的超时时间为:" + (task.timeOut/1000) + "s");
lineUpTaskHelp.setTimeOut(task); // 启动超时。干掉这句将不会记录任务超时
SystemClock.sleep(40*1000); // 模拟任务执行过程.这段代码就是你自己的业务代码, 这个延时40s模拟任务执行过程。
task.isResult = true; // 执行完成,标记为已经执行(不管任务执行成功或者失败都要在任务执行完成之后赋值为true)
if(task.isTimeOut){
// 。。 如果是超时引起的错误,将回调timeOut方法
return;
}
Log.e("Post","任务执行完成--------任务ID为:" + task.taskNo);
// if(isOdd(System.currentTimeMillis())){
// // 模拟任务执行的结果====失败,如果一个任务失败了会导致整个计划失败,请调用此方法。
// Log.e("Post","任务失败了,结束掉相关联正在排队的任务组");
// lineUpTaskHelp.deletePlanNoAll(task.planNo);
// }
lineUpTaskHelp.exOk(task);
}
}.start();
}
public boolean isOdd(long i) {
return (i & 1) == 1;
}
}