Android 定時任務的多種實現方式


定時任務實現總結

在Android中這算是一個常用的功能了,,有興趣一起來探討下可以
Android消息機制

首先來了解一下Android的消息處理機制

    即Handlerd的運行機制,handler的運行需要底層的MessageQueue和Looper的支撐。MessageQueue(消息隊列),它的內部存儲了一些消息,以隊列的形式對外提供插入和刪除的操作(實際為單鏈表存儲)。Looper(消息循環),配合MessageQueue實現實現消息的不斷入隊和出隊工作。

一個關系圖:

這里寫圖片描述

通過Handler可以很容易將任務切換到其他線程中執行,以減少主線程的負擔,因此Handler常用來進行UI更新。這里只是簡單的進行一些概述。對應handler還不清楚的強烈建議參考以下博客:
Android 異步消息處理機制
Android AsyncTask完全解析

當然,現在已經有更好的消息處理辦法了,了解handler和Asynctask可以更好的理解Android內部消息的處理機制。
推薦:EventBus,高度解耦,代碼簡潔明了,有興趣的可以自行參考使用。
1.采用Handle與線程的sleep(long)方法

1) 定義一個Handler類,用於處理接受到的Message。

Handler handler = new Handler() {  
    public void handleMessage(Message msg) {  
        // 要做的事情  
        super.handleMessage(msg);  
    }  
};  

    1
    2
    3
    4
    5
    6

2) 新建一個實現Runnable接口的線程類,如下:

public class MyThread implements Runnable {  
    @Override  
    public void run() {  
        // TODO Auto-generated method stub  
        while (true) {  
            try {  
                Thread.sleep(10000);// 線程暫停10秒,單位毫秒  
                Message message = new Message();  
                message.what = 1;  
                handler.sendMessage(message);// 發送消息  
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
    }  
}  

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

3) 在需要啟動線程的地方加入下面語句:

new Thread(new MyThread()).start();  

    1

分析:純正的java原生實現,在sleep結束后,並不能保證競爭到cpu資源,這也就導致了時間上必定>=10000的精度問題。
2.采用Handler的postDelayed(Runnable, long)方法

1)定義一個Handler類

Handler handler=new Handler();  


Runnable runnable=new Runnable() {  
    @Override  
    public void run() {  
        // TODO Auto-generated method stub  
        //要做的事情  
        handler.postDelayed(this, 2000);  
    }  
};  

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

2) 啟動與關閉計時器

handler.postDelayed(runnable, 2000);//每兩秒執行一次runnable.  

    1

handler.removeCallbacks(runnable);

    1

分析:嗯,看起蠻不錯,實現上也簡單了,和sleep想必還不會產生阻塞,注意等待和間隔的區別。
3.采用Handler與timer及TimerTask結合的方法

1) 定義定時器、定時器任務及Handler句柄

private final Timer timer = new Timer();  
private TimerTask task;  
Handler handler = new Handler() {  
    @Override  
    public void handleMessage(Message msg) {  
        // TODO Auto-generated method stub  
        // 要做的事情  
        super.handleMessage(msg);  
    }  
};  

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

2) 初始化計時器任務

task = new TimerTask() {  
    @Override  
    public void run() {  
        // TODO Auto-generated method stub  
        Message message = new Message();  
        message.what = 1;  
        handler.sendMessage(message);  
    }  
};   

    1
    2
    3
    4
    5
    6
    7
    8
    9

3) 啟動和關閉定時器

timer.schedule(task, 2000, 3000);   

    1

timer.cancel();  

    1

此外,Timer也可以配合runOnUiThread實現,如下

    private TimerTask mTimerTask = new TimerTask() {
        @Override
        public void run() {

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    //處理延時任務
                }
            });
        }
    };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

分析:timer.schedule(task, 2000, 3000);意思是在2秒后執行第一次,之后每3000秒在執行一次。timer不保證精確度且在無法喚醒cpu,不適合后台任務的定時。
采用AlarmManger實現長期精確的定時任務

AlarmManager的常用方法有三個:

    set(int type,long startTime,PendingIntent pi);//一次性
    setExact(int type, long triggerAtMillis, PendingIntent operation)//一次性的精確版
    setRepeating(int type,long startTime,long intervalTime,PendingIntent
    pi);//精確重復
    setInexactRepeating(int type,long startTime,long
    intervalTime,PendingIntent pi);//非精確,降低功耗

type表示鬧鍾類型,startTime表示鬧鍾第一次執行時間,long intervalTime表示間隔時間,PendingIntent表示鬧鍾響應動作

對以上各個參數的詳細解釋
鬧鍾的類型:

    AlarmManager.ELAPSED_REALTIME:休眠后停止,相對開機時間
    AlarmManager.ELAPSED_REALTIME_WAKEUP:休眠狀態仍可喚醒cpu繼續工作,相對開機時間
    AlarmManager.RTC:同1,但時間相對於絕對時間
    AlarmManager.RTC_WAKEUP:同2,但時間相對於絕對時間
    AlarmManager.POWER_OFF_WAKEUP:關機后依舊可用,相對於絕對時間

    絕對時間:1970 年 1月 1 日 0 點

startTime:
鬧鍾的第一次執行時間,以毫秒為單位,一般使用當前時間。

    SystemClock.elapsedRealtime():系統開機至今所經歷時間的毫秒數
    System.currentTimeMillis():1970 年 1 月 1 日 0 點至今所經歷時間的毫秒數

intervalTime:執行時間間隔。

PendingIntent :
PendingIntent用於描述Intent及其最終的行為.,這里用於獲取定時任務的執行動作。
詳細參考譯文:PendingIntent

利用AlarmManger+Service+BarocastReceiver實現5s一次打印操作

服務類:

public class HorizonService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d("TAG", "打印時間: " + new Date().
                        toString());
            }
        }).start();
        AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
        int five = 5000; // 這是5s
        long triggerAtTime = SystemClock.elapsedRealtime() + five;
        Intent i = new Intent(this, AlarmReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
        return super.onStartCommand(intent, flags, startId);
    }
}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

廣播接受器

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent i = new Intent(context, HorizonService.class);
        context.startService(i);
    }
}

    1
    2
    3
    4
    5
    6
    7

啟動定時任務:

Intent intent = new Intent(this,HorizonService.class);
startService(intent);

    1
    2

效果Demo:
這里寫圖片描述

本例通過廣播接收器和服務的循環調用實現了無限循環的效果,當然,你也可以直接利用setRepeating實現同樣的效果。

注意:不要忘了在manifest文件中注冊服務和廣播接收器。

    AlarmManager的取消方法:AlarmManger.cancel();

分析:該方式可喚醒cpu甚至實現精確定時,適用於配合service在后台執行一些長期的定時行為。

本文總結:不建議使用第一種方式,短期的定時任務推薦第二、三種方式實現,長期或者有精確要求的定時任務則可以配合Service在后台執行。

有其他疑問可下方提出或者直接鏈接官方文檔AlarmService
---------------------
作者:痕跡天涯119
來源:CSDN
原文:https://blog.csdn.net/u014492609/article/details/51475254
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM