Android中的通知和自定义通知布局

Android中的通知(Notification)是Android中的重要一部分,应用程序通过通知来提醒用户或者向用户传达信息,下面让我们来看一下怎么在我们的程序中使用通知和自定义通知的布局。

首先我们来看一下怎么向通知栏中发送一个通知。由于各个版本的Android在通知方面都有一些改动,所以很难找到一个标准的创建及使用通知的方法,但是程序设计出来总归是给用户使用的,那么我们可以采用兼容性最好的那个API来创建通知:我们可以使用NotificationCompat 这个类来进行通知的创建及设置属性,具体步骤如下:

1、获取系统的通知管理服务,通过:

(NotificationManager)getSystemService(
Context.NOTIFICATION_SERVICE)

方法来获取,注意要强制转换类型。

2、创建我们需要的通知并且设置对应属性:

Notification notification = new NotificationCompat.Builder(this)
        .setContentTitle("通知1") // 创建通知的标题
        .setContentText("这是第一个通知") // 创建通知的内容
        .setSmallIcon(R.drawable.small_icon) // 创建通知的小图标                
        .setLargeIcon(BitmapFactory.
        decodeResource(getResources(),
        R.drawable.ic_launcher)) // 创建通知的大图标
        /*
         * 首先,无论是使用自定义视图还是系统提供的视图,上面4的属性一定要设置,不然这个通知显示不出来
         */

3、调用通知管理服务的notify方法发送通知

我们依然通过一个例子来看一下: 新建一个Android工程: activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/button1NotifyNotification"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送第一种通知" />
    <Button 
        android:id="@+id/button2NotifyNotification"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送第二种通知"/>

</LinearLayout>

布局中的两个按钮分别用来发送系统布局的通知和我们自定义布局的通知,接下来是我们自定义的通知布局,新建一个布局文件notification.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/notificationLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFAADD"
    android:orientation="horizontal" >

    <ImageView 
        android:id="@+id/notificationImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/music"/>
    <TextView 
        android:id="@+id/notificationTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="正在播放:"/>
    <Button
        android:id="@+id/notificationButton1" 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/pause" />
    <Button 
        android:id="@+id/notificatinoButton2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/next"/>

</LinearLayout>

这个布局中我们采用横向布局,用来模拟一个音乐播放器的横栏,两个按钮分别对应 播放/暂停,下一曲 。 那么接下来是MainActivity.java:

import java.io.File;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.support.v4.app.NotificationCompat;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.RemoteViews;

public class MainActivity extends Activity {

    private NotificationManager notificationManager = null;
    private Button button = null;
    private MyBroadcastReceiver myBroadcastReceiver = null;
    public static final String button1StateJudge = "button1StateJudge";

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

        notificationManager = (NotificationManager) 
                getSystemService(Context.NOTIFICATION_SERVICE); // 获取系统提供的通知管理服务

        button = (Button) findViewById(R.id.button1NotifyNotification);
        button.setOnClickListener(listener);
        button = (Button) findViewById(R.id.button2NotifyNotification);
        button.setOnClickListener(listener);

        init(); // 注册广播
    }

    private void init()
    {
        myBroadcastReceiver = new MyBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter(MyBroadcastReceiver.ACTION_1);
        intentFilter.addAction(MyBroadcastReceiver.ACTION_2);
        registerReceiver(myBroadcastReceiver, intentFilter);
    }

    private View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch(v.getId())
            {
            case R.id.button1NotifyNotification:
                notifyFirstNotification();
                break;
            case R.id.button2NotifyNotification:
                notifySecondNotification();
                break;
            }
        }
    };

    private void notifyFirstNotification()
    {
        Intent intent = new Intent(this, SecondActivity.class);
        /*
         * 调用PendingIntent的静态放法创建一个 PendingIntent对象用于点击通知之后执行的操作,
         * PendingIntent可以理解为延时的Intent,在这里即为点击通知之后执行的Intent
         * 这里调用getActivity(Context context, int requestCode, Intent intent, int flag)方法
         * 表示这个PendingIntent对象启动的是Activity,类似的还有getService方法、getBroadcast方法
         */
        PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);

        Notification notification = new NotificationCompat.Builder(this)
        .setContentTitle("通知1") // 创建通知的标题
        .setContentText("这是第一个通知") // 创建通知的内容
        .setSmallIcon(R.drawable.small_icon) // 创建通知的小图标
        .setLargeIcon(BitmapFactory.decodeResource(getResources(),
                R.drawable.ic_launcher)) // 创建通知的大图标
        /*
         * 首先,无论你是使用自定义视图还是系统提供的视图,上面4的属性一定要设置,不然这个通知显示不出来
         */
        .setWhen(System.currentTimeMillis()) // 设定通知显示的时间
        .setContentIntent(pi) // 设定点击通知之后启动的内容,这个内容由方法中的参数:PendingIntent对象决定
        .setPriority(NotificationCompat.PRIORITY_MAX) // 设置通知的优先级
        .setAutoCancel(true) // 设置点击通知之后通知是否消失
        .setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg"))) // 设置声音
        /*
         * 设置震动,用一个 long 的数组来表示震动状态,这里表示的是先震动1秒、静止1秒、再震动1秒,这里以毫秒为单位
         * 如果要设置先震动1秒,然后停止0.5秒,再震动2秒则可设置数组为:long[]{1000, 500, 2000}。
         * 别忘了在AndroidManifest配置文件中申请震动的权限
         */
        .setVibrate(new long[]{1000, 0, 1000})
        /*
         * 设置手机的LED灯为蓝色并且灯亮2秒,熄灭1秒,达到灯闪烁的效果,不过这些效果在模拟器上是看不到的,
         * 需要将程序安装在真机上才能看到对应效果,如果不想设置这些通知提示效果,
         * 可以直接设置:setDefaults(Notification.DEFAULT_ALL);
         * 意味将通知的提示效果设置为系统的默认提示效果
         */
        .setLights(Color.BLUE, 2000, 1000)
        .build(); // 创建通知(每个通知必须要调用这个方法来创建)
        /*
         * 使用从系统服务获得的通知管理器发送通知,第一个参数是通知的id,不同的通知应该有不同的id,
         * 这样当我们要取消哪条通知的时候我们调用notificationManager(通知管理器).cancel(int id)
         * 方法并传入发送通知时的对应id就可以了。在这里如果我们要取消这条通知,
         * 我们调用notificationManager.cancel(1);就可以了
         * 第二个参数是要发送的通知对象
         */
        notificationManager.notify(1, notification); 
    }

    private void notifySecondNotification()
    {
        Intent button1I = new Intent("PressPauseOrPlayButton");

        PendingIntent button1PI = PendingIntent.getBroadcast(this, 0, button1I, 0);
        Intent button2I = new Intent("PressNextButton");
        PendingIntent button2PI = PendingIntent.getBroadcast(this, 0, button2I, 0);
        /*
         * 通知布局如果使用自定义布局文件中的话要通过RemoteViews类来实现,
         * 其实无论是使用系统提供的布局还是自定义布局,都是通过RemoteViews类实现,如果使用系统提供的布局,
         * 系统会默认提供一个RemoteViews对象。如果使用自定义布局的话这个RemoteViews对象需要我们自己创建,
         * 并且加入我们需要的对应的控件事件处理,然后通过setContent(RemoteViews remoteViews)方法传参实现
         */
        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.notification);
        /*
         * 对于自定义布局文件中的控件通过RemoteViews类的对象进行事件处理
         */
        remoteViews.setOnClickPendingIntent(R.id.notificationButton1, button1PI);
        remoteViews.setOnClickPendingIntent(R.id.notificatinoButton2, button2PI);

        Notification notification = new NotificationCompat.Builder(this)
        .setContentTitle("通知2") // 创建通知的标题
        .setContentText("这是第二个通知") // 创建通知的内容
        .setSmallIcon(R.drawable.small_icon) // 创建通知的小图标
        .setLargeIcon(BitmapFactory.decodeResource(getResources(),
                R.drawable.ic_launcher)) // 创建通知的大图标
        /*
         * 是使用自定义视图还是系统提供的视图,上面4的属性一定要设置,不然这个通知显示不出来
         */
        .setDefaults(Notification.DEFAULT_ALL)  // 设置通知提醒方式为系统默认的提醒方式
        .setContent(remoteViews) // 通过设置RemoteViews对象来设置通知的布局,这里我们设置为自定义布局
        .build(); // 创建通知(每个通知必须要调用这个方法来创建)

        notificationManager.notify(2, notification); // 发送通知

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();
        unregisterReceiver(myBroadcastReceiver); // 注销广播
    }
}

MainActivity.java的代码就有点多了,总体思路是对布局文件中的两个按钮进行事件处理,定义 notifyFirstNotification() 方法和 notifySecondNotification() 方法分别用于创建系统提供布局的通知和自定义布局的通知,并且发送通知。首先,notifyFirstNotification方法就是发送一个系统布局的通知,单击之后会启动一个Activity对象:SecondActivity.java,代码中有详细的注释,这里不再重复,下面给出SecondActivity.java的代码:

import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.TextView;

public class SecondActivity extends Activity {

    LinearLayout layout = null;
    TextView textView = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        layout = new LinearLayout(this);
        layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT));
        layout.setGravity(Gravity.CENTER_HORIZONTAL);
        layout.setOrientation(LinearLayout.VERTICAL);
        setContentView(layout);

        textView = new TextView(this);
        textView.setText("通过点击通知启动的Activity");
        layout.addView(textView, new LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT));


    }

}

这个Activity我们用的是代码来创建布局一个线性布局中包含一个TextView控件。别忘了在AndroidManifest.xml布局文件中注册SecondActivity:

<activity 
    android:name="SecondActivity"
    android:label="第二个Activity">
</activity>

我们接着来看notifySecondNotification方法,在这个方法中我们实现的是一个自定义布局的通知,我们注意到在onCreate方法中我们还动态注册了一个广播,如果对于广播不熟悉的小伙伴可以参考一下这篇博文: http://blog.csdn.net/hacker_zhidian/article/details/54773259 言归正传,这个广播干什么用的呢:在自定义通知布局中我们要对两个按钮进行事件处理,在自定义通知布局中,我们必须使用RemoteViews的对象来对布局文件中的两个按钮进行事件处理,而 RemoteViews的两个处理单击事件的方法都必须要传入PendingIntent 对象,PendingIntent对象必须通过Intent对象来构造(具体见代码注释),那么这样只能通过Activity、Broadcast、Service(它们都是通过Intent启动或者和Intent有关联)来响应按钮的单击事件。这样的话思路就清晰了,我们这里通过一个Broadcast来处理按钮单击事件,因此我们需要使用BroadcastReceiver对象来接收广播,那么接下来是MyBroadcastReceiver.java:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class MyBroadcastReceiver extends BroadcastReceiver {

    public static final String ACTION_1 = "PressPauseOrPlayButton";
    public static final String ACTION_2 = "PressNextButton";

    @Override
    public void onReceive(Context context, Intent intent)
    {
        String action = intent.getAction();
        String toastStr = "你点击了";
        if(action.equals(ACTION_1))
        {
            Toast.makeText(context, toastStr + "播放/暂停按钮", Toast.LENGTH_SHORT).show();
        }
        else if(action.equals(ACTION_2))
        {
            Toast.makeText(context, toastStr + "下一曲按钮", Toast.LENGTH_SHORT).show();
        }
    }
}

在这段代码中我们定义了一个类MyBroadcastReceiver继承于BroadCastReceiver,并且实现了它的抽象方法用于对按钮的点击进行相应的处理,这里只是简单地提示,值得注意的是:不应该在onReceive方法中进行耗时的操作,一般来说如果广播接收器的onReceive方法执行超过了10秒,系统就会认为这个应用没有响应。 Ok,下面是运行结果:

单击“发送第一种通知”按钮:

单击这个通知:

接下来单击“发送第二种通知”按钮:

这里图片是随便找的,不太美观,大家多多谅解。分别单击通知中的两个按钮:

Nice,我们成功的自定义了属于我们自己的通知

如果博客中有什么不正确的地方,还请多多指点 谢谢观看。。。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券