Android常用UI之Notification

转载请注明出处:http://blog.csdn.net/h_zhang/article/details/51114733

通知(Notification)是Android中一个比较有特色的功能,由于受到用户的认可和喜爱,IOS后来也加入了类似的功能。那么本篇文章就对Android Notification的使用方法做一个详细说明。Notification实际上是一则消息,不过这个消息显示在应用程序UI界面之外。也即是说,当你发出一条通知,它首先会在手机最上方的状态栏显示一个通知图标,下拉状态栏后可以看到通知详细内容。


创建一个最简单的通知

创建一个通知,你需要首先创建Notification.Builder对象,语法如下:
Notification.Builder builder = new Notification.Builder(this)
其中,this是Context实例。
然后使用builder开始构建通知的外观,有三个内容必须要进行设置的,缺一不可。

  • 通知图标:由builder.setSmallIcon()设置
  • 通知标题:由builder.setContentTitle()设置
  • 通知内容:由builder.setContentText()设置

下表列出了Notification.Builder类中的其他一些常用方法:

方法定义方法说明
setAutoCancel(true)点击通知后,通知自动被销毁
setLargeIcon (Bitmap b)设置通知的大图标
setProgress (int max, int progress, boolean indeterminate)设置通知中显示进度条
setSound (Uri sound, AudioAttributes audioAttributes)设置通知发出后的音效
setVibrate (long[] pattern)设置通知发出后的震动效果
setLights (int argb, int onMs, int offMs)设置通知发出后的LED灯的闪烁效果
setContentIntent (PendingIntent intent)点击通知时触发的PendingIntent

接着就调用NotificationCompat.Builder.build()方法来创建出Notification实例。最后将创建出来的Notification实例传递给NotificationManager.notify()方法就可以弹出一条通知。

下面代码创建并显示了一个最简单的通知:

布局文件,activity_main.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="cn.hebut.notification.MainActivity"
    tools:showIn="@layout/activity_main">

    <Button
        android:id="@+id/id_notification"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Notification"
        android:onClick="notification"/>

</LinearLayout>

MainActivity.java :

public class MainActivity extends AppCompatActivity
{

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

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public void notification(View view)
    {
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        Notification.Builder builder =
                new Notification.Builder(this)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                        .setContentTitle("通知标题")
                        .setContentText("通知内容")
                        .setAutoCancel(true);

        manager.notify(0, builder.build());
    }
}

调用setAutoCancel(true)方法,保证在点击通知之后,通知自动被销毁。最后一行manager.notify(0, builder.build());用于发出一条通知。第一个参数是一个id,用于唯一标识一个通知;第二个参数就是一个Notificaton对象。下面贴一下程序运行效果:


这里写图片描述

当你去点击这条通知的时候不会有任何效果。不对啊,好像点击每条通知都会有反应的呀?其实,要想点击通知有反应,就得借助PendingIntent来实现。那么什么是PendingIntent呢?PendintIntent和Intent又有什么区别呢?从字面上来看PendingIntent是一个挂起的Intent,PendingIntent本质上也是一个Intent,不同的是,Intent更倾向于立即执行某个动作,而PendingIntent更倾向于在某个合适的时机去执行某个动作。也可以把PendingIntent理解为某个延迟执行的Intent。下面代码实现点击通知时弹出一个新的Activity。

点击通知弹出的Activity布局文件, content_notification.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:gravity="center"
              android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="hello world"
        android:textSize="22sp"/>

</LinearLayout>

对于MainActivity.java我就贴出有变化的代码,MainActivity.java:

public void notification(View view)
{
    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    Notification.Builder builder =
            new Notification.Builder(this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                    .setContentTitle("通知标题")
                    .setContentText("通知内容")
                    .setAutoCancel(true);

    Intent intent = new Intent(this, NotificationActivity.class);
    PendingIntent pi = PendingIntent.getActivity(this, 0, //
            intent, PendingIntent.FLAG_UPDATE_CURRENT);
    builder.setContentIntent(pi);

    manager.notify(0, builder.build());
}

前面代码没有变化。第13行,创建了一个Intent实例,这个Intent用于启动NotificationActivity;第14行,使用PendingIntent.getActivity()方法创建一个PendingIntent实例,第一个参数是Context对象;第二个参数是requestCode,一般传0就可以;第三个参数是一个Intent对象;第四个参数是flag,这里给PendingIntent.FLAG_UPDATE_CURRENT,当然还有别的flag,大家可以查阅相关文档。第16行,调用builder.setContentIntent(pi)方法将创建好的PendingIntent对象设置进去。下面是程序运行效果:


这里写图片描述


Activity from a notification

当用户点击通知启动一个Activity时,你就必须考虑到这个Activity用途是什么。根据需求的不同,Android给出了两种Activity:一种叫做Special Activity。由于本身的局限性,通知中无法展示大量的信息,所以需要借助Activity将信息进行显示。简单说,Special Activity仅仅是通知的延伸;令一种叫Regular Activity,将启动的Activity作为应用程序工作流中的一部分。这种Activity与应用程序是紧密耦合的,而不仅仅是通知的延伸。下面介绍这两种Activity的使用方法。

Special Activity

本文第一部分“创建一个最简单的通知”中,点击通知后弹出的Activity就是一个Special Activity。它的作用仅仅是通知的延伸,用于显示在通知中无法详细显示的信息。这种Activity在Manifest文件中注册的时候,一般需要做如下配置:

<activity
    android:name=".NotificationActivity"
    android:launchMode="singleTask"
    android:excludeFromRecents="true">
</activity>

android:launchMode="singleTask"表明该Activity在全局只有一个实例;android:excludeFromRecents="true"表明在最近列表中不显示该Activity。

Regular Activity

对于Regular Activity,需要按如下步骤进行创建:
1. 创建一个Intent,用于启动点击通知后弹出的Activity
2. 通过调用TaskStackBuilder.create()方法创建一个返回栈
3. 通过addParentStack()将返回栈添加都栈构建器中
4. 调用addNextIntent()并将第一步创建的Intent作为参数传入

最后在Manifest文件中注册该Activity时,需要指明Activity的层级关系:

<activity
    android:name=".NotificationActivity"
    android:parentActivityName=".MainActivity">
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value=".MainActivity"/>
</activity>

下面我写了一个示例,用于展示Regular Activity的用法:
MainActivity.java:

public class MainActivity extends AppCompatActivity
{

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

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public void notification(View view)
    {
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        Notification.Builder builder =
                new Notification.Builder(this)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                        .setContentTitle("通知标题")
                        .setContentText("通知内容")
                        .setAutoCancel(true);

        Intent intent = new Intent(this, NotificationActivity.class);
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addParentStack(NotificationActivity.class);
        stackBuilder.addNextIntent(intent);
        PendingIntent pi = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

        builder.setContentIntent(pi);

        manager.notify(0, builder.build());
    }
}

第25~27行,创建了一个返回栈,并把第24行创建的Intent对象添加到栈顶;第28行,利用stackBuilder.getPendingIntent()方法得到一个PendingIntent对象;第29行,将PendingIntent对象设置到builder中;最后调用manager.notify()发布该通知。

布局文件没有变,我就不贴了。

最后,在Manifest文件中注册该Activity:

<activity
    android:name=".NotificationActivity"
    android:parentActivityName=".MainActivity">
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value=".MainActivity"/>
</activity>

下面是程序运行效果:


这里写图片描述

可以看到,当我们退出通过点击通知产生的Activity后,并没有返回到Android桌面,而是返回到了应用程序的Activity中。


动态更新通知内容

前面发布一个通知,最终调用了manager.notify(0, builder.build())方法。这个方法第一个参数是通知ID。所以,你想更新通知内容,也是调用该方法,只要保证ID是你想要更新的通知即可。
下面代码片段展示了更新通知的用法:

public void notification(View view)
{
    final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    final Notification.Builder builder =
            new Notification.Builder(this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                    .setContentTitle("通知标题")
                    .setContentText("通知内容")
                    .setAutoCancel(true);

    manager.notify(0, builder.build());

    new Thread(new Runnable()
    {
        @Override
        public void run()
        {
            int num = 10;
            for(int i = 1; i <= num; i++)
            {
                builder.setContentText("通知内容" + i);
                manager.notify(0, builder.build());

                try
                {
                    Thread.sleep(1 * 1000);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }).start();

}

当调用manager.notify(0, builder.build())方法的时候,系统会先检查ID为0的通知是否存在。如果通知不存在就创建该通知,如果通知已经存在就对通知直接更新。

下图为程序运行效果:


这里写图片描述


在通知里显示进度条

现在很多APP都提供下载功能。比如常用的视频播放APP(优酷,土豆,爱奇艺),都支持视频下载功能。在视频下载的时候,这些APP也会发布一个通知,并在通知里显示当前视频下载的进度。下面就讲解一下如何在通知里显示进度条。

进度条分为两种,一种是确定性的,一种是不确定性的。当你能估计操作(比如,下载)的时长,你可以使用确定性进度条;当你无法估计操作的时长,就可以使用不确定性进行条。

在通知中显示进度条也非常方便,调用Notification.Builder类中的setProgress (int max, int progress, boolean indeterminate)方法即可。第一个参数是进度最大值,一般给100;第二个参数是当前进度;第三个参数指明是确定性进度条还是不确定性进度条;

当下载操作完成后,你需要向用户提示操作完成并移除进度条。移除进度条调用setProgress(0, 0, false)即可。下面给出示例:

MainActivity.java :

public class MainActivity extends AppCompatActivity
{

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

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public void notification(View view)
    {
        final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        final Notification.Builder builder =
                new Notification.Builder(this)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                        .setContentTitle("下载视频")
                        .setContentText("视频正在下载...");


        new Thread(new Runnable()
        {
            @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
            @Override
            public void run()
            {
                int progress;
                for (progress = 0; progress <= 100; progress += 10)
                {
                    //确定性进度条
                    builder.setProgress(100, progress, false);
                    manager.notify(0, builder.build());
                    try
                    {
                        Thread.sleep(1 * 1000);
                    } catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }

                //提示下载结束,并移除进度条
                builder.setContentText("下载完成")
                        .setProgress(0, 0, false);
                manager.notify(0, builder.build());
            }
        }).start();
    }
}

代码也很简单。开了一个子线程用于模拟下载操作,在子线程中通过调用builder.setProgress(100, progress, false)方法显示当前进度,然后调用manager.notify(0, builder.build())方法来发布该通知。最后,当下载操作完成,给出提示并从通知中移除进度条。

下图是程序运行效果:


这里写图片描述

那么,如果想要显示不确定性进度条只需要将上面代码第34行builder.setProgress(100, progress, false)修改为builder.setProgress(0, 0, true)即可。然后继续调用manager.notify(0, builder.build())方法来发布该通知。

程序运行效果如下所示:


这里写图片描述


OK,本篇文章到这就结束了。关于Android通知的用法,就先讲解这么多。通过对本文的学习,相信大家能够基本掌握通知的用法。谢谢大家观看~~~

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值