歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android 結合AlarmManager淺談Intent和PendingIntent

Android 結合AlarmManager淺談Intent和PendingIntent

日期:2017/3/1 9:56:25   编辑:Linux編程

首先簡單說一下AlarmManager,AlarmManager的機制:全局定時器(又稱為鬧鐘),在特定的時刻為我們廣播一個指定的Intent,兩種形式:

1.在指定的時刻到來時執行某項操作,如你已經設定了一個鬧鐘時間,當該時間到來時,AlarmManager就為我們廣播一個已設定的Intent,通過這個intent來執行一些操作[實際上是PendingIntent]

2.以指定的時間間隔周期性的執行某項操作,這個就不解釋了



AlarmManager的鬧鐘類型及方法:

Android系統提供了四種類型的鬧鐘:

(1)、ELAPSED_REALTIME:在指定的延時之後發送Intent,但不喚醒設備

(2)、ELAPSED_REALTIME_WAKEUP:在指定的延時之後發送Intent,同時喚醒設備

延時是會把系統啟動的時間SystemClock.elapsedRealtime()算進去!!

(3)、RTC:在指定的時刻發送Intent,但不喚醒設備

(4)、RTC_WAKEUP:在指定的時刻發送Intent,同時喚醒設備



AlarmManager的方法:

(1)、void set(int type, long triggerAtTime, PendingIntent operation)
注冊一個鬧鐘

(2)、void setRepeating(int type, long triggerAtTime, long interval, PendingIntent operation)
注冊一個會重復的鬧鐘

(3)、void setInexactRepeating(int type, long triggerAtTime, long interval, PendingIntent operation)
注冊一個重復鬧鐘的不精確版本,它相對而言更節能(power-efficient)一些,因為系統可能會將幾個差不多的鬧鐘合並為一個來執行,減少設備的喚醒次數。
內置的幾個interval為:
INTERVAL_FIFTEEN_MINUTES
INTERVAL_HALF_HOUR
INTERVAL_HOUR
INTERVAL_HALF_DAY
INTERVAL_DAY
如果你將其設為DAY,那麼可能這一天中的所有鬧鐘都會被合並掉。

(4)、void cancel(PendingIntent operation)
取消一個注冊的鬧鐘

(5)、void setTimeZone(String timeZone)
設置系統的默認時區。需要android.permission.SET_TIME_ZONE權限



(5)、voidsetTime(long millis)

設置系統掛鐘時間,需要android.permission.SET_TIME權限


下面步入正題:

Intent和PendingIntent的關系 :

Intent是一個意圖,一個描述了想要啟動一個Activity、Broadcast或是Service的意圖。它主要持有的信息是它想要啟動的組件(Activity、Broadcast或是Service),在開發操作中,需要通過 startActivity , startService 或sendBroadcast 方法來啟動這個意圖執行某些操作!!

PendingIntent可以認為是對Intent的包裝,實際上就是,供當前App或之外的其他App調用,而常見的是供外部App使用,外部App執行這個 PendingIntent時,間接地調用裡面的Intent,即外部App延時執行PendingIntent中描述的Intent及其最終行為,PendingIntent主要持有的信息是它所包裝的Intent和當前App Context,即使當前App已經不存在了,也能通過存在於PendingIntent裡的 Context來執行Intent。當你把PendingIntent遞交給別的程序進行處理時,PendingIntent仍然擁有PendingIntent原程序所擁有的權限,當你從系統取得一個PendingIntent時,一定要非常小心才行,比如,通常,如果Intent目的地是你自己的component(Activity/Service/BroadcastReceiver)的話,你最好采用在Intent中顯示指定目的component名字的方式,以確保Intent最終能發到目的,否則Intent最後可能不知道發到哪裡了。

可以這樣理解:當你想在Aactivity中啟動另一個Bactivity,那麼你可以選擇兩種情況[立即啟動或延時啟動]:
1.通過intent配置需要啟動的Bactivity,然後調用startActivity()方法,讓他立即執行啟動操作,跳轉過去
2.另一種情況是,你雖然想啟動另一個Bactivity,可是你並不想馬上跳轉到Bactivity頁面,你想靜等5分鐘之後再跳轉到Bactivity,那麼你可以通過PendingIntent來實現[當然實現方式有很多啦,這裡僅是想說明PendingIntent與intent的區別],PendingIntent可以包裝第1步中的intent,然後通過AlarmManager這個定時器,定制5分鐘之後啟PendingIntent,實現這種延時操作,如果你還是聽著似懂非懂,一頭霧水,我表示很有壓力了,我該怎麼說你才能清楚呢,理論終究是抽象的,後見將會通過一個程序說明一下,程序中是啟動一個BroadcastReceiver,其實原理都是一樣的!!

如何獲得一個PendingIntent呢?其實很簡單:
1.你可以通過getActivity(Context context, int requestCode, Intent intent, int flags)系列方法從系統

取得一個用於啟動一個Activity的PendingIntent對象
2.可以通過getService(Context context, int requestCode, Intent intent, int flags)方法從系統取得一個

用於啟動一個Service的PendingIntent對象
3.可以通過getBroadcast(Context context, int requestCode, Intent intent, int flags)方法從系統取得一

個用於向BroadcastReceiver的發送廣播的PendingIntent對象

PendingIntent幾個常量:

1.FLAG_CANCEL_CURRENT :如果AlarmManager管理的PendingIntent已經存在,那麼將會取消當前的

PendingIntent,從而創建一個新的PendingIntent
2.FLAG_UPDATE_CURRENT:如果AlarmManager管理的PendingIntent已經存在,可以讓新的Intent更新之前

PendingIntent中的Intent對象數據,例如更新Intent中的Extras,另外,我們也可以在PendingIntent的原進程

中調用PendingIntent的cancel ()把其從系統中移除掉
3.FLAG_NO_CREATE :如果AlarmManager管理的PendingIntent已經存在,那麼將不進行任何操作,直接返回已經

存在的PendingIntent,如果PendingIntent不存在了,那麼返回null

代碼貼上:

1.MainActivity.java:

package com.test.Alarm;

import com.test.Alarm.R;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
private Button msetButton;
private Button mcancelButton;
private TextView mTextView;
private final int REQUEST_CODE_0 = 0;
private final int REQUEST_CODE_1 = 1;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) this.findViewById(R.id.mText);
msetButton = (Button) this.findViewById(R.id.setTimeButton);
mcancelButton = (Button) findViewById(R.id.cancelButton);

msetButton.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getApplicationContext(),
AlermReceiver.class);
intent.putExtra("flag", true);
// 創建2個PendingIntent
PendingIntent setPendIntent0 = PendingIntent.getBroadcast(
getApplicationContext(), REQUEST_CODE_0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Log.e("FLAG_UPDATE_CURRENT-->setPendIntent0:", setPendIntent0
+ "");

PendingIntent setPendIntent1 = PendingIntent.getBroadcast(
getApplicationContext(), REQUEST_CODE_1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Log.e("FLAG_UPDATE_CURRENT-->setPendIntent1:", setPendIntent1
+ "");

// 5秒後發送廣播,然後每隔10秒重復發廣播
int triggerAtTime = (int) (SystemClock.elapsedRealtime() + 5 * 1000);
int interval = 10 * 1000;

// 注冊以上創建的2個PendingIntent,每隔10秒重復發廣播
alarmMgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
triggerAtTime, interval, setPendIntent0);
alarmMgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
triggerAtTime, interval, setPendIntent1);

// alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
// triggerAtTime, pendIntent1);

}
});
mcancelButton.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getApplicationContext(),
AlermReceiver.class);
intent.putExtra("flag", false);
PendingIntent StopPendIntent0 = PendingIntent.getBroadcast(
getApplicationContext(), REQUEST_CODE_0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);

/**
* 如果你想更新putExtra中flag的值為false,那麼你必須通過alarmMgr的setxxx()方法再注冊一次,
* 相當於更新已經存在的intent,如果不這樣做,你就無法達到更新的目的,像這樣:
*
* alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 0,
* StopPendIntent0);
*
* 然後你再執行alarmMgr.cancel(StopPendIntent0);取消掉
*
* 這個可能就是你通過flag這個標志啟動了一個鬧鐘,並響鈴了,又想通過flag來關閉鬧鐘卻咋都不能關閉的原因,
* 問題可能就在這裡, 因為實際上你沒有更新數據
*/
// alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 0,
// StopPendIntent0);

Log.e("FLAG_UPDATE_CURRENT-->StopPendIntent0:", StopPendIntent0
+ "");
alarmMgr.cancel(StopPendIntent0);

// 以下僅是為了演示PendingIntent幾個常量的區別
PendingIntent StopPendIntent1 = PendingIntent.getBroadcast(
getApplicationContext(), REQUEST_CODE_1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Log.e("FLAG_UPDATE_CURRENT-->StopPendIntent1:", StopPendIntent1
+ "");
alarmMgr.cancel(StopPendIntent1);

PendingIntent StopPendIntent11 = PendingIntent.getBroadcast(
getApplicationContext(), REQUEST_CODE_1, intent,
PendingIntent.FLAG_NO_CREATE);
Log.e("FLAG_NO_CREATE------->StopPendIntent11:",
StopPendIntent11 + "");
alarmMgr.cancel(StopPendIntent11);

PendingIntent StopPendIntent12 = PendingIntent.getBroadcast(
getApplicationContext(), REQUEST_CODE_1, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
Log.e("FLAG_CANCEL_CURRENT-->StopPendIntent12:",
StopPendIntent12 + "");
alarmMgr.cancel(StopPendIntent12);

PendingIntent StopPendIntent13 = PendingIntent.getBroadcast(
getApplicationContext(), REQUEST_CODE_1, intent,
PendingIntent.FLAG_ONE_SHOT);
Log.e("FLAG_ONE_SHOT-------->StopPendIntent13:",
StopPendIntent13 + "");
alarmMgr.cancel(StopPendIntent13);
}
});
}
}

Copyright © Linux教程網 All Rights Reserved