【Android】Notification的使用及无法更改largeIcon问题

1.Notification的使用

  Notification的创建使用建造者模式,通过Builder构造器来创建Notification对象,并通过NotificationManager来对Notification进行管理
  但是由于android各个版本对这个功能有部分的修改,因此我们最好使用support-v7库中提供的NotificationCompat类,使用这个类的Builder构造器来构建Notification就能解决不同版本android系统的兼容问题

//通过Context获取到NotificationManager 
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

//构建PendingIntent
//第一个参数为Context
//第二个参数为requestCode,类似于startActivityForResult()中的requestCode吧(不确定)
//第三个传入Intent,表示触发时要做的行为
//第四个参数则用于确定PendingIntent的模式,有FLAG_ONE_SHOT、FLAG_NO_CREATE 、FLAG_CANCEL_CURRENT、FLAG_UPDATE_CURRENT等4个值可选
Intent intent = new Intent(this, NofiticationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, FLAG_UPDATE_CURRENT);

//通过NotificationCompat.Builder(Context context)构建Notification,使用build()获取到Notification实例
Notification notification= new NotificationCompat.Builder(MainActivity.this)
                        .setLargeIcon(BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.icon_spring_festival_logo))
                        .setSmallIcon(R.mipmap.icon_main_app_small_logo)
                        .setContentTitle("通知")// 设置在下拉status
                        .setContentText("这是一条通知")// TextView中显示的详细内容
                        .setContentIntent(mPendingIntent) // 关联PendingIntent
                        .setNumber(pushBean.id) // 在TextView的右方显示的数字,可放大图片看,在最右侧。这个number同时也起到一个序列号的左右,如果多个触发多个通知(同一ID),可以指定显示哪一个
                        .setAutoCancel(true) //设置是否点击后通知自动消失,也可以手动调用manager.cancel(id),id对应后面每个通知所指定的id
                        //进阶功能
                        //.setSound(Uri.parse("android.resource://" + packageName + File.separator + R.raw.ring_6))
                        .setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg"))) //设置声音
                        .setVibrate(new long[]{0, 1000, 1000, 1000})//设置震动,手机静止时长-振动时长-静止时长-震动时长....(以此类推)
                        .setLights(Color.GREEN, 1000, 1000) //设置LED灯的颜色、亮起时长、暗去时长
                        //.setDefaults(android.support.v7.app.NotificationCompat.DEFAULT_ALL)  //设置默认模式,自动选择声音、震动、灯光
                        .build();
//发出通知
manager.notify(id, notification); //第一个参数为id,要保证每个通知所指定的id都是不同的

关于Notification的largeIcon无法更改的问题

  在项目中我需要通过后台传入的url来加载通知的消息栏图片,于是我的demo如下

package com.sfexpress.testnotificationloadpicure;

import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.NotificationCompat;
import android.view.View;
import android.widget.Button;

import rx.Subscriber;
import rx.functions.Func1;

public class MainActivity extends AppCompatActivity {

    private Button btn_show_notification;

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

        final String url = "http://b.hiphotos.baidu.com/zhidao/pic/item/a6efce1b9d16fdfafee0cfb5b68f8c5495ee7bd8.jpg";
        btn_show_notification = (Button) findViewById(R.id.show_notification);
        btn_show_notification.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                long when = System.currentTimeMillis();
                final NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);


                int requestCode = 1;
                try {
                    requestCode = (int) when;
                } catch (Exception e) {
                    //不处理
                }
                final Notification notification = new NotificationCompat.Builder(MainActivity.this)

                        //在这里设置默认的largeIcon
                        .setLargeIcon(BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.icon_spring_festival_logo))  

                        .setSmallIcon(R.mipmap.icon_main_app_small_logo)
                        .setContentTitle("通知")
                        .setContentText("这是一条通知")
                        .build();

                final int requestCodeInner = requestCode;
                rx.Observable.just(url)
                        .map(new Func1() {
                            @Override
                            public Bitmap call(String url) {
                                //根据url对图片进行加载,并裁剪为192 X 192的尺寸
                                ImageLoader imageLoader = ImageLoader.build(MainActivity.this);
                                return imageLoader.loadBitmap(url,192, 192);
                            }
                        })
                        .compose(RxUtils.applySchedulers())
                        .subscribe(new Subscriber() {
                            @Override
                            public void onCompleted() {
                                //空实现
                            }

                            @Override
                            public void onError(Throwable e) {
                                //空实现
                            }

                            @Override
                            public void onNext(Bitmap bitmap) {
                                if(bitmap != null){
                                    //将bitmap设置到notification当中
                                    notification.largeIcon = bitmap;
                                }
                                manager.notify(requestCodeInner, notification);
                            }
                        });

            }
        });
    }
}

  程序运行的结果是largeIcon仍然显示为我在构建notification时的默认icon,而不是通过网络url加载的icon。
  刚开始我以为是因为匿名内部类导致外部Notification对象必须定义为final而导致不可修改,但是我们知道final在修饰一个对象的时候只是会使这个对象始终指向同一个地址,而不会限制对象中成员变量的修改。
  因此我尝试对程序打断点,结果发现,在最后调用manager.notify()的时候,notification中的largeIcon实际上已经被替换为了新加载的bitmap,因此我猜测在Builder构建的时候设置LargeIcon会将其设置到一个map当中,在manager.notify()的时候会优先从map中进行取值,为空才会查询notification的largeIcon字段,因此这种方式无法成功加载网络图片,那么解决方案就有两种:

  • 第一种方案:在Builder构建notification的时候不设置largeIcon,但是这种方式不优雅
  • 第二种方案: Builder构建notification时不直接调用build获取Notificaition实例,而是在manager.notify()调用前再调用build()方法,下面使用这种方案
package com.sfexpress.testnotificationloadpicure;

import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.NotificationCompat;
import android.view.View;
import android.widget.Button;

import rx.Subscriber;
import rx.functions.Func1;

public class MainActivity extends AppCompatActivity {

    private Button btn_show_notification;

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

        final String url = "http://b.hiphotos.baidu.com/zhidao/pic/item/a6efce1b9d16fdfafee0cfb5b68f8c5495ee7bd8.jpg";
        btn_show_notification = (Button) findViewById(R.id.show_notification);
        btn_show_notification.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                long when = System.currentTimeMillis();
                final NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);


                int requestCode = 1;
                try {
                    requestCode = (int) when;
                } catch (Exception e) {
                    //不处理
                }

                //获取到Builder对象
                final NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this);
                //给Builder对象设置默认属性
                builder.setLargeIcon(BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.icon_spring_festival_logo))
                        .setSmallIcon(R.mipmap.icon_main_app_small_logo)
                        .setContentTitle("通知")// 设置在下拉status
                        .setContentText("这是一条通知")// TextView中显示的详细内容
                        .setWhen(when);


                final int requestCodeInner = requestCode;
                rx.Observable.just(url)
                        .map(new Func1() {
                            @Override
                            public Bitmap call(String url) {
                                ImageLoader imageLoader = ImageLoader.build(MainActivity.this);
                                return imageLoader.loadBitmap(url,192, 192);
                            }
                        })
                        .compose(RxUtils.applySchedulers())
                        .subscribe(new Subscriber() {
                            @Override
                            public void onCompleted() {
                                //空实现
                            }

                            @Override
                            public void onError(Throwable e) {
                                //空实现
                            }

                            @Override
                            public void onNext(Bitmap bitmap) {
                                if(bitmap != null){
                                    builder.setLargeIcon(bitmap);
                                }
                                //在notify()调用前通过builder方法获取Notification实例并作为参数传入notify()方法
                                manager.notify(requestCodeInner, builder.build());
                            }
                        });

            }
        });
    }
}

  以这种方案实现就能够更加轻松的将notificaiton的通用构造过程封装起来,仅返回一个Builder对象,然后通过操作Builder对象对Notification进行个性化设置

你可能感兴趣的:(【Android】Notification的使用及无法更改largeIcon问题)