handler思想的个人简单实现2——postDelayed猜想

本文为文章《handler思想的个人简单实现》的续作。

https://blog.csdn.net/cjzjolly/article/details/79386416 

 

在平常开发过程中,常常会用到handler里面的postDelay作为一种执行延时任务的工具,其实就是UI线程循环里面塞了点“插曲”,比Timer节约一点资源。我突发奇想想试试在不看它代码实现的情况下能不能实现出类似的Handler,首先我想到了加入一个Runnable之后直接上sleep,可是这样太耗费资源了,所以我最后使用了一个后台线程执行倒计时,时间到了或者超过了任务的预定时刻,就执行handler任务列表里面相应的需要该时刻执行的runnable。这样做的好处是占用资源少,但实际上这个方法在任务表的runnable变多的时候,其实是时间变得不那么精确的。

 

 

代码不是十分长,也比较容易看懂,看看注释一定能懂,所以直接贴代码啦。以下就是我的实现方法:

 

Handler类:

package com.test.handler;

import java.util.ArrayList;
import java.util.List;

public class Handler {

	private List taskList = new ArrayList<>();

	/** 任务单元 **/
	private class Task {
		/** 任务runnalbe **/
		public Runnable runnable;
		/** 延迟多少毫秒之后执行Runnable **/
		public long delayed;

		public Task(Runnable runnable, long delayed) {
			this.runnable = runnable;
			this.delayed = delayed;
		}
	}

	private Object endLock = new Object();

	/** 内部循环 **/
	private class LoopThread extends Thread {
		
		long distance = 0;
		@Override
		public void run() {
			super.run();

			while (!taskList.isEmpty()) {
				long start = System.currentTimeMillis();
				for (int i = 0; i < taskList.size(); i++) {
					Task task = taskList.get(i);
					synchronized (task) {
						if (task != null) {
							if ((task.delayed -= distance < 1 ? 1 : distance) <= 0) {
								new Thread(task.runnable).start();
								taskList.remove(i);
								i--;
							}
						}
					}
				}
				long end = System.currentTimeMillis();
				distance = end - start;
				try {
					Thread.sleep(distance < 1 ? 1 : 0);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//System.out.println("已路过时间:" + distance);
			}
			synchronized (endLock) {
				// 线程已经完成所有任务,清空,退出,不占额外资源
				loopThread = null;
			}
		}
	}

	private LoopThread loopThread = null;

	/**添加延时任务**/
	public void postDealyed(Runnable r, long dealyMS) {
		taskList.add(new Task(r, dealyMS));
		synchronized (endLock) {
			if (loopThread == null) { // 如果线程为空
				loopThread = new LoopThread();
				loopThread.start();
			}
		}
	}
	
	/**删除延时任务**/
	public void remove(Runnable r){
		for (int i = 0; i < taskList.size(); i++) {
			Task task = taskList.get(i);
			synchronized (task) {
				if (task != null && task.runnable == r) {
					taskList.remove(i);
					break;
				}
			}
		}	
	}

}

测试类:

package com.test.handler;

public class TestMain {

	public static void main(String args[]){
		Handler handler = new Handler();
		//测试同时加几个延时任务
		handler.postDealyed(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("HandlerTest1");
			}
		}, 3000);
		
		handler.postDealyed(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("HandlerTest2");
			}
		}, 5000);
		
		handler.postDealyed(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("HandlerTest3");
			}
		}, 0);
		
		//测试移除:
		Runnable r = new Runnable() {
			
			@Override
			public void run() {
				System.out.println("HandlerTest4");
			}
		};
		handler.postDealyed(r, 6000);
		handler.remove(r);
		
		//测试在Handler内部循环线程已经结束的时候再加一个任务
		try {
			Thread.sleep(9000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		handler.postDealyed(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("end");
			}
		}, 300);
	}
}

测试效果:

 

 

//20190331  修正了一些效率问题,采用ArrayList代替LinkedList提高遍历速度

你可能感兴趣的:(安卓开发,理论基础,JAVA)