1、基本概念
intent英文意思是意圖,pending表示即將發生或來臨的事情。
PendingIntent這個類用於處理即將發生的事情。比如在通知Notification中用於跳轉頁面,但不是馬上跳轉。
Intent 是及時啟動,intent 隨所在的activity 消失而消失。
PendingIntent 可以看作是對intent的封裝,通常通過getActivity,getBroadcast ,getService來得到pendingintent的執行個體,當前activity並不能馬上啟動它所包含的intent,而是在外部執行 pendingintent時,調用intent的。正由於pendingintent中 儲存有當前App的Context,使它賦予外部App一種能力,使得外部App可以如同當前App一樣的執行pendingintent裡的 Intent, 就算在執行時當前App已經不存在了,也能通過存在pendingintent裡的Context照樣執行Intent。另外還可以處理intent執行後的操作。常和alermanger
和notificationmanager一起使用。
Intent一般是用作Activity、Sercvice、BroadcastReceiver之間傳遞資料,而Pendingintent,一般用在 Notification上,可以理解為順延強制的intent,PendingIntent是對Intent一個封裝。
2、例子
2.1 通知的例子
private void showNotify(){ Notification notice=new Notification(); notice.icon=R.drawable.icon; notice.tickerText="您有一條新的資訊"; notice.defaults=Notification.DEFAULT_SOUND; notice.when=10L; // 100 毫秒延遲後,震動 250 毫秒,暫停 100 毫秒後,再震動 500 毫秒 //notice.vibrate = new long[] { 100, 250, 100, 500 };出錯? //notice.setLatestEventInfo(this, "通知", "開會啦", PendingIntent.getActivity(this, 0, null, 0));notice.setLatestEventInfo(this, "通知", "開會啦", PendingIntent.getActivity(this, 0, new Intent(this,Activity2.class), 0));//即將跳轉頁面,還沒跳轉 NotificationManager manager=(NotificationManager)getSystemService(this.NOTIFICATION_SERVICE); manager.notify(0,notice); }
2.1 簡訊發送的例子
String msg ="你好,美女";String number = "135****6784";SmsManager sms = SmsManager.getDefault();PendingIntent pi = PendingIntent.getBroadcast(SmsActivity.this,0,new Intent(...),0);sms.sendTextMessage(number, null, msg, pi, null);Toast.makeText(SmsActivity.this,"發送成功",Toast.LENGHT_LONG).show();
PendingIntent就是一個Intent的描述,我們可以把這個描述交給別的程式,別的程式根據這個描述在後面的別的時間做你安排做的事情 (By giving a PendingIntent to another application, you are granting it the right to perform the operation you have specified as if the other application was yourself,就相當於PendingIntent代表了Intent)。本例中別的程式就是傳送簡訊的程式,簡訊發送成功後要把intent廣播出去
。
函數SmsManager.sendTextMessage(String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)中參數解釋:
1)PendingIntent sentIntent:當簡訊發出時,成功的話sendIntent會把其內部的描述的intent廣播出去,否則產生錯誤碼並通過android.app.PendingIntent.OnFinished進行回調,這個參數最好不為空白,否則會存在資源浪費的潛在問題;
2)PendingIntent deliveryIntent:是當訊息已經傳遞給收信人後所進行的PendingIntent廣播。
查看PendingIntent 類可以看到許多的Send函數,就是PendingIntent在進行被賦予的相關的操作。
3、PendingIntent的執行過程
以alarm service為例:
1. activity請求一個alarm一般這樣來做:
# //建立一個PendingIntent
# Intent intent = new Intent(ALARM_ALERT_ACTION);
# intent.putExtra(ID, id);
# intent.putExtra(TIME, atTimeInMillis);
# PendingIntent sender = PendingIntent.getBroadcast(
# context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
# //獲得AlarmMnager並註冊一個新鬧鈴,
# //一次性鬧鈴的設定
#
# AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
# am.set(AlarmManager.POWER_OFF_WAKEUP, atTimeInMillis, sender);
2. AlarmManager.set調用AlarmManagerService.set
3. AlarmManagerService.set的核心代碼如下:
我們可以看到它就是把PendingIntent儲存起來而已
4. alarm manager service會定時查看是否有alarm到期了,如果到期了做相應處理。
5. AlarmThread會調用
alarm.operation.send(mContext, 0,
mBackgroundIntent.putExtra(
Intent.EXTRA_ALARM_COUNT, alarm.count),
mResultReceiver, mHandler);
也就是通過PendingIntent.send執行intent操作,alarm這個就會發送ALARM_ALERT_ACTION的broadcast。
補充說明:
1. PendingIntent重要特點是非同步處理。
2. 另外有一個要說明的是PendingIntent.onFinished,它可以作為PendingIntent.send的一個參數,
我們知道PendingIntent.send一般是在service中執行,這個調用的send後,回調onFished類的onSendFinished,所以onSendFinished一般也是在service中執行的
4、深入分析
public final class PendingIntent extends Object implements Parcelable
PendingIntent用於描述Intent及其最終的行為.
- 你可以通過getActivity(Context context, int requestCode, Intent intent, int flags)系列方法從系統取得一個用於啟動一個Activity的PendingIntent對象,
- 可以通過getService(Context context, int requestCode, Intent intent, int flags)方法從系統取得一個用於啟動一個Service的PendingIntent對象
- 可以通過getBroadcast(Context context, int requestCode, Intent intent, int flags)方法從系統取得一個用於向BroadcastReceiver的Intent廣播的PendingIntent對象
返回的PendingIntent可以遞交給別的應用程式,然後繼續處理。這裡的話你可以稍後才處理PendingIntent中描述的Intent及其最終行為。
當你把PendingIntent遞交給別的程式進行處理時,PendingIntent仍然擁有PendingIntent原程式所擁有的許可權(with the same permissions and identity).當你從系統取得一個PendingIntent時,一定要非常小心才行。比如,通常,如果Intent目的地是你自己的component(Activity/Service/BroadcastReceiver)的話,你最好採用在Intent中顯示指定目的component名字的方式,以確保Intent最終能發到目的,否則Intent最後可能不知道發到哪裡了。一個PendingIntent就是Android系統中的一個token(節點,這個應該是Linux或C\C++用語)的一個對象引用,它描述了一些將用於retrieve的資料(這裡,這些資料描述了Intent及其最終的行為)。
這就意味著即使PendingIntent原進程結束了的話, PendingIntent本身仍然還存在,可在其他進程(PendingIntent被遞交到的其他程式)中繼續使用.如果我在從系統中提取一個PendingIntent的,而系統中有一個和你描述的PendingIntent對等的PendingInent, 那麼系統會直接返回和該PendingIntent其實是同一token的PendingIntent,而不是一個新的token和PendingIntent。然而你在從提取PendingIntent時,通過FLAG_CANCEL_CURRENT參數,讓這個老PendingIntent的先cancel()掉,這樣得到的pendingInten和其token的就是新的了。
通過FLAG_UPDATE_CURRENT參數的話,可以讓新的Intent會更新之前PendingIntent中的Intent對象資料,例如更新Intent中的Extras。另外,我們也可以在PendingIntent的原進程中調用PendingIntent的cancel ()把其從系統中移除掉。
注意:兩個PendingIntent對等是指它們的operation一樣, 且其它們的Intent的action, data, categories, components和flags都一樣。但是它們的Intent的Extra可以不一樣。
4.1 主要常量
- FLAG_CANCEL_CURRENT:如果當前系統中已經存在一個相同的PendingIntent對象,那麼就將先將已有的PendingIntent取消,然後重建一個PendingIntent對象。
- FLAG_NO_CREATE:如果當前系統中不存在相同的PendingIntent對象,系統將不會建立該PendingIntent對象而是直接返回null。
- FLAG_ONE_SHOT:該PendingIntent只作用一次。在該PendingIntent對象通過send()方法觸發過後,PendingIntent將自動調用cancel()進行銷毀,那麼如果你再調用send()方法的話,系統將會返回一個SendIntentException。
- FLAG_UPDATE_CURRENT:如果系統中有一個和你描述的PendingIntent對等的PendingInent,那麼系統將使用該PendingIntent對象,但是會使用新的Intent來更新之前PendingIntent中的Intent對象資料,例如更新Intent中的Extras。
4.2 主要成員函數
該系列方法將從系統取得一個用於啟動一個Activity的PendingIntent對象。
public static PendingIntent getActivity (Context context, int requestCode, Intent intent, int flags)
Since: API Level 1
Retrieve a PendingIntent that will start a new activity, like calling Context.startActivity(Intent). Note that the activity will be started outside of the context of an existing activity, so you must use the Intent.FLAG_ACTIVITY_NEW_TASK launch flag in the
Intent.
因為對於Context的startActivity方法,如果不是在其子類(Activity)中調用,那麼必須對Intent加上FLAG_ACTIVITY_NEW_TASK。
具體可以參照Context中對startActivity方法的說明或《Activity和Task的基本模型》
Parameters
context
The Context in which this PendingIntent should start the activity.
requestCode
Private request code for the sender (currently not used).
intent
Intent of the activity to be launched.
flags May be FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT, or any of the flags as supported byIntent.fillIn() to control which unspecified parts of the intent
that can be supplied when the actual send happens.
當我們使用Intent.fillIn()方法時,表示其Intent的某個資料項目可以被send方法的Inent參數進行覆蓋重寫。
Returns
Returns an existing or new PendingIntent matching the given parameters. May return null only if FLAG_NO_CREATE has been supplied.
public static PendingIntent getActivities (Context context, int requestCode, Intent[] intents, int flags)
Since: API Level 11
Like getActivity(Context, int, Intent, int), but allows an array of Intents to be supplied. The first Intent in the array is taken as the primary key for the PendingIntent, like the single Intent given to getActivity(Context, int, Intent, int). Upon sending
the resulting PendingIntent, all of the Intents are started in the same way as they would be by passing them to startActivities(Intent[]).
The first intent in the array will be started outside of the context of an existing activity, so you must use the Intent.FLAG_ACTIVITY_NEW_TASK launch flag in the Intent. (Activities after the first in the array are started in the context of the previous activity
in the array, so FLAG_ACTIVITY_NEW_TASK is not needed nor desired for them.)
The last intent in the array represents the key for the PendingIntent. In other words, it is the significant element for matching (as done with the single intent given togetActivity(Context, int, Intent, int), its content will be the subject of replacement
by send(Context, int, Intent) andFLAG_UPDATE_CURRENT, etc. This is because it is the most specific of the supplied intents, and the UI the user actually sees when the intents are started.
Parameters
context
The Context in which this PendingIntent should start the activity.
requestCode
Private request code for the sender (currently not used).
intents
Array of Intents of the activities to be launched.
flags May be FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT, or any of the flags as supported byIntent.fillIn() to control which unspecified parts of the intent
that can be supplied when the actual send happens.
當我們使用Inent.fillIn()所支援的flags時,表示其Intent的資料項目可以被send方法的Intent參數覆蓋重寫。
Returns
Returns an existing or new PendingIntent matching the given parameters. May return null only if FLAG_NO_CREATE has been supplied.
該方法將系統取得一個用於啟動一個Service的PendingIntent對象.
public static PendingIntent getService (Context context, int requestCode, Intent intent, int flags)
Since: API Level 1
Retrieve a PendingIntent that will start a service, like calling Context.startService(). The start arguments given to the service will come from the extras of the Intent.
Parameters
context
The Context in which this PendingIntent should start the service.
requestCode
Private request code for the sender (currently not used).
intent
An Intent describing the service to be started.
flags May be FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT, or any of the flags as supported byIntent.fillIn() to control which unspecified parts of the intent
that can be supplied when the actual send happens.
當我們使用Intent.fillIn()方法的flags時,它表示其Intent的資料項目可以被send方法的Intent參數覆蓋重寫。
Returns
Returns an existing or new PendingIntent matching the given parameters. May return null only if FLAG_NO_CREATE has been supplied.
該方法將從系統取得一個用於向BroadcastReceiver的Intent廣播的PendingIntent對象
public static PendingIntent getBroadcast (Context context, int requestCode, Intent intent, int flags)
Since: API Level 1
Retrieve a PendingIntent that will perform a broadcast, like calling Context.sendBroadcast().
Parameters
context
The Context in which this PendingIntent should perform the broadcast.
requestCode
Private request code for the sender (currently not used).
intent
The Intent to be broadcast.
flags May be FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT, or any of the flags as supported byIntent.fillIn() to control which unspecified parts of the intent
that can be supplied when the actual send happens.
當我們使用Intent.fillIn()方法的flags時,它表示其Intent的資料項目可以被send方法的Intent參數覆蓋重寫。
Returns
Returns an existing or new PendingIntent matching the given parameters. May return null only if FLAG_NO_CREATE has been supplied.
該系列主要用於觸發PendingIntent的Intent行為。用其Intent或啟動一個Activity,或啟動一個Service,或向BroadcastReceiver發送Intent廣播。
public void send ()
Since: API Level 1
Perform the operation associated with this PendingIntent.
Throws
PendingIntent.CanceledException Throws CanceledException if the PendingIntent is no longer allowing more intents to be sent through it.
public void send (Context context, int code, Intent intent)
Since: API Level 1
Perform the operation associated with this PendingIntent, allowing the caller to specify information about the Intent to use.
Parameters
context
The Context of the caller.
該參數是因為intent參數才需要提供的,所用如果你的intent參數不為null的話,該參數也不能為null.
code Result code to supply back to the PendingIntent's target.
intent Additional Intent data. See Intent.fillIn() for information on how this is applied to the original Intent.
Throws
PendingIntent.CanceledException Throws CanceledException if the PendingIntent is no longer allowing more intents to be sent through it.
public void send (int code, PendingIntent.OnFinished onFinished, Handler handler)
Since: API Level 1
Perform the operation associated with this PendingIntent, allowing the caller to be notified when the send has completed.
Parameters
code Result code to supply back to the PendingIntent's target.
onFinished The object to call back on when the send has completed, or null for no callback.
通過該參數,我們可以設定在Intent發送成功後的回呼函數。
handler Handler identifying the thread on which the callback should happen. If null, the callback will happen from the thread pool of the process.
用於說明onFinished參數指定的回呼函數,最終在哪個Handler中進行調用。
Throws
PendingIntent.CanceledException Throws CanceledException if the PendingIntent is no longer allowing more intents to be sent through it.
public void send (Context context, int code, Intent intent, PendingIntent.OnFinished onFinished, Handler handler)
Since: API Level 1
Perform the operation associated with this PendingIntent, allowing the caller to specify information about the Intent to use and be notified when the send has completed.
For the intent parameter, a PendingIntent often has restrictions on which fields can be supplied here, based on how the PendingIntent was retrieved ingetActivity(Context, int, Intent, int), getBroadcast(Context, int, Intent, int), or getService(Context, int,
Intent, int).
Parameters
context The Context of the caller. This may be null if intent is also null.
該參數是因為intent參數才需要提供的,一般是當前的context,如果你的intent參數不為null的話,該函數也不能為null.
code Result code to supply back to the PendingIntent's target.
intent Additional Intent data. See Intent.fillIn() for information on how this is applied to the original Intent. Use null to not modify the original Intent.
onFinished The object to call back on when the send has completed, or null for no callback.
通過該參數,我們可以指定Intent發送成功後的回呼函數。
handler Handler identifying the thread on which the callback should happen. If null, the callback will happen from the thread pool of the process.
該參數說明onFinished參數指定的回呼函數將在哪個Handler中進行調用。
Throws
PendingIntent.CanceledException Throws CanceledException if the PendingIntent is no longer allowing more intents to be sent through it.
public void cancel ()
Since: API Level 1
Cancel a currently active PendingIntent. Only the original application owning an PendingIntent can cancel it.
只有PengdingIntent的原應用程式才能調用cancel()來把它從系統中移除掉。
getTargetPackage()函數
public String getTargetPackage ()
Since: API Level 1
Return the package name of the application that created this PendingIntent, that is the identity under which you will actually be sending the Intent. The returned string is supplied by the system, so that an application can not spoof its package.
Returns
The package name of the PendingIntent, or null if there is none associated with it.
參考資料:
《Intent和PendingIntent的區別》
《Android PendingIntent的深入理解》
《PendingIntent詳解》