Android 結合AlarmManager淺談Intent和PendingIntent

來源:互聯網
上載者:User

首先簡單說一下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. */@Overridepublic 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() {@Overridepublic void onClick(View v) {AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);Intent intent = new Intent(getApplicationContext(),AlermReceiver.class);intent.putExtra("flag", true);// 建立2個PendingIntentPendingIntent 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() {@Overridepublic 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);}});}}

2.廣播監聽:

package com.test.Alarm;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.util.Log;import android.widget.Toast;public class AlermReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Bundle bundle = intent.getExtras();Toast.makeText(context, "進入鬧鐘BroadcastReceiver", 100).show();if (bundle != null) {Log.i("AlermReceiver:", String.valueOf(bundle.getBoolean("flag")));if (bundle.getBoolean("flag")) {// 開啟鬧鐘操作Toast.makeText(context, "開啟", 100).show();} else {// 關閉鬧鐘操作Toast.makeText(context, "關閉", 100).show();}}}}

3.首頁面activity_main.xml:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <TextView        android:id="@+id/mText"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="@string/hello" />    <Button        android:id="@+id/setTimeButton"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/setTimeButton" />    <Button        android:id="@+id/cancelButton"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/cancelButton" /></LinearLayout>

 

最後別忘了再AndroidManifest.xml中註冊廣播

 <receiver android:name="com.test.Alarm.AlermReceiver"/>

 

運行一下:

 

通過列印日誌,就可以看出PendingIntent幾個常量的大致區別啦!!

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.