GVKun编程网logo

Android中关于Notification及NotificationManger的详解(android notificationmanager)

20

对于Android中关于Notification及NotificationManger的详解感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍androidnotificationmanager,

对于Android中关于Notification及NotificationManger的详解感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍android notificationmanager,并为您提供关于Android Notification、Android Notification 从 notify 到添加 view 的处理流程、Android Notification 使用方法详解、android Notification 的一个简单应用(在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转)的有用信息。

本文目录一览:

Android中关于Notification及NotificationManger的详解(android notificationmanager)

Android中关于Notification及NotificationManger的详解(android notificationmanager)

Android状态栏提醒

在Android中提醒功能也可以用AlertDialog,但是我们要慎重的使用,因为当使用AlertDialog的时候,用户正在进行的操作将会被打断,因为当前焦点被AlertDialog得到。我们可以想像一下,当用户打游戏正爽的时候,这时候来了一条短信。如果这时候短信用AlertDialog提醒,用户必须先去处理这条提醒,从而才能继续游戏。用户可能会活活被气死。而使用Notification就不会带来这些麻烦事,用户完全可以打完游戏再去看这条短信。所以在开发中应根据实际需求,选择合适的控件。

步骤:

一、添加布局对象

复制代码 代码如下:

<Button
android:id="@+id/showButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="showNotification" />

<Button
android:id="@+id/cancelButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="cancelNotification" />


二、修改MianActivity继承处Activity并实现接口OnClickListener
复制代码 代码如下:

public class MainActivity extends Activity implements OnClickListener {
 private Context mContext = this;
 private Button showbtn,calclebtn;
 private Notification noti;
 private notificationmanager notimanger;
 private static int NOTIFICATION_ID = 0x0001;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  setUpViews();
 }

 private void setUpViews() {
  showbtn = (Button) findViewById(R.id.showButton);
  calclebtn = (Button) findViewById(R.id.cancelButton);
  noti = new Notification(R.drawable.ic_launcher,"this is a notification",System.currentTimeMillis());
  noti.defaults = Notification.DEFAULT_SOUND;// 使用默认的提示声音
  noti.defaults |= Notification.DEFAULT_VIBRATE;// 添加震动
  notimanger = (notificationmanager) this.getSystemService(mContext.NOTIFICATION_SERVICE);//获取Nofificationmanger对象
  showbtn.setonClickListener(this);//让Activity实现接口OnClickListener可以简单的通过此两行代码添加按钮点击响应事件
  calclebtn.setonClickListener(this);
 }

 // 按钮点击事件响应
 @Override
 public void onClick(View v) {
  if (v == showbtn) {
   Intent intent = new Intent(this.getApplicationContext(),this.getClass());
   // 设置Intent.FLAG_ACTIVITY_NEW_TASK
   intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   PendingIntent contentIntent = PendingIntent.getActivity(this,intent,0);
   // noti.setLatestEventInfo(context,contentTitle,contentText,contentIntent)设置(上下文,标题,内容,PendingInteng)
   noti.setLatestEventInfo(this,"10086","你从此以后免除所有话费",contentIntent);
   // 发送通知(消息ID,通知对象)
   notimanger.notify(NOTIFICATION_ID,noti);
  } else if (v == calclebtn) {
   // 取消通知(id)
   notimanger.cancel(NOTIFICATION_ID);
  }
 }
}

Android Notification

Android Notification

请教一下,如何定义一个按键,当按下的时候弹出系统的Notification通知?急等...

Android Notification 从 notify 到添加 view 的处理流程

Android Notification 从 notify 到添加 view 的处理流程

创建 Notification 是很容易的,android8.0 以后开始加入通知渠道 NotificationChannel,然后在构造 NotificationCompat.Builder 的时候,指定要发送的渠道,最后调用 NotificationManager.notify (id,notification) 发送通知。

    public void notify(int id, Notification notification)
    {
        notify(null, id, notification);
    }
    ---------------
    public void notify(String tag, int id, Notification notification)
    {
        notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId()));
    }
    ---------------
    public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
    {
        INotificationManager service = getService();
                 final Notification copy = Builder.maybeCloneStrippedForDelivery(notification, isLowRam);
                 ...
        try {
            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                    copy, user.getIdentifier());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
     }   
-------------------
    static public INotificationManager getService()
    {
        if (sService != null) {
            return sService;
        }
        IBinder b = ServiceManager.getService("notification");
        sService = INotificationManager.Stub.asInterface(b);
        return sService;
    }

获取了 INotificationManager 远程接口对象,把 Notification 给加入到队列中,
INotificationManager 的远程对象是 NotificationManagerService 里的 mservice,NotificationManagerService 是系统服务。在开机启动的时候,Systemserver 里和其他系统服务一起启动,最后注册到 ServiceManager 里。

publishBinderService (Context.NOTIFICATION_SERVICE, mService);  // 把 service 注册到 Servicemanager 里
----
private final IBinder mService = new INotificationManager.Stub(){
...
}

接着前面的,找到了 enqueueNotificationWithTag

    @Override
    public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
            Notification notification, int userId) throws RemoteException {
        enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
                Binder.getCallingPid(), tag, id, notification, userId);
    }
    ------------
    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
            final int callingPid, final String tag, final int id, final Notification notification,
            int incomingUserId) {
            .... 处理 notification 包含的信息,通知渠道,优先级。。
            mHandler.post(new EnqueueNotificationRunnable(userId, r));
    }

把 notification 转换为 NotificationRecord,并 post 给 EnqueueNotificationRunnable,

    EnqueueNotificationRunnable 的 run 方法里。
    @Override
    public void run() {
        synchronized (mNotificationLock) {
            mEnqueuedNotifications.add(r);
            scheduleTimeoutLocked(r);
            ...
            mHandler.post(new PostNotificationRunnable(r.getKey()));
        }
    ------------
    @Override
    public void run() {
        synchronized (mNotificationLock) {
            try {
                NotificationRecord r = null;
                int N = mEnqueuedNotifications.size();    
                NotificationRecord old = mNotificationsByKey.get(key);
                final StatusBarNotification n = r.sbn;
                final Notification notification = n.getNotification();      
                ...
                 if (notification.getSmallIcon() != null) {
                     StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
                     mListeners.notifyPostedLocked(n, oldSbn);
                     if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
                         mHandler.post(new Runnable() {
                             @Override
                             public void run() {
                                 mGroupHelper.onNotificationPosted(
                                         n, hasAutoGroupSummaryLocked(n));
                             }
                         });
                     }
                }
                ...
                buzzBeepBlinkLocked(r);
               } 
  ------------
  void buzzBeepBlinkLocked(NotificationRecord record) {
    处理 notification 的 声音 震动和灯光闪烁
  }
  ------------
  public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
    发送给状态栏
    mHandler.post(new Runnable() {
       @Override
       public void run() {
           notifyPosted(info, sbnToPost, update);
       }
   });
  }
  ↓
  private void notifyPosted(final ManagedServiceInfo info,
        final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
    final INotificationListener listener = (INotificationListener) info.service;
    StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
    try {
        listener.onNotificationPosted(sbnHolder, rankingUpdate);
    } catch (RemoteException ex) {
        Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
    }
  }
  

INotificationListener 是另一个远程接口对象

protected class NotificationListenerWrapper extends INotificationListener.Stub
------------

@Override
public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
        NotificationRankingUpdate update) {
        SomeArgs args = SomeArgs.obtain();
        args.arg1 = sbn;
        args.arg2 = mRankingMap;
        mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_POSTED,
                args).sendToTarget();
        }

case MSG_ON_NOTIFICATION_POSTED: {
   SomeArgs args = (SomeArgs) msg.obj;
   StatusBarNotification sbn = (StatusBarNotification) args.arg1;
   RankingMap rankingMap = (RankingMap) args.arg2;
   args.recycle();
   onNotificationPosted(sbn, rankingMap);
------------
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
    onNotificationPosted(sbn);
}    
public void onNotificationPosted(StatusBarNotification sbn) {
    // optional
}

很意外,发现方法是空的,那调这么多有什么用? 研究了一下发现,onNotificationPosted 的这个方法属于的是

public abstract class NotificationListenerService extends Service {
1
NotificationListenerService 是个抽象方法,那很自然调用的时候会调用它的子类,
然后

public class NotificationListenerWithPlugins extends NotificationListenerService
1
但是找了一圈 NotificationListenerWithPlugins ,没有 onNotificationPosted,那只有继续找它的子类了,
后来发现,在 Statusbar 里有个匿名内部类实现了 NotificationListenerService 的方法。

private final NotificationListenerWithPlugins mNotificationListener =
        new NotificationListenerWithPlugins() {
        ...
        @Override
        public void onNotificationPosted(final StatusBarNotification sbn,
                final RankingMap rankingMap) {
                
              mHandler.post(new Runnable() {
                  @Override
                  public void run() {
                ...
                if (isUpdate) {
                    updateNotification(sbn, rankingMap);
                } else {
                    addNotification(sbn, rankingMap);
                }
                ...
            }
        }
        ...
}

------------
    public void addNotification(StatusBarNotification notification, RankingMap ranking)
       throws InflationException {
        Entry shadeEntry = createNotificationViews(notification);
        boolean isHeadsUped = shouldPeek(shadeEntry);.
        ...
    }
------------
protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn)
        throws InflationException {
     NotificationData.Entry entry = new NotificationData.Entry(sbn);
        Dependency.get(LeakDetector.class).trackInstance(entry);
     entry.createIcons(mContext, sbn);
     // Construct the expanded view.
     inflateViews(entry, mStackScroller);
}
------------
protected void inflateViews(Entry entry, ViewGroup parent) {
      new RowInflaterTask().inflate(mContext, parent, entry,
              row -> {
                  bindRow(entry, pmUser, sbn, row);
                  updateNotification(entry, pmUser, sbn, row);
              });
}            

最后 bindRow 就是去构造通知栏的通知 View,然后 updateNotification 就是去显示到状态栏。

private void updateNotification(Entry entry, PackageManager pmUser,
     StatusBarNotification sbn, ExpandableNotificationRow row) {
        ...
        row.updateNotification(entry);
}
------------
public void updateNotification(NotificationData.Entry entry) {
    mEntry = entry;
    mStatusBarNotification = entry.notification;
    mNotificationInflater.inflateNotificationViews();
}
------------
public void inflateNotificationViews() {
    inflateNotificationViews(FLAG_REINFLATE_ALL);
}
------------
void inflateNotificationViews(int reInflateFlags) {
    ...
    StatusBarNotification sbn = mRow.getEntry().notification;
    new AsyncInflationTask(sbn, reInflateFlags, mRow, mIsLowPriority,
            mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
            mCallback, mRemoteViewClickHandler).execute();
}

使用了异步任务 AsyncTask 去完成布局

AsyncInflationTask

@Override
protected InflationProgress doInBackground(Void... params) {
     return createRemoteViews(mReInflateFlags,
     recoveredBuilder, mIsLowPriority, mIsChildInGroup,
     mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
     packageContext);
}
------------
private static InflationProgress createRemoteViews(int reInflateFlags,
            Notification.Builder builder, boolean isLowPriority, boolean isChildInGroup,
            boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
            Context packageContext) {
        InflationProgress result = new InflationProgress();
        isLowPriority = isLowPriority && !isChildInGroup;
        if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
            result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight);
        }

        if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
            result.newExpandedView = createExpandedView(builder, isLowPriority);
        }

        if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
            result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight);
        }

        if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
            result.newPublicView = builder.makePublicContentView();
        }

        if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
            result.newAmbientView = redactAmbient ? builder.makePublicAmbientNotification()
                    : builder.makeAmbientNotification();
        }
        result.packageContext = packageContext;
        return result;
    }  

到了这里,都是创建各种布局
比如 createContentView


public RemoteViews createContentView() {
    return createContentView(false /* increasedheight */ );
}
------------
public RemoteViews createContentView(boolean increasedHeight) {
    if (mN.contentView != null && useExistingRemoteView()) {
        return mN.contentView;
    } else if (mStyle != null) {
        final RemoteViews styleView = mStyle.makeContentView(increasedHeight);
        if (styleView != null) {
            return styleView;
        }
    }
    return applyStandardTemplate(getBaseLayoutResource());
}

这里会去判断我们是否有在 notification 里添加 style, 如果有不同的 style,比如音乐播放器那种 notification,就是自定义 style,如果没有,那就用默认的 layout。

private int getBaseLayoutResource() {
    return R.layout.notification_template_material_base;
}
------------
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/status_bar_latest_event_content"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:tag="base" >
    <include layout="@layout/notification_template_header" />
    <LinearLayout
        android:id="@+id/notification_main_column"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:layout_marginStart="@dimen/notification_content_margin_start"
        android:layout_marginEnd="@dimen/notification_content_margin_end"
        android:layout_marginTop="@dimen/notification_content_margin_top"
        android:layout_marginBottom="@dimen/notification_content_margin_bottom"
        android:orientation="vertical" >
        <include layout="@layout/notification_template_part_line1" />
        <include layout="@layout/notification_template_text" />
        <include
            android:layout_width="match_parent"
            android:layout_height="@dimen/notification_progress_bar_height"
            android:layout_marginTop="@dimen/notification_progress_margin_top"
            layout="@layout/notification_template_progress" />
    </LinearLayout>
    <include layout="@layout/notification_template_right_icon" />
</FrameLayout>

原来这就是我们用的 notification 的布局内容。

private RemoteViews applyStandardTemplate(int resId) {
    return applyStandardTemplate(resId, mParams.reset().fillTextsFrom(this));
}
private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) {
    return applyStandardTemplate(resId, mParams.reset().hasProgress(hasProgress)
            .fillTextsFrom(this));
}
private RemoteViews applyStandardTemplate(int resId, StandardTemplateParams p) {
    updateBackgroundColor(contentView);
    bindNotificationHeader(contentView, p.ambient);
    bindLargeIcon(contentView);
}
 

Android Notification 使用方法详解

Android Notification 使用方法详解

Android Notification 使用方法详解

用TaskStackBuilder来获取PendingIntent处理点击跳转到别的Activity,首先是用一般的PendingIntent来进行跳转。

mBuilder = new NotificationCompat.Builder(this).setContent(view) 
    .setSmallIcon(R.drawable.icon).setTicker("新资讯") 
    .setWhen(System.currentTimeMillis()) 
    .setongoing(false) 
    .setAutoCancel(true); 
Intent intent = new Intent(this,NotificationShow.class); 
 PendingIntent pendingIntent = PendingIntent.getActivity(this,intent,PendingIntent.FLAG_UPDATE_CURRENT); 
mBuilder.setContentIntent(pendingIntent); 

直接用PendingIntent来跳转到NotificationShow,在运行效果上来看,首先发送了一条Notification到通知栏上,然后这时,我退出程序,即MainActivity已经不存在了,回到home主菜单,看到Notification仍然存在,当然,我们还没有点击或者cancel它,现在去点击Notification,跳转到NotificationShow界面,然后我们按下Back键,发现直接回到主界面了。现在大多数android应用都是在通知栏中如果有Notification通知的话,点击它,然后会直接跳转到对应的应用程序的某个界面,这时如果回退,即按下Back键,会返回到该应用程序的主界面,而不是系统的主界面。所以用上面这种PendingIntent的做法达不到目的。这里我们使用TaskStackBuilder来做。

mBuilder = new NotificationCompat.Builder(this).setContent(view) 
        .setSmallIcon(R.drawable.icon).setTicker("新资讯") 
        .setWhen(System.currentTimeMillis()) 
        .setongoing(false) 
        .setAutoCancel(true); 
    Intent intent = new Intent(this,NotificationShow.class); 
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); 
    stackBuilder.addParentStack(NotificationShow.class); 
    stackBuilder.addNextIntent(intent); 
    PendingIntent pendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT); 
//    PendingIntent pendingIntent = PendingIntent.getActivity(this,//    intent,PendingIntent.FLAG_UPDATE_CURRENT); 
    mBuilder.setContentIntent(pendingIntent); 

        显示用TaskStackBuilder.create(this)一个stackBuilder实例,接下来addParentStack();关于这个方法,我们查一下官方api文档:Add the activity parent chain as specified by the parentActivityName attribute of the activity (or activity-alias) element in the application's manifest to the task stack builder. 这句话是说添加一个activity,与这个activity的manifest文件中的parentActivityName的属性相关联。

那么我们就在manifest文件中添加这个属性

<activity 
  android:name="com.shulf.notificationtest.NotificationShow" 
  android:parentActivityName=".MainActivity" > 
</activity> 

让它的parentActivity为MainActivity,也就是说在NotificationShow这个界面点击回退时,会跳转到MainActivity这个界面,而不是像上面一样直接回到了程序的主菜单。运行一下,最后效果确实是这样。

以上实用Android Notification的实例详解,如有疑问请留言或者到本站社区交流讨论,本站关于Android开发的文章还有很多,希望大家搜出查阅,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

android Notification 的一个简单应用(在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转)

android Notification 的一个简单应用(在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转)

   网上很多的例子都是直接获取 Notification 对象来设置一个通知,其实 Notification 跟 Dialog 一样,也有自己的 Builder,可以用 builder 对象来设置一个 Notification

    这个例子是在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转(跟 android 的 vcard 文件导入时弹出的 Notification 一样)

    NotificationManager mNotificationManager = (NotificationManager)
                context.getSystemService(Context.NOTIFICATION_SERVICE);
        Notification.Builder builder = new Notification.Builder(context);
        builder.setOngoing(true);
        builder.setProgress (total, current, false);// 设置进度条,false 表示是进度条,true 表示是个走马灯
        builder.setTicker (title);// 设置 title
        builder.setWhen(System.currentTimeMillis());
        builder.setContentTitle (content);// 设置内容
        builder.setAutoCancel (true);// 点击消失
        builder.setSmallIcon(R.drawable.upload);
        builder.setContentIntent (PendingIntent.getActivity (context, 0, new Intent (), 0));// 这句和点击消失那句是 “Notification 点击消失但不会跳转” 的必须条件,如果只有点击消失那句,这个功能是不能实现的

        Notification noti = builder.getNotification();
        mNotificationManager.notify(id,noti);

希望这个例子对其他人有点用,因为我特曾为这个功能苦恼过,呵呵!


今天关于Android中关于Notification及NotificationManger的详解android notificationmanager的介绍到此结束,谢谢您的阅读,有关Android Notification、Android Notification 从 notify 到添加 view 的处理流程、Android Notification 使用方法详解、android Notification 的一个简单应用(在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转)等更多相关知识的信息可以在本站进行查询。

本文标签:

上一篇android notification 的总结分析(android notificationmanager)

下一篇Android TabWidget切换卡的实现应用(android切换选项卡)