关于Notification的一点愚见(PendingIntent工作流程)

来源:互联网 发布:搞笑的网络短剧2016 编辑:程序博客网 时间:2024/06/05 16:59

PendingIntent,顾名思义,延迟的Intent。那么肯定会产生一个疑问,那就是PendingIntent究竟和Intent的区别在哪里呢?
其实PendingIntent其实就是对Intent的一个封装,不过Intent是立即触发效果,就像我们常用的这样:

        Intent intent = new Intent(MainActivity.this,DemoActivity1.class);        startActivity(intent);

而PendingIntent触发的时间点不太一样,一般是触发效果的地点不在函数中,而是在其他方法处被调用,所以看起来就像被延迟了一样。

PendingIntent的声明

我们可以知道PendingIntent可以支持三种意图:启动Activity,启动Service,启动Broadcast。我们取出其中一个场景来讨论,其他两个场景是类似的。
上一章中,有如下这段:

PendingIntent pendingIntent = PendingIntent.getActivity(this,                    0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

这一段就是PendingIntent的声明,调用PendingIntent中的getActivity()的方法返回实例。
下面是getActivity的源码:

    public static PendingIntent getActivity(Context context, int requestCode,            Intent intent, @Flags int flags) {        return getActivity(context, requestCode, intent, flags, null);    }

这里又调用了:

public static PendingIntent getActivity(Context context, int requestCode,            @NonNull Intent intent, @Flags int flags, @Nullable Bundle options) {        String packageName = context.getPackageName();        String resolvedType = intent != null ? intent.resolveTypeIfNeeded(                context.getContentResolver()) : null;        try {            intent.migrateExtraStreamToClipData();            intent.prepareToLeaveProcess();            IIntentSender target =                ActivityManagerNative.getDefault().getIntentSender(                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,                    null, null, requestCode, new Intent[] { intent },                    resolvedType != null ? new String[] { resolvedType } : null,                    flags, options, UserHandle.myUserId());            return target != null ? new PendingIntent(target) : null;        } catch (RemoteException e) {        }        return null;    }

其中核心代码:

IIntentSender target =                ActivityManagerNative.getDefault().getIntentSender(                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,                    null, null, requestCode, new Intent[] { intent },                    resolvedType != null ? new String[] { resolvedType } : null,                    flags, options, UserHandle.myUserId());            return target != null ? new PendingIntent(target) : null;

而这里ActivityManagerNative.getDefault()是指的是AMS(ActivityManagerService)这个类,这个类可以说是贯穿了Android整个应用层的结构。它在Android系统中,四大组件的行为和它密切相关。
而AMS是属于原进程之外,那么我们就必须完成进程间通讯的动作。而同时Activity是继承了Binder实现了IActivityManager的接口。之前的讲述Binder的时候也说过了,在Android的进程间通讯,Binder起到了至关重要的作用。

于此同时,也要说明一下IIntentSender这个类其实是继承了IInterface抽象类的接口。

 public interface IIntentSender extends android.os.IInterface

AMS中PendingIntent的工作

我们下去AMS的getIntentSender()看看这个函数的究竟。

  @Override    public IIntentSender getIntentSender(int type,            String packageName, IBinder token, String resultWho,            int requestCode, Intent[] intents, String[] resolvedTypes,            int flags, Bundle options, int userId) {....//获取Intent对象,存入数组并且对非法的intent做出处理        synchronized(this) {            int callingUid = Binder.getCallingUid();            int origUserId = userId;            userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,                    type == ActivityManager.INTENT_SENDER_BROADCAST,                    ALLOW_NON_FULL, "getIntentSender", null);            if (origUserId == UserHandle.USER_CURRENT) {                // We don't want to evaluate this until the pending intent is                // actually executed.  However, we do want to always do the                // security checking for it above.                userId = UserHandle.USER_CURRENT;            }            try {                if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {                    int uid = AppGlobals.getPackageManager()                            .getPackageUid(packageName, UserHandle.getUserId(callingUid));                    if (!UserHandle.isSameApp(callingUid, uid)) {                        String msg = "Permission Denial: getIntentSender() from pid="                            + Binder.getCallingPid()                            + ", uid=" + Binder.getCallingUid()                            + ", (need uid=" + uid + ")"                            + " is not allowed to send as package " + packageName;                        Slog.w(TAG, msg);                        throw new SecurityException(msg);                    }                }                return getIntentSenderLocked(type, packageName, callingUid, userId,                        token, resultWho, requestCode, intents, resolvedTypes, flags, options);            } catch (RemoteException e) {                throw new SecurityException(e);            }        }    }

我们主要看这一段线程同步的代码,最后你会发现获取完uid之类的信息之后就会回调函数getIntentSenderLocked(type, packageName, callingUid, userId,
token, resultWho, requestCode, intents, resolvedTypes, flags, options);这个才是真正处理问题的函数。

IIntentSender getIntentSenderLocked(int type, String packageName,            int callingUid, int userId, IBinder token, String resultWho,            int requestCode, Intent[] intents, String[] resolvedTypes, int flags,            Bundle options) {        if (DEBUG_MU)            Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid);        ActivityRecord activity = null;        if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {            activity = ActivityRecord.isInStackLocked(token);            if (activity == null) {                return null;            }            if (activity.finishing) {                return null;            }        }        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);        PendingIntentRecord.Key key = new PendingIntentRecord.Key(                type, packageName, activity, resultWho,                requestCode, intents, resolvedTypes, flags, options, userId);        WeakReference<PendingIntentRecord> ref;        ref = mIntentSenderRecords.get(key);        PendingIntentRecord rec = ref != null ? ref.get() : null;        if (rec != null) {            if (!cancelCurrent) {                if (updateCurrent) {                    if (rec.key.requestIntent != null) {                        rec.key.requestIntent.replaceExtras(intents != null ?                                intents[intents.length - 1] : null);                    }                    if (intents != null) {                        intents[intents.length-1] = rec.key.requestIntent;                        rec.key.allIntents = intents;                        rec.key.allResolvedTypes = resolvedTypes;                    } else {                        rec.key.allIntents = null;                        rec.key.allResolvedTypes = null;                    }                }                return rec;            }            rec.canceled = true;            mIntentSenderRecords.remove(key);        }        if (noCreate) {            return rec;        }        rec = new PendingIntentRecord(this, key, callingUid);        mIntentSenderRecords.put(key, rec.ref);        if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {            if (activity.pendingResults == null) {                activity.pendingResults                        = new HashSet<WeakReference<PendingIntentRecord>>();            }            activity.pendingResults.add(rec.ref);        }        return rec;    }

这一段做的工作有一下几点:
1.假若flags是type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT。则说明是从Activity应答的PendingIntent,我们不做讨论。

2.假如PendingIntentRecord不为空,根据PendingIntent的标志位,Intent数组的做出调整来达到PendingIntent的效果。
这里先说一下PendingIntent,有四个标志位:

1)FLAG_ONE_SHOT :当前描述的PendingIntent只能被使用一次,然后它就会调用cancel删除。如果还有后续相同的PendingIntent,那么他们的send方法将会调用失败。
对于通知栏而言,采用此标志位,同类通知只能使用一次,后续点击通知会无效。

2)FLAG_NO_CREATE:当前描述的PendingIntent不会主动创建,如果当前PendingIntent之前不存在,则所有的getActivity,getService,getBroadcast返回null,获取PendingIntent失败。这个很少用,暂时不讨论。

3)FLAG_CANCEL_CURRENT:当前描述的PendingIntent已经存在了,那么他们会被cancel,然后系统创建一个新的PendingIntent。对于通知栏而言,被cancel后的消息单击无效。

4)FLAG_UPDATE_CURRENT:如果当前的PendingIntent已经存在,则它们都会被更新,即里面的PendingIntent都换为最新。

3.假如PendingIntentRecord为空则创建一个新的PendingIntentRecord。并且存入Activity中PendingIntentRecord的HashSet中。最后返回PendingIntentRecord。

这个时候,我们发现返回了PendingIntentRecord,说明这个类正是实现了IIntentSender。让我们看看这个类是怎么回事吧。

final class PendingIntentRecord extends IIntentSender.Stub

看到了吧,这个类正是实现了IIntentSender.Stub的类。

final class PendingIntentRecord extends IIntentSender.Stub

是不是觉得和眼熟呢?没错就是我们之前分析的AIDL,在这个过程AMS相当于中转器,就像设计模式中的中介者一样。将函数转移到远程端的实现。这种思想在探索四大组件的时候经常会用到。

PendingIntentRecord中工作

在这个类中完成的事情只有一件,那就是将数据存储进来。

PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) {        owner = _owner;        key = _k;        uid = _u;        ref = new WeakReference<PendingIntentRecord>(this);    }//内部类key的定义     Key(int _t, String _p, ActivityRecord _a, String _w,                int _r, Intent[] _i, String[] _it, int _f, Bundle _o, int _userId) {            type = _t;            packageName = _p;            activity = _a;            who = _w;            requestCode = _r;            requestIntent = _i != null ? _i[_i.length-1] : null;            requestResolvedType = _it != null ? _it[_it.length-1] : null;            allIntents = _i;            allResolvedTypes = _it;            flags = _f;            options = _o;            userId = _userId;            int hash = 23;            hash = (ODD_PRIME_NUMBER*hash) + _f;            hash = (ODD_PRIME_NUMBER*hash) + _r;            hash = (ODD_PRIME_NUMBER*hash) + _userId;            if (_w != null) {                hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode();            }            if (_a != null) {                hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode();            }            if (requestIntent != null) {                hash = (ODD_PRIME_NUMBER*hash) + requestIntent.filterHashCode();            }            if (requestResolvedType != null) {                hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode();            }            hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode();            hash = (ODD_PRIME_NUMBER*hash) + _t;            hashCode = hash;            //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x"            //        + Integer.toHexString(hashCode));        }

在这一段代码中,很好的解释了为什么我们在声明PendingIntent的时候,请求码一般为0,在上面hashcode的数值和请求码requestCode进行相加的运算获得新的请求码。假如请求码变动了,hashcode也变动了,那么在AMS中建立的HashSet的检索策略不同了就会造成寻找到的Intent不同,对错误的Intent处理了错误标志位。

到这里,PendingIntent已经存储,完毕正在等待用户的调度。

NotificationManager的调用

我们这里分析Notification中PendingIntent的情况,其实在AppWidget中调用PendingIntent的情景也是十分类似。

我们在制作通知的时候,最后会声明一个NotificationManager的notify去唤醒PendingIntent并且执行。

让我们去NotificationManager中看看,notify方法吧。
我们可以知道, public void notify(int id, Notification notification)又会调用 public void notify(String tag, int id, Notification notification)

 public void notify(String tag, int id, Notification notification)    {        int[] idOut = new int[1];        INotificationManager service = getService();        String pkg = mContext.getPackageName();        if (notification.sound != null) {            notification.sound = notification.sound.getCanonicalUri();            if (StrictMode.vmFileUriExposureEnabled()) {                notification.sound.checkFileUriExposed("Notification.sound");            }        }        if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");        Notification stripped = notification.clone();        Builder.stripForDelivery(stripped);        try {            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,                    stripped, idOut, UserHandle.myUserId());            if (id != idOut[0]) {                Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);            }        } catch (RemoteException e) {        }    }

在这一段中,我们只用注意这个函数service.enqueueNotificationWithTag(pkg, mContext.getOpPack-ageName(), tag, id,stripped, idOut, UserHandle.myUserId());
这个函数也是进程间的通讯,透过INotificationManager这个AIDL实现的类,远程调用NotificationManagerService中方法。这个过程也是AIDL实现的Binder弯完成的。

NotificationManagerService中的工作流程

在这里,声明了一个IBinder来实现Stub:

private final IBinder mService = new INotificationManager.Stub() 

而函数enqueueNotificationWithTag又会调用:

void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,            final int callingPid, final String tag, final int id, final Notification notification,            int[] idOut, int incomingUserId) {            ...            //从NotificationList中获取通知存入NotificationRecord,以及对Notification中            //的一些非法额度参数进行异常处理            mHandler.post(new Runnable() {            @Override            public void run() {                synchronized (mNotificationList) {                    // === Scoring ===                    // 0. Sanitize inputs                    notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,                            Notification.PRIORITY_MAX);                    // Migrate notification flags to scores                    if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {                        if (notification.priority < Notification.PRIORITY_MAX) {                            notification.priority = Notification.PRIORITY_MAX;                        }                    } else if (SCORE_ONGOING_HIGHER &&                            0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {                        if (notification.priority < Notification.PRIORITY_HIGH) {                            notification.priority = Notification.PRIORITY_HIGH;                        }                    }                    // 1. initial score: buckets of 10, around the app [-20..20]                    final int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER;                    // 2. extract ranking signals from the notification data                    final StatusBarNotification n = new StatusBarNotification(                            pkg, opPkg, id, tag, callingUid, callingPid, score, notification,                            user);                    NotificationRecord r = new NotificationRecord(n, score);                    NotificationRecord old = mNotificationsByKey.get(n.getKey());                    if (old != null) {                        // Retain ranking information from previous record                        r.copyRankingInformation(old);                    }                    mRankingHelper.extractSignals(r);                    // 3. Apply local rules                    // blocked apps                    if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {                        if (!isSystemNotification) {                            r.score = JUNK_SCORE;                            Slog.e(TAG, "Suppressing notification from package " + pkg                                    + " by user request.");                        }                    }                    if (r.score < SCORE_DISPLAY_THRESHOLD) {                        // Notification will be blocked because the score is too low.                        return;                    }                    // Clear out group children of the old notification if the update causes the                    // group summary to go away. This happens when the old notification was a                    // summary and the new one isn't, or when the old notification was a summary                    // and its group key changed.                    if (old != null && old.getNotification().isGroupSummary() &&                            (!notification.isGroupSummary() ||                                    !old.getGroupKey().equals(r.getGroupKey()))) {                        cancelGroupChildrenLocked(old, callingUid, callingPid, null);                    }                    int index = indexOfNotificationLocked(n.getKey());                    if (index < 0) {                        mNotificationList.add(r);                        mUsageStats.registerPostedByApp(r);                    } else {                        old = mNotificationList.get(index);                        mNotificationList.set(index, r);                        mUsageStats.registerUpdatedByApp(r, old);                        // Make sure we don't lose the foreground service state.                        notification.flags |=                                old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;                        r.isUpdate = true;                    }                    mNotificationsByKey.put(n.getKey(), r);                    // Ensure if this is a foreground service that the proper additional                    // flags are set.                    if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {                        notification.flags |= Notification.FLAG_ONGOING_EVENT                                | Notification.FLAG_NO_CLEAR;                    }                    applyZenModeLocked(r);                    mRankingHelper.sort(mNotificationList);                    if (notification.icon != 0) {                        StatusBarNotification oldSbn = (old != null) ? old.sbn : null;                        mListeners.notifyPostedLocked(n, oldSbn);                    } else {                        Slog.e(TAG, "Not posting notification with icon==0: " + notification);                        if (old != null && !old.isCanceled) {                            mListeners.notifyRemovedLocked(n);                        }                        // ATTENTION: in a future release we will bail out here                        // so that we do not play sounds, show lights, etc. for invalid                        // notifications                        Slog.e(TAG, "WARNING: In a future release this will crash the app: "                                + n.getPackageName());                    }                    buzzBeepBlinkLocked(r);                }            }        });        idOut[0] = id;

我们主要看Handler.post方法中的Runnable方法。
这么最主要的工作就是这个函数:

if (old != null && old.getNotification().isGroupSummary() &&                            (!notification.isGroupSummary() ||                                    !old.getGroupKey().equals(r.getGroupKey()))) {                        cancelGroupChildrenLocked(old, callingUid, callingPid, null);                    }

这一段的意思就是清掉前一个通知,如果更新而导致数组的大小出现了变化的话。这个发生在过去的通知是个所有的通知的集合,或者当过去的通知是一个集合但是他的key发生了改变。

而函数cancelGroupChildrenLocked中做了一个动作那就是去除尾部的通知同时执行尾部的通知,接下来又调用了cancelNotificationLocked(childR, false, REASON_GROUP_SUMMARY_CANCELED);

 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {  if (sendDelete) {            if (r.getNotification().deleteIntent != null) {                try {                    r.getNotification().deleteIntent.send();                } catch (PendingIntent.CanceledException ex) {                    // do nothing - there's no relevant way to recover, and                    //     no reason to let this propagate                    Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);                }            }        }        ....   }

我们只需要注重上面那一段通过Notification的deleteIntent(上面在显示Notification的时候已经显示了deleteIntent是PendingIntent)的send方法,执行了PendingIntent。

PendingIntent的send

我们接着看PendingIntent的send的方法,在这里send被重载了好几种方法,最终会到这个send执行:

 public void send(Context context, int code, Intent intent,            OnFinished onFinished, Handler handler, String requiredPermission)            throws CanceledException {        try {            String resolvedType = intent != null ?                    intent.resolveTypeIfNeeded(context.getContentResolver())                    : null;            int res = mTarget.send(code, intent, resolvedType,                    onFinished != null                            ? new FinishedDispatcher(this, onFinished, handler)                            : null,                    requiredPermission);            if (res < 0) {                throw new CanceledException();            }        } catch (RemoteException e) {            throw new CanceledException(e);        }    }

最终会由mTarget.send调用,而mTarget则是IInterSender,这时又会回到PendingIntentRecord。这个时候就可以调用之前存进来的PendingIntent了。
最后由函数sendInner完成:

int sendInner(int code, Intent intent, String resolvedType,            IIntentReceiver finishedReceiver, String requiredPermission,            IBinder resultTo, String resultWho, int requestCode,            int flagsMask, int flagsValues, Bundle options, IActivityContainer container) {        synchronized(owner) {            if (!canceled) {                sent = true;                if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {                    owner.cancelIntentSenderLocked(this, true);                    canceled = true;                }                Intent finalIntent = key.requestIntent != null                        ? new Intent(key.requestIntent) : new Intent();                if (intent != null) {                    int changes = finalIntent.fillIn(intent, key.flags);                    if ((changes&Intent.FILL_IN_DATA) == 0) {                        resolvedType = key.requestResolvedType;                    }                } else {                    resolvedType = key.requestResolvedType;                }                flagsMask &= ~Intent.IMMUTABLE_FLAGS;                flagsValues &= flagsMask;                finalIntent.setFlags((finalIntent.getFlags()&~flagsMask) | flagsValues);                final long origId = Binder.clearCallingIdentity();                boolean sendFinish = finishedReceiver != null;                int userId = key.userId;                if (userId == UserHandle.USER_CURRENT) {                    userId = owner.getCurrentUserIdLocked();                }                switch (key.type) {                    case ActivityManager.INTENT_SENDER_ACTIVITY:                        if (options == null) {                            options = key.options;                        } else if (key.options != null) {                            Bundle opts = new Bundle(key.options);                            opts.putAll(options);                            options = opts;                        }                        try {                            if (key.allIntents != null && key.allIntents.length > 1) {                                Intent[] allIntents = new Intent[key.allIntents.length];                                String[] allResolvedTypes = new String[key.allIntents.length];                                System.arraycopy(key.allIntents, 0, allIntents, 0,                                        key.allIntents.length);                                if (key.allResolvedTypes != null) {                                    System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0,                                            key.allResolvedTypes.length);                                }                                allIntents[allIntents.length-1] = finalIntent;                                allResolvedTypes[allResolvedTypes.length-1] = resolvedType;                                owner.startActivitiesInPackage(uid, key.packageName, allIntents,                                        allResolvedTypes, resultTo, options, userId);                            } else {                                owner.startActivityInPackage(uid, key.packageName, finalIntent,                                        resolvedType, resultTo, resultWho, requestCode, 0,                                        options, userId, container, null);                            }                        } catch (RuntimeException e) {                            Slog.w(ActivityManagerService.TAG,                                    "Unable to send startActivity intent", e);                        }                        break;                    case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:                        key.activity.task.stack.sendActivityResultLocked(-1, key.activity,                                key.who, key.requestCode, code, finalIntent);                        break;                    case ActivityManager.INTENT_SENDER_BROADCAST:                        try {                            // If a completion callback has been requested, require                            // that the broadcast be delivered synchronously                            owner.broadcastIntentInPackage(key.packageName, uid,                                    finalIntent, resolvedType,                                    finishedReceiver, code, null, null,                                requiredPermission, (finishedReceiver != null), false, userId);                            sendFinish = false;                        } catch (RuntimeException e) {                            Slog.w(ActivityManagerService.TAG,                                    "Unable to send startActivity intent", e);                        }                        break;                    case ActivityManager.INTENT_SENDER_SERVICE:                        try {                            owner.startServiceInPackage(uid,                                    finalIntent, resolvedType, userId);                        } catch (RuntimeException e) {                            Slog.w(ActivityManagerService.TAG,                                    "Unable to send startService intent", e);                        }                        break;                }                if (sendFinish) {                    try {                        finishedReceiver.performReceive(new Intent(finalIntent), 0,                                null, null, false, false, key.userId);                    } catch (RemoteException e) {                    }                }                Binder.restoreCallingIdentity(origId);                return 0;            }        }        return ActivityManager.START_CANCELED;    }

其实写的这么长,我们最终只有这么一句有用:

owner.startActivityInPackage(uid, key.packageName, finalIntent,                                        resolvedType, resultTo, resultWho, requestCode, 0,                                        options, userId, container, null);

这里的owner又是指AMS,我们回到AMS去看看,又是调用了什么:

final int startActivityInPackage(int uid, String callingPackage,            Intent intent, String resolvedType, IBinder resultTo,            String resultWho, int requestCode, int startFlags, Bundle options, int userId,            IActivityContainer container, TaskRecord inTask) {        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,                false, ALLOW_FULL_ONLY, "startActivityInPackage", null);        // TODO: Switch to user app stacks here.        int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent,                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,                null, null, null, options, userId, container, inTask);        return ret;    }

看到 mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent,resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,null, null, null, options, userId, container, inTask);
这个函数,我,恍然大悟,这不就是Activity启动流程中的一部分吗,通过Activity监听器来执行在Activity在任务栈中启动过程。

至此PendingIntent是如何启动四大组件的Activity就分析完毕了。

流程图

PendIntent工作流程

感谢任玉刚大神的android开发探索艺术,以及下面这位大神
PendingIntent的工作原理

0 0
原创粉丝点击