Android實(shí)現(xiàn)定時(shí)器的幾種方法

前言

這幾天正在看Android官方的開(kāi)發(fā)文檔,里面有很多很值得思考的開(kāi)發(fā)建議,有時(shí)間的朋友可以去看一下(官方是英文文檔,如果看不懂可以通過(guò)瀏覽器插件翻譯對(duì)比著看,還是很方便的)。

其中一篇課程提到了AlarmManager,這個(gè)類之前僅僅是了解這是一個(gè)鬧鐘的管理器,如果要是做一些勝過(guò)提醒、鬧鐘之類的軟件都需要用到。官方的例子用來(lái)實(shí)現(xiàn)定時(shí)器,突然覺(jué)得這是一個(gè)很神奇的事情,就搜集了一些資料,把我知道的實(shí)現(xiàn)計(jì)時(shí)器的幾種方法寫(xiě)下來(lái),給自己加深記憶,也分享給大家。

正文

我用到的幾種實(shí)現(xiàn)定時(shí)器的類:Handler, Timer, Thread, AlarmManager。

AlarmManager

AlarmManager是系統(tǒng)開(kāi)放的鬧鐘功能,使用方式和普通的manager沒(méi)有區(qū)別。

AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);  
// Schedule the alarm!  
Intent intent = new Intent(XXXXX);
PendingIntent sender = PendingIntent.getBroadcast(mcontext,requestCode, intent, 0);  
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,  
                         firstTime, 30*1000, sender); 

上面就是定時(shí)器的基本用法,先獲取manager,然后定義鬧鐘的flag,循環(huán)時(shí)間,到指定時(shí)間發(fā)出的pendingIntent。

一般都發(fā)出的pendingIntent都是廣播,我們自定義一個(gè)廣播接收器,就可以通過(guò)接收這個(gè)廣播,來(lái)處理自己的功能邏輯了。

這里需要注意在獨(dú)立進(jìn)程中配置,這是android所定義的

<receiver android:name="com.xxxx.Receiver" android:process=":remote" />

優(yōu)點(diǎn)總結(jié)##

1,Alarm定時(shí)不需要程序自身去維護(hù),而又系統(tǒng)來(lái)維護(hù),使得程序更好避免了容易出錯(cuò)問(wèn)題,更是占用系統(tǒng)資源,cpu占有率。

2,即使程序退出后,程序自身不會(huì)有任何煩惱的問(wèn)題,系統(tǒng)到時(shí)間自動(dòng)調(diào)用對(duì)應(yīng)組件執(zhí)行定義好的邏輯

3,定時(shí)的多樣性,包括一次定時(shí),循環(huán)定時(shí)(在xx年x月x日?qǐng)?zhí)行,周一至周五執(zhí)行,每天幾點(diǎn)幾分執(zhí)行。。。)

適用場(chǎng)景##

個(gè)人覺(jué)得比較適用于獨(dú)立的功能邏輯,例如如果app需要定時(shí)從服務(wù)器抓取最新的數(shù)據(jù),使用獨(dú)立的service會(huì)與主體的功能分離、便于維護(hù),關(guān)鍵是耗電低,不易出錯(cuò)。

Handler

Handler可以幫助我們?cè)谧泳€程中操作UI線程,例如子線程解析數(shù)據(jù),解析結(jié)束后通知UI刷新界面。他本身也可以實(shí)現(xiàn)定時(shí)器。

private Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case 0:
                // 移除所有的msg.what為0等消息,保證只有一個(gè)循環(huán)消息隊(duì)列再跑
                handler.removeMessages(0);
                // app的功能邏輯處理
                ...
                // 再次發(fā)出msg,循環(huán)更新
                handler.sendEmptyMessageDelayed(0, 1000);
                break;

            case 1:
                // 直接移除,定時(shí)器停止
                handler.removeMessages(0);
                break;

            default:
                break;
            }
        };
    };

只要在啟動(dòng)定時(shí)器的時(shí)候,Handler.sendEmptyMessage(0),定時(shí)器就啟動(dòng)了。繼續(xù)循環(huán)和停止的方法,注釋上已經(jīng)寫(xiě)了。

優(yōu)點(diǎn)總結(jié)##

每次循環(huán)都是在主線程中操作,避免了子線程和主線程之間的穿插交互,個(gè)人覺(jué)得比timer好控制,功能實(shí)現(xiàn)也很簡(jiǎn)單。

適用場(chǎng)景##

個(gè)人覺(jué)得比較適用連續(xù)更新UI,不做復(fù)雜耗時(shí)的處理的情況,例如在播放器中,我們需要更新當(dāng)前播放進(jìn)度的時(shí)間的顯示,僅僅是更新了文字顯示,用handler就是個(gè)不錯(cuò)的選擇。

Timer

Timer是Android直接啟動(dòng)定時(shí)器的類,也是我最早接觸可以實(shí)現(xiàn)定時(shí)器的功能的工具類。

他的用法一般人都知道:

// 初始化定時(shí)器
Timer timer = new Timer();
timer.schedule(new TimerTask() {

    @Override
    public void run() {
        Log.e("lzp", "timer excute");
    }
}, delay, period);

// 停止定時(shí)器
private void stopTimer(){
    if(timer != null){
        timer.cancle();
        // 一定設(shè)置為null,否則定時(shí)器不會(huì)被回收
        timer = null;
    }
}

delay : 從定時(shí)器初始化成功 開(kāi)始啟動(dòng) 的延遲時(shí)間。
period:定時(shí)器的間隔時(shí)間。

優(yōu)點(diǎn)總結(jié)##

Timer的使用很簡(jiǎn)單,TimerTask是一個(gè)子線程,方便處理一些比較復(fù)雜耗時(shí)的功能邏輯,經(jīng)常與handler結(jié)合使用。

適用場(chǎng)景

跟handler自身實(shí)現(xiàn)的定時(shí)器相比,Timer可以做一些復(fù)雜的處理,例如,需要對(duì)有大量對(duì)象的list進(jìn)行排序,在TimerTask中執(zhí)行不會(huì)阻塞子線程,常常與handler結(jié)合使用,在處理完復(fù)雜耗時(shí)的操作后,通過(guò)handler來(lái)更新UI界面。

**特別吐槽:對(duì)于部分手機(jī),如果你在TimerTask直接更新了UI線程是不會(huì)報(bào)錯(cuò)的,而且運(yùn)行正常,但是一定注意,更新UI一定要在主線程中執(zhí)行,否則排查錯(cuò)誤的時(shí)候你懂得。而且這個(gè)東西特別耗電,特別耗電,特別耗電,重要的事情說(shuō)三遍,一定在不使用的時(shí)候關(guān)閉,慎用。
**

Thread##

Thread實(shí)現(xiàn)定時(shí)器是創(chuàng)建一個(gè)子線程,在里面while循環(huán),可以通過(guò)handler來(lái)更新UI。個(gè)人覺(jué)得Thread和Timer沒(méi)區(qū)別,只是長(zhǎng)得不一樣。

private MyThread thread;

    private class MyThread extends Thread {

        public boolean stop;

        public void run() {
            while (!stop) {
                // 處理功能

                // 通過(guò)睡眠線程來(lái)設(shè)置定時(shí)時(shí)間
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        };
    };

    /**
     * 啟動(dòng)線程
     * */
    private void start() {
        if (thread == null) {
            thread = new MyThread();
            thread.start();
        }
    }

    /**
     * 停止線程
     * */
    private void stop() {
        if (thread != null) {
            thread.stop = true;
            thread = null;
        }
    }

優(yōu)點(diǎn)總結(jié)

覺(jué)得跟Timer差不多,沒(méi)什么特殊優(yōu)點(diǎn)

適用場(chǎng)景

跟Timer差不多吧 ,多線程如果考慮不周經(jīng)常會(huì)出問(wèn)題,經(jīng)常會(huì)出現(xiàn)多個(gè)相同功能的線程同時(shí)存在,android本身對(duì)于子線程的使用使用數(shù)量是有限制的,而且一個(gè)app同時(shí)跑多個(gè)線程是一個(gè)很可怕的事情,所以和Timer一樣,使用的時(shí)候一定要謹(jǐn)慎考慮。

結(jié)尾

以上就是我個(gè)人使用過(guò)的定時(shí)器的幾種實(shí)現(xiàn)的方法,但是都僅僅是簡(jiǎn)單的介紹,更為詳細(xì)的用法在網(wǎng)上有很多相關(guān)的資料,如果有錯(cuò)誤,歡迎留言批評(píng)指正,希望看完這篇文章能對(duì)你有所幫助。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容