android-线程管理-TaskHelper

以前线程总是使用new Thread().start()这种方式,或者使用线程池ThreadPoolExecutor管理,但是线程池只能控制数量,无法控制逻辑,各种线程之间的逻辑关系和顺序等

所以我封装了一个线程管理的类TaskHelper

TaskHelper主要功能
1.很多线程集中管理起来使用单线程多任务模式简化逻辑,特别是网络线程
2.串行的执行方式,可以在不同的类里创建任务并且排队执行,非常方便的管理了线程,例如多同一个文件的io操作,简单的处理
3.不同id的线程可以通过join来管理顺序,简化了很多操作,优化项目结构

TaskHelper 实现代码

import android.os.Process;
import android.util.Log;
import android.util.SparseArray;

import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class TaskHelper {
    private final static String TAG = "TaskHelper";
    private SparseArray helperArray;
    private volatile static TaskHelper instance;

    public static TaskHelper getInstance() {
        if (instance == null) {
            synchronized (TaskHelper.class) {
                if (instance == null) {
                    instance = new TaskHelper();
                }
            }
        }
        return instance;
    }

    private TaskHelper() {
        if (helperArray == null) {
            helperArray = new SparseArray();
        }
    }

    public static SingleTask getTask(int taskId) {
        TaskHelper helper = getInstance();
        SingleTask task;
        synchronized (helper.helperArray) {
            task = helper.helperArray.get(taskId);
            if (task == null) {
                task = new SingleTask(taskId);
                helper.helperArray.put(taskId, task);
            }
        }
        return task;
    }

    public void cancel() {
        synchronized (helperArray) {
            int size = helperArray.size();
            for (int i = 0; i < size; i++) {
                SingleTask task = helperArray.valueAt(i);
                task.cancel();
            }
            helperArray.clear();
        }
        instance = null;
    }

    public void cancel(int taskId) {
        SingleTask task = null;
        synchronized (helperArray) {
            task = helperArray.get(taskId);
            if (task != null) {
                task.cancel();
                helperArray.remove(taskId);
            }
        }
    }

    public static class SingleTask {
        private BlockingQueue queue;
        private boolean isRun = false;
        private int taskId;
        private final Object lock = new Object();
        private Thread mThread;

        private SingleTask(int taskId) {
            this.taskId = taskId;
            queue = new LinkedBlockingQueue();
        }

        public boolean contains(String runnableName) {
            for (Runnable r : queue) {
                if (r.getClass().getName().equals(runnableName)) {
                    return true;
                }
            }
            return false;
        }

        public void addTaskAndRun(Runnable runnable) {
            int size = queue.size();
            queue.add(runnable);
            start();
        }

        public SingleTask addTask(Runnable runnable) {
            queue.add(runnable);
            return this;
        }

        public void join() {
            boolean b;
            synchronized (lock) {
                b = isRun;
            }
            if (b) {
                try {
                    mThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        public void cancel() {
            queue.clear();
        }

        public void start() {
            synchronized (lock) {
                if (isRun) {
                    return;
                }
                isRun = true;
                mThread = new Thread() {
                    public void run() {
                        Runnable runnable;
                        try {
                            while (isRun
                                    && (runnable = queue.poll(200,
                                    TimeUnit.MILLISECONDS)) != null) {
                                Log.i(TAG, "run task name:"
                                        + runnable.getClass().getName() + taskId);
                                try {
                                    runnable.run();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        isRun = false;
                        TaskHelper.getInstance().cancel(taskId);
                    }
                };
                mThread.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
                mThread.start();
            }
        }
    }
}
可以创建一个taskId生成器,统一管理所有的taskId
public class TaskIdFactory {
    private static int id = 0;

    public static int gen() {
        int newId;
        synchronized (TaskIdFactory.class) {
            if (id == Integer.MAX_VALUE - 1) {
                id = 0;
            }
            ++id;
            newId = id;
        }
        return newId;
    }
}

使用方法

1.运行线程
TaskHelper.getTask(TaskIdFactory.gen()).addTaskAndRun(new Runnable() {
            @Override
            public void run() {
                //TODO
            }
        });
2.单线程模式
int taskId = TaskIdFactory.gen();
TaskHelper.getTask(taskId).addTaskAndRun(new Runnable() {
            @Override
            public void run() {
                //任务1
            }
        });
TaskHelper.getTask(taskId).addTaskAndRun(new Runnable() {
            @Override
            public void run() {
                //任务2
            }
        });

当任务1和任务2的taskId相同时,任务1和任务2就会按顺序排队运行

3.如果当你在某个地方运行了很多个串联线程,然后又退出了这个界面,就可以使用
TaskHelper.getTask(taskId).cancel();

停止该线程,使排在队列后面没有运行的任务释放掉,不会再运行了。

4.如果退出了应用,则可以直接关闭所有任务
TaskHelper.getInstance().cancel();
5.两个线程直接的顺序管理,例如你的下一个界面要显示的数据要依赖任务的结果,但是任务不是在这个页面启动的。

比如,我做一个应用商店的时候,首页要显示需要更新的应用数量,就需要在首页去请求更新应用数据,但是二级页面需要更新的应用数据也依赖这个结果。如果打开二级页面的时候这个结果还没返回,就可以使用TaskHelper的线程join,来完成这个功能。这里没必要去启动Service实现那么麻烦,直接在首页使用

TaskHelper.getTask(taskId1).addTaskAndRun(new Runnable() {
            @Override
            public void run() {
                //请求数据并保存
            }
        });

然后二级页面启动一个新的任务去等待结果

TaskHelper.getTask(taskId2).addTaskAndRun(new Runnable() {
            @Override
            public void run() {
                TaskHelper.getTask(taskId1).join();
                //读取task1里获取的数据
            }
        });

你可能感兴趣的:(android-线程管理-TaskHelper)