歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android 結合AlarmManager淺談Intent和PendingIntent

首先簡單說一下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