Notification通知消息:


public class MainActivity extends Activity implements OnClickListener
{
    NotificationManager notificationMgr =  null;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
                                    
        notificationMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        findViewById(R.id.button1).setOnClickListener(this);
        findViewById(R.id.button2).setOnClickListener(this);
    }
    @Override
    public void onClick(View v)
    {
        switch (v.getId())
        {
        case R.id.button1:
            btn1Click();
            break;
        case R.id.button2:
            btn2Click();
            break;
        default:
            break;
        }
    }
    private void btn2Click()
    {
        notificationMgr.cancel(123);//手动取消,括号内为通知消息的id
    }
                                
    private void btn3Click()
    {
        /* 1.创建通知对象
         * new Notification(icon, tickerText, when)
         * (1)icon设置通知栏的图标
         * (2)tickerText设置通知栏的通知消息标题
         * (3)when设置什么时候发送通知,一般为即时发送,使用System.currentTimeMillis()
         *
         * 2.点击事件关联的Activity
         * (1)getActivities(context, requestCode, intents, flags)
         *
         * 3.设置标题和内容
         * notify.setLatestEventInfo(context, contentTitle, contentText, contentIntent)
         * (1)context:Activity类继承了context,MainActivity继承Activity类
         * (2)contentTitle, contentText: 设置通知标题、通知内容
         *
         * 4.发送通知
         * (1)通过通知管理器发送通知
         * (2)创建管理器对象都是用getSystemService()得到,对象是object类,所以需要强转类型
         * (3)管理器发送通知notificationMgr.notify(id, notification),id指通知消息的id号
         */
                                    
        //1.创建通知对象
        Notification notifyname = new Notification(R.drawable.ic_launcher, "通知消息1",System.currentTimeMillis());
        //设置取消类型
        notifyname.flags = Notification.FLAG_AUTO_CANCEL;//设置为自动取消,用户点击通知后自动取消
        notifyname.flags = Notification.FLAG_ONGOING_EVENT;//设置为无法取消
                                    
        //2.点击事件关联的Activity
        Intent intent = new Intent(this, SecondActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
                                    
        //3.设置标题和内容
        notifyname.setLatestEventInfo(this, "通知标题1", "通知内容1", contentIntent);
                                    
        //4.发送通知
        NotificationManager notificationMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationMgr.notify(123, notifyname);
    }
                                
    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}



自定义通知界面:

//点击发送下载通知并更新通知进度条
private void clickNotify()//remoteView(远程控件)才可在通知布局里用
{
    sendNotify();
    for (int i = 0; i < 10; i++)
    {
        updateNotify(i);
    }
    finishNotify();
}
//发送通知
private void sendNotify()
{
    mNotify = new Notification(R.drawable.ic_launcher, "准备升级", System.currentTimeMillis());
      
    //mNotify.sound = Uri.fromFile(file);//自定义的声音
    mNotify.flags |= Notification.DEFAULT_LIGHTS;//或等于,在原来设置的基础增加设置。默认的灯亮。
    mNotify.flags |= Notification.DEFAULT_SOUND;//默认的声音
    mNotify.flags |= Notification.DEFAULT_VIBRATE;//默认的震动
      
    Intent intent = new Intent();
    mNotify.contentIntent = PendingIntent.getActivity(this, 0, intent , 0);//设置跳转
    mNotify.contentView = new RemoteViews(getPackageName(), R.layout.notify_layout);//自定义布局
      
    mNotifyMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    mNotifyMgr.notify(1234, mNotify);
}
//更新通知
private void updateNotify(int i)
{
    //mNotify.contentView.setBitmap(viewId, methodName, value);设置图片
      
    mNotify.contentView.setTextColor(R.id.textView1, Color.BLUE);//设置文字颜色等
    mNotify.contentView.setTextViewText(R.id.textView1, "进度"+i);
    mNotify.contentView.setProgressBar(R.id.progressBar1, 10, i, false);//最后一项指:是否为无止境的
    mNotifyMgr.notify(1234, mNotify);
}
//下载完成
private void finishNotify()
{
    Intent intent = new Intent(this,NextActivity.class);
    mNotify.contentIntent = PendingIntent.getActivity(this, 0, intent , 0);//设置跳转
      
    mNotify.contentView.setProgressBar(R.id.progressBar1, 10, 10, false);//最后一项指:是否为无止境的
    mNotifyMgr.notify(1234, mNotify);     
}




监听通知清除处理:

  
    
    private int NOTIFY_ID = 0;
    private final static int NOTIFY_REQUEST_CODE = 0;
    private final static String TYPE_NOTIFY_DEL = "type.notify.del";
    /**
     * 创建可监听被清除(手动清除)的通知消息。
     * setDeleteIntent,这个方法在API Level 11(Android 3.0) 新增的.
     * 注意不要设置setAutoCancel为true,否则监听器接收不到。
     * 手动清除时才能监听到,点击时只是产生跳转。
     * @param msg
     * @param left
     */
    private void showNotification()
    {
        // 创建通知消息对象
        NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);
        builder.setTicker("收到一条新的消息");// 弹出的提示
        builder.setContentTitle("通知标题");// 通知消息的标题
        builder.setContentText("通知内容");// 通知消息的内容
        builder.setSmallIcon(IMLib.getInstance().getDrawableId());
        builder.setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), IMLib.getInstance().getDrawableId()));
        builder.setDefaults(Notification.DEFAULT_ALL);
        builder.setWhen(System.currentTimeMillis());
        builder.setAutoCancel(false);
        
        // 点击通知时隐式意图启动Activity
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        String uri = "imlib://" + mContext.getPackageName() + "/conversation";
        intent.setData(Uri.parse(uri));
        PendingIntent contentIntent = PendingIntent.getActivity(mContext.getApplicationContext(), NOTIFY_REQUEST_CODE, intent, 0);
        builder.setContentIntent(contentIntent);
        
        // 手动清除通知时发送广播
        Intent intent_bro = new Intent();
        intent_bro.setAction(IMService.BROADCAST_ACTION);
        intent_bro.putExtra(IMService.TYPE, TYPE_NOTIFY_DEL);
        PendingIntent intent_del = PendingIntent.getBroadcast(mContext, NOTIFY_REQUEST_CODE, intent_bro , 0);
        builder.setDeleteIntent(intent_del);
        
        //显示通知 
        manager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
        manager.notify(NOTIFY_ID, builder.build());
    }


再配合广播处理手动清除后的事件:

    /**
     * 消息处理广播
     * @author zeng
     */
    class IMServiceBroadcastReceiver extends BroadcastReceiver
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            Log.e("", "通知广播");
            if(intent == null || context == null)
            {
                return;
            }
            
            String type = intent.getStringExtra(TYPE);
            if(type.equals(IMNotificationManager.TYPE_NOTIFY_DEL))
            {
                Log.e("", "通知被清除");
                //清除通知
                NotificationManager manager = IMNotificationManager.getInstance(getApplicationContext()).getNotificationManager();
//                manager.cancel(IMNotificationManager.NOTIFY_ID);
                manager.cancelAll();
                //重置通知参数
                IMNotificationManager.getInstance(getApplicationContext()).resetNotificationArgs();
            }
        }



另一种处理方法:

点击通知自动消除并发送广播,在接收广播处理时完成跳转事件。

    /**
     * 创建可监听被清除的通知消息。
     * setDeleteIntent,这个方法在API Level 11(Android 3.0) 新增的.
     * 注意不要设置setAutoCancel为true,否则监听器接收不到。
     * @param msg
     * @param left
     */
    private void showNotificationMsg(Message msg, int left)
    {
        //获取通知消息的内容
        String ntfStr = getNotificationContentText(msg, left);
        
        // 创建通知消息对象
        NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);
        builder.setTicker("收到一条新的消息");// 弹出的提示
        builder.setContentTitle("通知标题");// 通知消息的标题
        builder.setContentText(ntfStr);// 通知消息的内容
        builder.setSmallIcon(IMLib.getInstance().getDrawableId());
        builder.setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), IMLib.getInstance().getDrawableId()));
        builder.setDefaults(Notification.DEFAULT_ALL);
        builder.setWhen(System.currentTimeMillis());
        builder.setAutoCancel(true);
        
        // 点击通知时隐式意图启动Activity
        String uri = "imlib://" + mContext.getPackageName() + "/conversation";
        
        // 手动清除通知时发送广播
        Intent intent_bro = new Intent();
        intent_bro.setAction(IMService.BROADCAST_ACTION);
        intent_bro.putExtra(IMService.TYPE, TYPE_NOTIFY_DEL);
        intent_bro.putExtra("intent_action", ""+Intent.ACTION_VIEW);
        intent_bro.putExtra("intent_data", ""+uri);
        
        PendingIntent contentIntent = PendingIntent.getBroadcast(mContext, NOTIFY_REQUEST_CODE, intent_bro , PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(contentIntent);
        
        //显示通知 
        instance.manager.notify(NOTIFY_ID, builder.build());
    }


广播处理:

   /**
     * 消息处理广播
     * 
     * @author zeng
     */
    class IMServiceBroadcastReceiver extends BroadcastReceiver
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            Log.e("", "通知广播");
            if (intent == null || context == null)
            {
                return;
            }
            
            String type = intent.getStringExtra(TYPE);
            String intent_action = intent.getStringExtra("intent_action");
            String intent_data = intent.getStringExtra("intent_data");
            
            Log.e("intent_action", "" + intent_action);
            Log.e("intent_data", "" + intent_data);
            
            
            if (type.equals(IMNotificationManager.TYPE_NOTIFY_DEL))
            {
                Intent intent_click = null;
                
                if (intent_action != null)
                {
                    intent_click = new Intent();
                    intent_click.setAction(intent_action);
                }
                
                if (intent_click != null)
                {
                    intent_click.addCategory(Intent.CATEGORY_DEFAULT);
                }
                
                if (intent_data != null && Uri.parse(intent_data) != null)
                {
                    intent_click.setData(Uri.parse(intent_data));
                }
                
                if (intent_click != null)
                {
                    intent_click.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent_click);
                }
                
                // 重置通知参数
                IMNotificationManager.getInstance(getApplicationContext()).resetNotificationArgs();
            }
        }
    }


注:记得添加上intent_click.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);同时设置Activity的android:launchMode="singleTask"



Notification新旧版本用法区别:



Notification即通知,用于在通知栏显示提示信息。

在较新的版本中(API level  > 11),Notification类中的一些方法被Android声明deprecated(弃用),其实基本上相当于全部弃用了,因为这个类本身方法就少得可怜。

Android官方声明弃用,一定有它的理由,虽然我也不知道是什么。奈何本人轻度强迫症患者,人家都建议你不要用了,那就不要老是恪守着N年前的东西了。

就像是以前,一说到标签页,大家基本上都会想到TabHost配合ActivityGroup,但Android后来提倡Fragment。

废话说多了,还是小结一下使用方法。下面按照创建一个通知的步骤一步一步来,同时给出新旧实现方法。

1、获取Notification管理器

NotificationManager noteMng = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);


2、新建一个Notification,设置状态栏显示样式

private Notification note;
//API 11以下
note = new Notification(R.drawable.ico_launcher "显示于屏幕顶端状态栏的文本", System.currentTimeMillis());
//API 11及以上
Notification.Builder builder = new Notification.Builder(nowContext).setTicker("显示于屏幕顶端状态栏的文本")
.setSmallIcon(R.drawable.ic_laucher);

API 11以上版本中,状态栏显示的样式跟下拉通知栏中显示的样式,可以一起设置,就是通过Notification.Builder类来实现,这里的Builder只调用了两个方法来设置状态栏显示样式。


3、设置Notification标志位(非必要步骤)
//FLAG_ONGOING_EVENT表明有程序在运行,该Notification不可由用户清除
note.flags = Notification.FLAG_ONGOING_EVENT;


4、设置点击Notification后的触发事件
//通过Intent,使得点击Notification之后会启动新的Activity
Intent i = new Intent(nowContext, AnotherActivity.class);
//该标志位表示如果Intent要启动的Activity在栈顶,则无须创建新的实例
i.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
pendingIntent = PendingIntent.getActivity(nowContext, 100, i, PendingIntent.FLAG_UPDATE_CURRENT);


5、设置Notification在通知栏里的样式
(1)系统默认样式
//API 11以下:
note.setLatestEventInfo(nowContext, "take me to your heart", "Micheal learn to rock", pendingIntent);

//API 16及以上,build()方法要求API 16及以上

//一会API 11以上,一会API16以上,我也很想知道Android的API是怎么设计的
note = builder.setContentIntent(pendingIntent).setContentTitle("title").setContentText("text").build();

(2)自定义样式:

自定义样式,就是让Notification在通知栏显示成自定义的xml布局
应当注意的是,Notification的自定义样式,只支持以下可视组件:
FrameLayout, LinearLayout, RelativeLayout
TextView, Button, AnalogClock, ImageView, ImageButton, Chronometer, ProgressBar

RemoteView view = new RemoteView(nowActivity.getPackageName(), R.layout.note_layout);
//API 11以下
note.contentView = view;
note.contentIntent = pendingIntent;
//API 16及以上,又是build()方法导致的,汗。。
note = builder.setContent(view).setContentIntent(pendingIntent).build();

这个步骤里有一个很值得注意的地方:pendingIntent被设置为note的contentIntent的值,就意味着点击了这个通知才会触发该Intent。

那么如果只是想让自定义布局里的某个按钮触发呢?比如说,弄了一个音乐播放器,Service负责播放音乐,Notification显示当前播放进度和一些简单的暂停按钮、上一首、下一首按钮,让用户不用再打开界面就可以通过Notification上的按钮操纵音乐播放。

假设说想让自定义布局里的一个id为R.id.button1的按钮来触发这个Intent,可以如下操作:

view.setOnClickPendingIntent(R.id.button1, pendingIntent);//在上面创建RemoteView实例后加上这句

然后注意,pendingIntent已经绑定到按钮上了,上面Notificatiion实例中,设置contentIntent的语句要去掉。


6、发布该通知,第一个参数为该notification的ID
noteMng.notify(10, note);


参考资料:Android技巧小结之新旧版本Notification



关于PendingIntent.FLAG_UPDATE_CURRENT使用:

对于相同action和category的intent对象,只更新他的extra值。

参考资料: android PendingIntent.getBroadcast 之坑