最近我發現,項目中的Handler實例越來越多了,且非常的雜亂。甚至有的時候,只是爲了一個定時任務、延遲任務,便new了一個新的Handler實例。毫無疑問,這樣的寫法必然會導致最後的代碼冗餘極高,且極難維護。
由此我想通過一個全局的Handler來實現優化,防止代碼冗餘。以下是我的做法。
首先定義一個ThreadUtil類
public class ThreadUtil {
//do something
}
其次,在類中寫一個靜態方法:isRunMainThread()
public class ThreadUtil {
/**
* 用於判斷當前是否運行在主線程中
*/
public static boolean isRunMainThread() {
return Looper.getMainLooper() == Looper.myLooper();
}
}
然後在該類中再定義一個Handler
public class ThreadUtil {
/**
* 這個Handler將會是整個項目中唯一的Handler實例
*/
private static Handler handler = new Handler() {
@Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
//do something
}
};
/**
* 用於判斷當前是否運行在主線程中
*/
public static boolean isRunMainThread() {
return Looper.getMainLooper() == Looper.myLooper();
}
}
寫好這兩個基礎之後,我們就要開始對其進行拓展了。拓展的第一步是實現我們的基本需求:線程切換。
一般情況下,我們可以通過View.post(Runnable run)、Handler.post(Runnable run)等方法,從子線程中跳轉至主線程來操作UI。
有時候也會通過new Thread(Runnable run).start()方法,從主線程跳轉至子線程來進行一些耗時操作,比如IO操作、網絡請求等。
基於這兩種需求,我們可以在ThreadUtil類中添加兩個方法:runOnMainThread、runOnChildThread
public class ThreadUtil {
/.../
/**
* 將傳入的Runnable在主線程中運行起來
*/
public static void runOnMainThread(Runnable runnable) {
if (runnable == null) return;
if (isRunMainThread()) {
runnable.run();
} else {
handler.post(runnable);
}
}
/**
* 將傳入的Runnable在子線程中運行
*/
public static void runOnChildThread(Runnable runnable) {
if (runnable == null) return;
if (isRunMainThread()) {
new Thread(runnable).start();
} else {
runnable.run();
}
}
}
這兩個方法的原理都非常簡單。就是將需要執行的代碼塊,包裝在Runnable接口中,然後作爲參數傳入即可。
可是光是這樣不能算優雅,還可以繼續拓展,使這個類的功能更強大。
拓展第二步,延遲執行:
很多時候,我們並不希望Runnable中的代碼馬上執行,這是就需要延遲操作,那麼在我們這個類裏怎麼拓展呢?
public class ThreadUtil {
private static final int DelayedRunChildThread = 1;
/**
* 這個Handler將會是整個項目中唯一的Handler實例
*/
private static Handler handler = new Handler() {
@Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
switch (msg.what) {
case DelayedRunChildThread:
runOnChildThread((Runnable) msg.obj);
break;
}
}
};
/.../
/**
* 在主線程中延遲執行一個Runnable接口
* @param time 延遲時間,以毫秒爲單位
*/
public static void runOnMainThreadDelayed(Runnable runnable, long time) {
if (runnable == null || time < 0) return;
handler.postDelayed(runnable, time);
}
/**
* 延遲執行一個子線程
* @param time 延遲時間,以毫秒爲單位
*/
public static void runOnChildThreadDelayed(Runnable runnable, long time) {
if (runnable == null || time < 0) return;
Message message = Message.obtain();
message.what = DelayedRunChildThread;
message.obj = runnable;
handler.sendMessageDelayed(message, time);
}
}
這裏我又添加了兩個方法:runOnMainThreadDelayed、runOnChildThreadDelayed。
如此一來,既可以在主線程中進行一些延遲操作,也可以在子線程中進行一些延遲操作。可這樣寫也帶來一些問題。
假設,某個代碼塊Runnable A延遲10秒執行,可到第7秒時,我想取消這個Runnable A怎麼辦?按照我們現在的寫法,似乎無法優雅的移除掉某個延遲的Runnable。
那麼我們再對ThreadUtil進行一次拓展,讓它具備移除Runnable任務的功能。傳送門->Android中優雅的線程切換寫法(二)