PendingIntent源码分析
⼀、 重要api和参数
⾸先看下官⽅解释:
A description of an Intent and target action to perform with it. Instances of this class are created with getActivity(Context, int, Intent, int), getActivities(Context, int, Intent[], int), getBroadcast(Context, int, Intent, int), and getService(Context, int, Intent, int); the returned object can be handed to other applications so that they can perform the action you described on your behalf at a later time.
简单来说PendingIntent就是⼀个Intent的封装,我们可以把这个封装好的intent交给别的程序,别的程序根据这个intent延后处理intent中所描述的事情。
重要的⽅法有三个:
getActivity(Context context, int requestCode, Intent intent, int flags, Bundle options)
getBroadcast(Context context, int requestCode, Intent intent, int flags)
getService(Context context, int requestCode, Intent intent, int flags)
重要的参数:
FLAG_CANCEL_CURRENT:清除之前的,重新创建⼀个新的
FLAG_NO_CREATE:如果pendingintent不存在则不创建直接返回null
FLAG_ONE_SHOT:⼀次性的.
FLAG_UPDATE_CURRENT:如果已经存在,则复⽤这个pendingIntent实例,只更新intent相关的extra data
之前DeviceManager和LCTS中存在alarm个数过多的问题,就是这⾥参数不正确造成的。
⼆、⽐较两个PendingIntent实例是否相等的流程
两个PendingIntent对等是指它们的intentSender⼀样, 且其它们的Intent的action, data, categories, components和flags都⼀样。但是它们的Intent的Extra可以不⼀样。
具体分析如下:
@PendingIntent.java
@Override
public boolean equals(Object otherObj) {
if (otherObj instanceof PendingIntent) {
return mTarget.asBinder().equals(((PendingIntent)otherObj).mTarget.asBinder());
梦想的梦
}
return fal;
}
这⾥复写了equals⽅法,⽐较的是mTarget,⽽这个对象是⼀个IIntentSender的对象。
public static PendingIntent getActivity(Context context, int requestCode,
青椒怎么做好吃Intent intent, int flags, Bundle options) {
String packageName = PackageName();
String resolvedType = intent != null ? solveTypeIfNeeded(
try {
intent.migrateExtraStreamToClipData();
ntent.prepareToLeaveProcess();
IIntentSender target =Default().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, options, UrId());
return target != null ? new PendingIntent(target) : null;
构造⽅法:
PendingIntent(IIntentSender target) {
mTarget = target;
}
上⾯提到的mTarget是在这⾥创建的,通过AMS查询到⼀个intentnder的实例,然后通过PendingIntent的构造⽅法 传⼊。
@ActivityManagerService.java
IIntentSender getIntentSenderLocked (int type, String packageName,int callingUid, int urId, IBinder token, String resultWho,int requestCode, Intent[] intents, String[] resolvedTypes, int flags,Bundle options) {
...
final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
|PendingIntent.FLAG_UPDATE_CURRENT);
//根据参数⽣成key
PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, activity, resultWho,
requestCode, intents, resolvedTypes, flags, options, urId);
WeakReference<PendingIntentRecord> ref;
//从已有的IntentSendRecoder中查找是否有key⼀样的
ref = (key);
PendingIntentRecord rec = ref != null ? () : null;
//如果找到key⼀样的
if (rec != null) {
if (!cancelCurrent) { //参数不是FLAG_CANCEL_CURRENT
出入登记
if (updateCurrent) { //参数是FLAG_UPDATE_CURRENT
if (questIntent != null) { //替换intents中最后⼀个intent的extra
placeExtras(intents != null ?
intents[intents.length - 1] : null);
}
if (intents != null) {
intents[intents.length-1] = questIntent;
rec.key.allIntents = intents;
rec.key.allResolvedTypes = resolvedTypes;
} el {
rec.key.allIntents = null;
rec.key.allResolvedTypes = null;
}
}
return rec;
}
笔记本电脑的功率
rec.canceled = true;意犹未尽
}
if (noCreate) {
return rec;
}
三、pendingIntent的发送和接收流程
使⽤到PendingIntent的主要场景都是和android中特定的的远程服务打交道(如:短信、通知、闹铃等)。
下⾯以Alarm为例,介绍⼀下整个发送和接收流程。
从上⾯的介绍知道,通过getActivity,getService,getBroadcast⽅法能够获得⼀个PendingIntent的实例。
【例⼦】
PendingIntent nder = Broadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmMgr = (AlarmManager) SystemService(Context.ALARM_SERVICE); alarmMgr.cancel(nder);
alarmMgr.t(AlarmManager.RTC, System.currentTimeMillis() + period,nder);
@AlarmManagerService.java中t()⽅法最后调到了tImplLocked()
private void tImplLocked (int type, long when, long whenElapd, long windowLength,
long maxWhen, long interval, PendingIntent operation, boolean isStandalone,
boolean doValidate, WorkSource workSource) {
Alarm a = new Alarm(type, when, whenElapd, windowLength, maxWhen, interval,operation, workSource); removeLocked(operation);
int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapd, maxWhen);
if (whichBatch < 0) {//mAlarmBatches没找到匹配的batch
Batch batch = new Batch(a);
batch.standalone = isStandalone;
addBatchLocked(mAlarmBatches, batch);
谢霆锋生日
} el {
Batch batch = (whichBatch);
if (batch.add(a)) {
// The start time of this batch advanced, so batch ordering may
// have just been broken. Move it to where it now belongs.
addBatchLocked(mAlarmBatches, batch);
}
rescheduleKernelAlarmsLocked();
}
这⾥最重要的就是新建/获取⼀个Batch 对象,加⼊到mAlarmBatches这个list中,然后调⽤ rescheduleKernelAlarmsLocked⽅法
private void rescheduleKernelAlarmsLocked () {
// Schedule the next upcoming wakeup alarm. If there is a deliverable batch
// prior to that which contains no wakeups, we schedule that as well.
if (mAlarmBatches.size() > 0) {
final Batch firstWakeup = findFirstWakeupBatchLocked();
final Batch firstBatch = (0);
if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
mNextWakeup = firstWakeup.start;
tLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
}
if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) { mNextNonWakeup = firstBatch.start;
tLocked(ELAPSED_REALTIME, firstBatch.start);
}
}
}厨房的英文
找出第⼀个唤醒型的alarm和第⼀个⾮唤醒型的alarm,⼀并处理
private void tLocked (int type, long when){
...
Message msg = Message.obtain();
msg.what = ALARM_EVENT;
mHandler.ndMessageAtTime(msg, when);
}
这⾥就简单的发送⼀个message。
private class AlarmHandler extends Handler {
public static final int ALARM_EVENT = 1;
public static final int MINUTE_CHANGE_EVENT = 2;
public static final int DATE_CHANGE_EVENT = 3;
public AlarmHandler() {
}
public void handleMessage (Message msg) {
if (msg.what == ALARM_EVENT ) {
ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
synchronized (mLock) {
final long nowRTC = System.currentTimeMillis();
final long nowELAPSED = SystemClock.elapdRealtime();
triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
}
// now trigger the alarms without the lock held
for (int i=0; i<triggerList.size(); i++) {
Alarm alarm = (i);
try {
alarm.operation.nd();
} catch (PendingIntent.CanceledException e) {
if (peatInterval > 0) {
// This IntentSender is no longer valid, but this
// is a repeating alarm, so toss the hor.
remove(alarm.operation);
}
}
}
}
}
}
private void triggerAlarmsLocked (ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
while (mAlarmBatches.size() > 0) {
Batch batch = (0);
if (batch.start > nowELAPSED) {
//遍历mAlarmBatches,直到所有的到期的batch都被处理完毕
break;
}
final int N = batch.size();
for (int i = 0; i < N; i++) {
Alarm alarm = (i);
triggerList.add(alarm);
if (peatInterval > 0) {
pe, alarm.when + delta, nextElapd, alarm.windowLength,
maxTriggerTime(nowELAPSED, nextElapd, peatInterval),
alarm.workSource);
}
}
}
这⾥最重要的事情就是将触发的alarm加⼊到triggerList,如果有repeat的,继续调⼀次tImplLocked,重新⾛⼀遍流程。
回到handlemessage⽅法中,triggerAlarmsLocked调⽤结束后,所有被触发的alarm都存在triggerList⾥,然后遍历这个list去调⽤alarm.operation.nd();
这⾥的operation就是⼀个PendingIntent。
@PendingIntent.java
public void nd () throws CanceledException {
nd(null, 0, null, null, null, null);
}
public void nd (Context context, int code, Intent intent,OnFinished onFinished, Handler handler, String requiredPermission) throws CanceledException {
企业商业模式
try {
String resolvedType = intent != null ?
int res = mTarget.nd (code, intent, resolvedType,
onFinished != null? new FinishedDispatcher(this, onFinished, handler): null,
requiredPermission);
if (res < 0) {