android定時器AlarmManager

好久沒寫Blog了,一是最近項目比較忙,二也是最近家裏的事也比較多
好了,寒暄到此爲止,貌似有些短暫 😁


最近項目有一些位置信息需要實時去上傳,也有好長一段時間沒用過心跳服務了,一直都在用激光推動啊,阿里的MQTT啊

也是藉此機會複習一下這個簡單的Service

那麼這裏用的定時器就是Google推薦的Alarm
下面簡單介紹一下這個AlarmManager

一. AlarmManager的常用方法有三個:

1.set(int type,long startTime,PendingIntent pi);
該方法用於設置一次性鬧鐘,第一個參數表示鬧鐘類型,第二個參數表示鬧鐘執行時間,第三個參數表示鬧鐘響應動作。

2.setRepeating(int type,long startTime,long intervalTime,PendingIntent pi);
該方法用於設置重複鬧鐘,第一個參數表示鬧鐘類型,第二個參數表示鬧鐘首次執行時間,第三個參數表示鬧鐘兩次執行的間隔時間,第三個參數表示鬧鐘響應動作。

3.setInexactRepeating(int type,long startTime,long intervalTime,PendingIntent pi);
該方法也用於設置重複鬧鐘,與第二個方法相似,不過其兩個鬧鐘執行的間隔時間不是固定的而已。

二. 參數詳解:

**1.**int type: 鬧鐘的類型,常用的有5個值:AlarmManager.ELAPSED_REALTIME、 AlarmManager.ELAPSED_REALTIME_WAKEUP、AlarmManager.RTC、 AlarmManager.RTC_WAKEUP、AlarmManager.POWER_OFF_WAKEUP。

AlarmManager.ELAPSED_REALTIME表示鬧鐘在手機睡眠狀態下不可用,該狀態下鬧鐘使用相對時間(相對於系統啓動開始),狀態值爲3;

AlarmManager.ELAPSED_REALTIME_WAKEUP表示鬧鐘在睡眠狀態下會喚醒系統並執行提示功能,該狀態下鬧鐘也使用相對時間,狀態值爲2;

AlarmManager.RTC表示鬧鐘在睡眠狀態下不可用,該狀態下鬧鐘使用絕對時間,即當前系統時間,狀態值爲1;

AlarmManager.RTC_WAKEUP表示鬧鐘在睡眠狀態下會喚醒系統並執行提示功能,該狀態下鬧鐘使用絕對時間,狀態值爲0;

AlarmManager.POWER_OFF_WAKEUP表示鬧鐘在手機關機狀態下也能正常進行提示功能,所以是5個狀態中用的最多的狀態之一,該狀態下鬧鐘也是用絕對時間,狀態值爲4;不過本狀態好像受SDK版本影響,某些版本並不支持;

2. long startTime: 鬧鐘的第一次執行時間,以毫秒爲單位,可以自定義時間,不過一般使用當前時間。需要注意的是,本屬性與第一個屬性(type)密切相關,

3. long intervalTime:對於後兩個方法來說,存在本屬性,表示兩次鬧鐘執行的間隔時間,也是以毫秒爲單位。

4. PendingIntent pi: 綁定了鬧鐘的執行動作,比如發送一個廣播、給出提示等等。PendingIntent是Intent的封裝類。需要注意的是,如果是通過啓動服務來實現鬧鐘提 示的話,PendingIntent對象的獲取就應該採用Pending.getService(Context c,int i,Intent intent,int j)方法;如果是通過廣播來實現鬧鐘提示的話,PendingIntent對象的獲取就應該採用 PendingIntent.getBroadcast(Context c,int i,Intent intent,int j)方法;如果是採用Activity的方式來實現鬧鐘提示的話,PendingIntent對象的獲取就應該採用 PendingIntent.getActivity(Context c,int i,Intent intent,int j)方法。如果這三種方法錯用了的話,雖然不會報錯,但是看不到鬧鐘提示效果。

接下來 也是直接上代碼吧

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.support.annotation.Nullable;

import com.bohan.ems.mdm.MdmManage;
import com.bohan.ems.mdm.utils.Constant;
import com.bohan.icexpressapp.business.base.ViewCallback;
import com.bohan.icexpressapp.core.MainApplication;
import com.bohan.icexpressapp.core.log.SLog;
import com.bohan.icexpressapp.network.base.BaseReq;
import com.bohan.icexpressapp.network.networkserver.handoverserver.entity.BeanRespEmpty;

import org.apache.commons.lang3.StringUtils;

/**
 * @author The sky seems to be raining
 * @class 主線程心跳服務
 */
public class HeartBeatService extends Service {

    // 心跳間隔
    // 以前爲final static的,但是服務器要求修改間隔時間,則去掉
    //心跳間隔時間 默認毫秒
    public static final int DEFAULT_INTERVAL = 3 * 60 * 1000;
    //心跳間隔時間 默認毫秒
    public static int HEART_SPE = DEFAULT_INTERVAL;
    public static final String ACTION_ALARM_HEARTBEAT = "ACTION_ALARM_HEARTBEAT";

    private PendingIntent heartbeatPi = null;
    private AlarmManager heartbeatAlarm;

    private MainService mMainService;
    private int shark = 0;

    private ScreenControlAlarmReceiver screenControlAlarmReceiver;

    /**
     * 初始化窗口
     */
    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("### N1GHeartService onCreate");
        initData();
        initReceiver();
    }

    private void initData() {
        mMainService = new MainService(MainApplication.getInstance());
        heartbeatAlarm = (AlarmManager) getSystemService(ALARM_SERVICE);
    }

    /**
     * 初始化接收對象
     */
    private void initReceiver() {
        screenControlAlarmReceiver = new ScreenControlAlarmReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ACTION_ALARM_HEARTBEAT);
        registerReceiver(screenControlAlarmReceiver, intentFilter);
    }

    /**
     * 釋放資源
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(screenControlAlarmReceiver);
        endTimer();
    }

    // 每次啓動Servcie時都會調用該方法
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("--onStartCommand()--");
        shark = intent.getIntExtra("SHARK", DEFAULT_INTERVAL);
        startTimer(shark * 1000 + "");
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * 更新心跳間隔,並啓動心跳
     *
     * @param timeString 心跳間隔  單位:毫秒
     */
    private void startTimer(String timeString) {

        HEART_SPE = DEFAULT_INTERVAL;
        int tempTime = 0;
        if (StringUtils.isEmpty(timeString) || "null".equals(timeString)) {
            //如果登錄認證就失敗了,也需要啓動timer
            tempTime = HEART_SPE;
        } else {
            try {
                tempTime = Integer.parseInt(timeString);
            } catch (NumberFormatException e) {
                tempTime = HEART_SPE;
                e.printStackTrace();
            }
        }

        if (tempTime == HEART_SPE && heartbeatPi != null) {
            //間隔時間和原來一致,並且啓動過timer,不重啓timer
            return;
        } else {
            //間隔時間和原來不一致,重啓timer
            HEART_SPE = tempTime;
            endTimer();

            Intent alarmIntent = new Intent(ACTION_ALARM_HEARTBEAT);
            heartbeatPi = PendingIntent.getBroadcast(HeartBeatService.this, 0, alarmIntent, 0);//通過廣播接收
            heartbeatAlarm.setRepeating(AlarmManager.RTC, 0, HEART_SPE, heartbeatPi);//INTERVAL毫秒後觸發
            SLog.Console("心跳間隔:" + HEART_SPE + "");
            heartBeat();

        }
    }

    public class ScreenControlAlarmReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //你的邏輯處理
            //如果需要實現間隔定時器功能,在重新執行1的發送步驟,實現間隔定時,間隔時間爲INTERVAL
            heartBeat();
        }
    }

    /**
     * 停止心跳
     */
    private void endTimer() {
        if (heartbeatAlarm != null && heartbeatPi != null) {
            heartbeatAlarm.cancel(heartbeatPi);
            heartbeatPi = null;
        }
    }

    /**
     * 心跳上傳數據
     */
    private void heartBeat() {
        BeanRespEmpty req = new BeanRespEmpty();
        mMainService.heartbeat(new BaseReq<>(req), new ViewCallback() {
            @Override
            public void returnResult(boolean result, Object... objects) {
                if (result) {
                    SLog.Console("心跳上傳位置信息成功" +
                            Constant.LOCATION + ":" + MdmManage.getInstance().getLongiTude() + "," +
                            MdmManage.getInstance().getLatiTude() + "," + MdmManage.getInstance().getLastAlt());
                } else {
                    SLog.Console("心跳上傳位置信息失敗" +
                            Constant.LOCATION + ":" + MdmManage.getInstance().getLongiTude() + "," +
                            MdmManage.getInstance().getLatiTude() + "," + MdmManage.getInstance().getLastAlt());
                }
            }
        });
    }
}

看完代碼,總結一下使用步驟吧

AlarmManager的使用步驟

1)初始化ALarmManager實例 ALarmManager am=(ALarmManager)getSystemService(ALARM_SERVICE);
2)定義一個PendingIntent發出廣播
3)調用ALarmManager方法,設置定時或重複提醒
4)取消提醒:
我這直接用的cancle方法,並且記得註銷掉廣播監聽器

是不是特別簡單實用啊,如文中有不對的地方,請及時糾正,謝謝大家

另外,文中很多代碼可能與實際業務相關,我實在是懶得刪除了,大家一看便知,最後提前祝大家臘八節快樂

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章