对NotificationManager和方法notify的理解

来源:互联网 发布:列生成算法思想 编辑:程序博客网 时间:2024/06/08 09:48
NotificationManager myNotiManager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
myNotiManager.notify(myNoti.flags,myNoti);
1,NOTIFICATION_SERVICE怎么得到的?
2,NotificationManager怎么产生的?

3,notify的动作又是怎么做到的?


从上面的函数:

@Override    public Object getSystemService(String name) {        if (getBaseContext() == null) {            throw new IllegalStateException(                    "System services not available to Activities before onCreate()");        }        if (WINDOW_SERVICE.equals(name)) {            return mWindowManager;        } else if (SEARCH_SERVICE.equals(name)) {            ensureSearchManager();            return mSearchManager;        }        return super.getSystemService(name);    }

继续跟入父类:getSystemService(name)

@Override   public Object getSystemService(String name) {        if (LAYOUT_INFLATER_SERVICE.equals(name)) {            if (mInflater == null) {                mInflater = LayoutInflater.from(mBase).cloneInContext(this);            }            return mInflater;        }        return mBase.getSystemService(name);    }

继续跟入mBase.getSystemService(name)

在Context.java中文件,此函数的实现在ContextImp.java

public abstract Object getSystemService(String name);static {        registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {                public Object getService(ContextImpl ctx) {                    return AccessibilityManager.getInstance(ctx);                }});        ----------------------------                registerService(NOTIFICATION_SERVICE, new ServiceFetcher() {                public Object createService(ContextImpl ctx) {                    final Context outerContext = ctx.getOuterContext();                    return new NotificationManager(                        new ContextThemeWrapper(outerContext,                                Resources.selectSystemTheme(0,                                        outerContext.getApplicationInfo().targetSdkVersion,                                        com.android.internal.R.style.Theme_Dialog,                                        com.android.internal.R.style.Theme_Holo_Dialog,                                        com.android.internal.R.style.Theme_DeviceDefault_Dialog)),                        ctx.mMainThread.getHandler());                }});       ----------------------------------        registerService(WINDOW_SERVICE, new ServiceFetcher() {                public Object getService(ContextImpl ctx) {                    return WindowManagerImpl.getDefault(ctx.mPackageInfo.mCompatibilityInfo);                }});    }

以上的静态块加载完成后会放到SYSTEM_SERVICE_MAP中,在通过开始的serviceName得到。

private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =            new HashMap<String, ServiceFetcher>();    private static int sNextPerContextServiceCacheIndex = 0;    private static void registerService(String serviceName, ServiceFetcher fetcher) {        if (!(fetcher instanceof StaticServiceFetcher)) {            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;        }        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);    }

通过下面的函数对public abstract Object getSystemService(String name)真正实现 ContextImpl.java
@Override    public Object getSystemService(String name) {        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);        return fetcher == null ? null : fetcher.getService(this);    }

很明显此时有NOTIFICATION_SERVICE即service != null,直接返回service;返回一个对应的Manager 

public Object getService(ContextImpl ctx) {            ArrayList<Object> cache = ctx.mServiceCache;            Object service;            synchronized (cache) {                if (cache.size() == 0) {                    // Initialize the cache vector on first access.                    // At this point sNextPerContextServiceCacheIndex                    // is the number of potential services that are                    // cached per-Context.                    for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {                        cache.add(null);                    }                } else {                    service = cache.get(mContextCacheIndex);                    if (service != null) {                        return service;                      }                }                service = createService(ctx);                cache.set(mContextCacheIndex, service);                return service;            }        }

在看 myNotiManager.notify(myNoti.flags,myNoti);

public void notify(int id, Notification notification)    {        notify(null, id, notification);    }         public void notify(String tag, int id, Notification notification)    {        int[] idOut = new int[1];        INotificationManager service = getService();        String pkg = mContext.getPackageName();        if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");        try {            service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut);            if (id != idOut[0]) {                Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);            }        } catch (RemoteException e) {        }    }        static public INotificationManager getService()    {        if (sService != null) {            return sService;        }        IBinder b = ServiceManager.getService("notification");        sService = INotificationManager.Stub.asInterface(b);        return sService;    }    public static IBinder getService(String name) {        try {            IBinder service = sCache.get(name);            if (service != null) {                return service;            } else {                return getIServiceManager().getService(name);            }        } catch (RemoteException e) {            Log.e(TAG, "error in getService", e);        }        return null;    }

 那么 notification 这个key的IBinder有吗?

在Context.java里定义了:public static final String NOTIFICATION_SERVICE = "notification";
  public static void initServiceCache(Map<String, IBinder> cache) {
        if (sCache.size() != 0) {
            throw new IllegalStateException("setServiceCache may only be called once");
        }
        sCache.putAll(cache);
    }
    
    上面的代码是在系统第一次启动时就加载的。

再回到

public void notify(String tag, int id, Notification notification)    {        int[] idOut = new int[1];        INotificationManager service = getService();   //这里已经得到实例        String pkg = mContext.getPackageName();        if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");        try {            service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut);            if (id != idOut[0]) {                Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);            }        } catch (RemoteException e) {        }    }

在NotificationManagerService.java下实现 enqueueNotificationWithTag

public void enqueueNotificationWithTag(String pkg, String tag, int id, Notification notification,            int[] idOut)    {        enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(),                tag, id, notification, idOut);    }

最终到:

public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,            String tag, int id, int priority, Notification notification, int[] idOut)    {        checkIncomingCall(pkg);        // Limit the number of notifications that any given package except the android        // package can enqueue.  Prevents DOS attacks and deals with leaks.        if (!"android".equals(pkg)) {            synchronized (mNotificationList) {                int count = 0;                final int N = mNotificationList.size();                for (int i=0; i<N; i++) {                    final NotificationRecord r = mNotificationList.get(i);                    if (r.pkg.equals(pkg)) {                        count++;                        if (count >= MAX_PACKAGE_NOTIFICATIONS) {                            Slog.e(TAG, "Package has already posted " + count                                    + " notifications.  Not showing more.  package=" + pkg);                            return;                        }                    }                }            }        }        // This conditional is a dirty hack to limit the logging done on        //     behalf of the download manager without affecting other apps.        if (!pkg.equals("com.android.providers.downloads")                || Log.isLoggable("DownloadManager", Log.VERBOSE)) {            EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, tag,                    notification.toString());        }        if (pkg == null || notification == null) {            throw new IllegalArgumentException("null not allowed: pkg=" + pkg                    + " id=" + id + " notification=" + notification);        }        if (notification.icon != 0) {            if (notification.contentView == null) {                throw new IllegalArgumentException("contentView required: pkg=" + pkg                        + " id=" + id + " notification=" + notification);            }        }        synchronized (mNotificationList) {            NotificationRecord r = new NotificationRecord(pkg, tag, id,                     callingUid, callingPid,                     priority,                    notification);            NotificationRecord old = null;            int index = indexOfNotificationLocked(pkg, tag, id);            if (index < 0) {                mNotificationList.add(r);            } else {                old = mNotificationList.remove(index);                mNotificationList.add(index, r);                // Make sure we don't lose the foreground service state.                if (old != null) {                    notification.flags |=                        old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;                }            }            // 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;            }            if (notification.icon != 0) {                StatusBarNotification n = new StatusBarNotification(pkg, id, tag,                        r.uid, r.initialPid, notification);                n.priority = r.priority;                if (old != null && old.statusBarKey != null) {                    r.statusBarKey = old.statusBarKey;                    long identity = Binder.clearCallingIdentity();                    try {                        mStatusBar.updateNotification(r.statusBarKey, n);                    }                    finally {                        Binder.restoreCallingIdentity(identity);                    }                } else {                    long identity = Binder.clearCallingIdentity();                    try {                        r.statusBarKey = mStatusBar.addNotification(n);                        mAttentionLight.pulse();                    }                    finally {                        Binder.restoreCallingIdentity(identity);                    }                }                sendAccessibilityEvent(notification, pkg);            } else {                Slog.e(TAG, "Ignoring notification with icon==0: " + notification);                if (old != null && old.statusBarKey != null) {                    long identity = Binder.clearCallingIdentity();                    try {                        mStatusBar.removeNotification(old.statusBarKey);                    }                    finally {                        Binder.restoreCallingIdentity(identity);                    }                }            }            // If we're not supposed to beep, vibrate, etc. then don't.            if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)                    && (!(old != null                        && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))                    && mSystemReady) {                final AudioManager audioManager = (AudioManager) mContext                .getSystemService(Context.AUDIO_SERVICE);                // sound                final boolean useDefaultSound =                    (notification.defaults & Notification.DEFAULT_SOUND) != 0;                if (useDefaultSound || notification.sound != null) {                    Uri uri;                    if (useDefaultSound) {                        uri = Settings.System.DEFAULT_NOTIFICATION_URI;                    } else {                        uri = notification.sound;                        try {                            MediaPlayer mMediaPlayer = new MediaPlayer();                            mMediaPlayer.setDataSource(notification.sound.toString());                        } catch (Exception ex) {                            Slog.d(TAG, "default notification will be used");                            uri = Settings.System.DEFAULT_NOTIFICATION_URI;                        }                    }                    boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;                    int audioStreamType;                    if (notification.audioStreamType >= 0) {                        audioStreamType = notification.audioStreamType;                    } else {                        audioStreamType = DEFAULT_STREAM_TYPE;                    }                    mSoundNotification = r;                    // do not play notifications if stream volume is 0                    // (typically because ringer mode is silent).                    if (audioManager.getStreamVolume(audioStreamType) != 0) {                        long identity = Binder.clearCallingIdentity();                        try {                            mSound.play(mContext, uri, looping, audioStreamType);                        }                        finally {                            Binder.restoreCallingIdentity(identity);                        }                    }                }                // vibrate                final boolean useDefaultVibrate =                    (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;                if ((useDefaultVibrate || notification.vibrate != null)                        && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_NOTIFICATION)) {                    mVibrateNotification = r;                    mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN                                                        : notification.vibrate,                              ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);                }            }            // this option doesn't shut off the lights            // light            // the most recent thing gets the light            mLights.remove(old);            if (mLedNotification == old) {                mLedNotification = null;            }            //Slog.i(TAG, "notification.lights="            //        + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));            if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {                mLights.add(r);                updateLightsLocked();            } else {                if (old != null                        && ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0)) {                    updateLightsLocked();                }            }        }        idOut[0] = id;    }

以上就是对
NotificationManager myNotiManager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
myNotiManager.notify(myNoti.flags,myNoti);
这2行代码的初略理解!

原创粉丝点击