android进阶学习

Notification 通知栏

2019-04-03  本文已影响228人  Android_冯星

知识点

下面的都是废话 不必看了 官网有中文文档 说的很清楚

直接贴代码

版本25 这个版本不需要兼容8.0

默认通知

   /**
     * 默认样式的通知栏
     *
     * @param context
     * @param builder
     * @return
     */
    public NotificationCompat.Builder defaultNotify(Context context, NotificationCompat.Builder builder) {

        builder.setContentTitle("梦里挑灯看剑")
                .setContentText("江山如此多娇,引无数英雄竞折腰")
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))// 右侧显示大图标
                .setSmallIcon(R.drawable.test_baseline_school_black_24)
                .setWhen(System.currentTimeMillis())
                .setShowWhen(true)//显示时间 默认true
                .setDefaults(NotificationCompat.DEFAULT_ALL)//默认提示 铃声 震动
                .setPriority(NotificationCompat.PRIORITY_MAX)//设置优先级 和默认提示 搭配使用 可实现 悬浮提示效果 
                .setContentIntent(getTaskStackPending())
                //.setContentInfo("ContentInfo")
                //.setNumber(5)
                .setOngoing(true)//true不可以滑动删除 false 可以滑动删除
                .setAutoCancel(true)
        ;
        return builder;
    }

进度条通知


    /**
     * 进度条通知栏
     *
     * @param builder
     * @return
     */
    public NotificationCompat.Builder progressNotify(final NotificationCompat.Builder builder) {
        builder.setContentTitle("正在下载:")
                .setAutoCancel(false)
                .setOngoing(true)
                .setShowWhen(false)//显示时间 默认true
                .setDefaults(NotificationCompat.DEFAULT_ALL)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
                .setOnlyAlertOnce(true)
                .setSmallIcon(R.drawable.test_baseline_school_black_24);

        new Thread() {
            @Override
            public void run() {
                int progress = 0;

                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    progress += 10;
                    builder.setProgress(100, progress, false);
                    builder.setContentTitle("正在下载:" + progress + "%");
                    builder.setContentInfo(progress + "%");
                    mNotifyManager.notify(500, builder.build());
                }
                builder.setContentTitle("下载完成:");
                mNotifyManager.notify(500, builder.build());
                //mNotifyManager.cancel(500);

            }
        }.start();
        return builder;
    }

bigTextStyle

public NotificationCompat.Builder bigTextStyleNotify(NotificationCompat.Builder builder) {
        NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle();

        bigTextStyle.bigText("Android4.1+之后出现几种折叠样式,均需要使用setStyle()方法设定 setStyle()传递一个NotificationCompat.Style对象,它是一个抽象类,Android为我们提供了三个实现类,用于显示不同的场景。Android4.1+之后出现几种折叠样式,均需要使用setStyle()方法设定 setStyle()传递一个NotificationCompat.Style对象,它是一个抽象类,Android为我们提供了三个实现类,用于显示不同的场景。Android4.1+之后出现几种折叠样式,均需要使用setStyle()方法设定 setStyle()传递一个NotificationCompat.Style对象,它是一个抽象类,Android为我们提供了三个实现类,用于显示不同的场景。");
        bigTextStyle.setBigContentTitle("折叠式:BigText"); //替换掉了 setContentTitle
        bigTextStyle.setSummaryText("摘要");
        return builder
                .setSmallIcon(R.drawable.test_baseline_school_black_24)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
                .setContentTitle("折叠式:BigText")
                .setContentText("对折叠样式的说明")
                .setStyle(bigTextStyle)
                .setWhen(System.currentTimeMillis())
                .setDefaults(NotificationCompat.DEFAULT_ALL)
                .setPriority(NotificationCompat.PRIORITY_MAX)
                .setContentIntent(getTaskStackPending())
                // .setOngoing(true)//true不可以滑动删除 false 可以滑动删除  使用这个属性 通知栏默认展开状态 说的不是很明白 可以自己试一下
                .setAutoCancel(true);
    }

inboxStyle

public NotificationCompat.Builder inboxStyleNotify(NotificationCompat.Builder builder) {
        return builder
                .setSmallIcon(R.drawable.test_baseline_school_black_24)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
                .setContentTitle("折叠式:Inbox")
                .setContentText("对折叠样式的说明")
                .setStyle(new NotificationCompat.InboxStyle()
                        .addLine("第一行数据")
                        .addLine("第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                        .addLine("第一行数据")
                )
                .setWhen(System.currentTimeMillis())
                .setDefaults(NotificationCompat.DEFAULT_ALL)
                .setPriority(NotificationCompat.PRIORITY_MAX)
                .setContentIntent(getTaskStackPending())
                //.setOngoing(true)//true不可以滑动删除 false 可以滑动删除  使用这个属性 通知栏默认展开状态 说的不是很明白 可以自己试一下
                .setAutoCancel(true);
    }

bigPictureStyle

public NotificationCompat.Builder bigPictureStyleNotify(NotificationCompat.Builder builder) {
        return builder
                .setSmallIcon(R.drawable.test_baseline_school_black_24)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
                .setContentTitle("折叠式:BigPicture")
                .setContentText("对折叠样式的说明")
                .setStyle(new NotificationCompat.BigPictureStyle()
                        .bigPicture(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
                )
                .setWhen(System.currentTimeMillis())
                .setDefaults(NotificationCompat.DEFAULT_ALL)
                .setPriority(NotificationCompat.PRIORITY_MAX)
                .setContentIntent(getTaskStackPending())
                // .setOngoing(true)//true不可以滑动删除 false 可以滑动删除  使用这个属性 通知栏默认展开状态 说的不是很明白 可以自己试一下
                .setAutoCancel(true);
    }

自定义大图 setCustomBigContentView 可理解为可折叠

 public NotificationCompat.Builder customBigNotify(NotificationCompat.Builder builder) {

        RemoteViews views = new RemoteViews(getPackageName(), R.layout.test_custom_remote_view_dj);


        views.setOnClickPendingIntent(R.id.test_iv_large_img, getPendingIntent("onClickLargeImage"));
        views.setOnClickPendingIntent(R.id.test_iv_src_right, getPendingIntent("onClickRightImage"));

        views.setOnClickPendingIntent(R.id.test_iv_src, getPendingIntent("onClickLeftImage"));
        views.setOnClickPendingIntent(R.id.test_tv_title, getPendingIntent("onClickTextTitle"));

        return builder
                .setSmallIcon(R.drawable.test_baseline_school_black_24)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
                .setContentTitle("自定义")
                .setContentText("RemoteViews")
                .setWhen(System.currentTimeMillis())
                .setDefaults(NotificationCompat.DEFAULT_ALL)
                .setPriority(NotificationCompat.PRIORITY_MAX)
                .setContentIntent(getTaskStackPending())
                .setCustomBigContentView(views)
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                .setOngoing(true)//true不可以滑动删除 false 可以滑动删除  使用这个属性 通知栏默认展开状态 说的不是很明白 可以自己试一下
                .setAutoCancel(true);
    }

setCustomContentView 不可折叠

public NotificationCompat.Builder customNotify(NotificationCompat.Builder builder) {

        RemoteViews views = new RemoteViews(getPackageName(), R.layout.test_custom_remote_view_dj);

        /**
         * 加入点击事件  setAutoCancel 无效
         */
//        views.setOnClickPendingIntent(R.id.test_iv_large_img,getPendingIntent("onClickLargeImage"));
//        views.setOnClickPendingIntent(R.id.test_iv_src_right,getPendingIntent("onClickRightImage"));
//
//        views.setOnClickPendingIntent(R.id.test_iv_src,getPendingIntent("onClickLeftImage"));
//        views.setOnClickPendingIntent(R.id.test_tv_title,getPendingIntent("onClickTextTitle"));

        return builder
                .setSmallIcon(R.drawable.test_baseline_school_black_24)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
                .setContentTitle("自定义")
                .setContentText("RemoteViews")
                .setWhen(System.currentTimeMillis())
                .setDefaults(NotificationCompat.DEFAULT_ALL)
                .setPriority(NotificationCompat.PRIORITY_MAX)
                .setContentIntent(getTaskStackPending())
                .setCustomContentView(views)
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)//锁屏通知
                .setOngoing(true)//true不可以滑动删除 false 可以滑动删除  使用这个属性 通知栏默认展开状态 说的不是很明白 可以自己试一下
                .setAutoCancel(true);
    }

调用方式

 mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        mBuilder = new NotificationCompat.Builder(context);


        findViewById(R.id.app_test_btn_send_notify).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                new Thread() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        //showProgressNotify();
                        showNotify();


                        mNotifyManager.notify(id++, defaultNotify(context, mBuilder).build());

                        progressNotify(mBuilder);

                        mNotifyManager.notify(id++, bigTextStyleNotify(mBuilder).build());

                        mNotifyManager.notify(id++, inboxStyleNotify(mBuilder).build());

                        //mNotifyManager.notify(id++, bigPictureStyleNotify(mBuilder).build());

                        //mNotifyManager.notify(id++, customBigNotify(mBuilder).build());

                        mNotifyManager.notify(id++, customNotify(mBuilder).build());


                    }
                }.start();
            }

        });
public PendingIntent getTaskStackPending() {
        //创建 Intent 以启动 Activity。
        Intent resultIntent = new Intent(this, TestReceiveActivity.class);
        //创建堆栈生成器
        TaskStackBuilder builder = TaskStackBuilder.create(this);
        //将返回栈添加到堆栈生成器。 对于在清单文件中所定义层次结构内的每个 Activity,返回栈均包含可启动 Activity 的 Intent 对象。此方法还会添加一些可在全新任务中启动堆栈的标志。
        builder.addParentStack(TestReceiveActivity.class);
        builder.addNextIntent(resultIntent);//添加可从通知中启动 Activity 的 Intent。 将在第一步中创建的 Intent 作为 addNextIntent() 的参数传递
        /**
         * 如需,请通过调用 TaskStackBuilder.editIntentAt() 向堆栈中的 Intent 对象添加参数。有时,需要确保目标 Activity 在用户使用“返回”导航回它时会显示有意义的数据。
         */
        //通过调用 getPendingIntent() 获得此返回栈的 PendingIntent。 然后,您可以使用此 PendingIntent 作为 setContentIntent() 的参数。
        return builder.getPendingIntent(200, PendingIntent.FLAG_UPDATE_CURRENT);
    }


    public PendingIntent getPendingIntent(Context context, int requestCode, Intent intent) {
        return PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }


 private PendingIntent getPendingIntent(String action) {
        Intent intent = new Intent(this, TestReceiveActivity.class);
        intent.setAction(action);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 200, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        /**
         FLAG_ONE_SHOT 表示返回的PendingIntent仅能执行一次,执行完后自动取消
         FLAG_NO_CREATE 表示如果描述的PendingIntent不存在,并不创建相应的PendingIntent,而是返回NULL
         FLAG_CANCEL_CURRENT 表示相应的PendingIntent已经存在,则取消前者,然后创建新的PendingIntent, 这个有利于数据保持为最新的,可以用于即时通信的通信场景
         FLAG_UPDATE_CURRENT 表示更新的PendingIntent
         */
        return pendingIntent;
    }

配置TaskStackBuilder

<application
        android:allowBackup="true"
        android:icon="@mipmap/test_ic_launcher"
        android:label="@string/test_app_name"
        android:roundIcon="@mipmap/test_ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/test_AppTheme">
        <activity android:name=".TestPluginMainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".TestNotificationActivity" />

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

    </application>

WindowManager

简单实现

public class TestWindowService extends Service {


    private static final String TAG = "TestWindowService";
    private WindowManager.LayoutParams params;
    private WindowManager windowManager;
    private View view;
    private int startX;
    private int startY;
    private int endX;
    private int endY;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        createFloatView();
        initWindow();
        addWindowView2Window();
        initClick();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    private void initWindow() {
        windowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);

        params = new WindowManager.LayoutParams();

        // 更多type:https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#TYPE_PHONE
        params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;

        params.format = PixelFormat.TRANSPARENT;

        params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
//                |WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
//                        |WindowManager.LayoutParams.FLAG_FULLSCREEN
        ;

        // 设置通知栏的长和宽
//        params.width = windowManager.getDefaultDisplay().getWidth();
//        params.height = 200;

        params.width = WindowManager.LayoutParams.MATCH_PARENT;
        params.height = (int) (200 * getResources().getDisplayMetrics().density + 0.5);
        params.gravity = Gravity.LEFT | Gravity.TOP;

    }

    private void createFloatView() {
        view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.test_custom_remote_view_dj, null);
        int height = view.getHeight();
    }

    private void addWindowView2Window() {
        windowManager.addView(view, params);
    }

    private void initClick() {
        view.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        startX = (int) event.getRawX();
                        startY = (int) event.getRawY();

                        Log.d(TAG, "getRawX: " + startX + "  getX() =  " + event.getX());
                        Log.d(TAG, "getRawY: " + startY + "  getY() =  " + event.getY());
                        //getRawX是触摸位置相对于屏幕的坐标,getX是相对于父控件的坐标
                        break;
                    case MotionEvent.ACTION_MOVE:
                        Log.d(TAG, "onTouch: move");
                        endX = (int) event.getRawX();
                        endY = (int) event.getRawY();

                        params.x = (int) (event.getRawX() - view.getMeasuredWidth() / 2);
                        params.y = (int) (event.getRawY() - view.getMeasuredHeight() / 2);

                        windowManager.updateViewLayout(view, params);
                        return true;
                    case MotionEvent.ACTION_UP:
                        if (needIntercept()) {
                            return true;
                        }
                        break;

                    case MotionEvent.ACTION_CANCEL:
                        break;
                }
                return false;
            }
        });
    }

    private boolean needIntercept() {
        if (Math.abs(startX - endX) > 30 || Math.abs(startY - endY) > 30) {
            return true;
        }
        return false;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (windowManager != null) {
            windowManager.removeView(view);
        }
        view = null;
    }

现在我们把版本改成8.0以上

//统一编译版本
ext {
    buildToolsVersion = '28.0.3'
    compileSdkVersion = 28
    minSdkVersion = 16
    targetSdkVersion = 28
    versionCode = 1
    versionName = "1.0"
    //javaVersion = JavaVersion.VERSION_1_8
    supportLibraryVersion = '28.0.0'
}

windowmManager 问题

Unable to create service com.component.fx.plugin_test.TestWindowService: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@7a19d70 -- permission denied for window type 2010

    Unable to add window android.view.ViewRootImpl$W@7a19d70 -- permission denied for window type 2010
原因

使用SYSTEM_ALERT_WINDOW权限的应用程序无法再使用以下窗口类型在其他应用程序和系统窗口上方显示警报窗口:

TYPE_PHONE
TYPE_PRIORITY_PHONE
TYPE_SYSTEM_ALERT
TYPE_SYSTEM_OVERLAY
TYPE_SYSTEM_ERROR

相反,应用必须使用名为TYPE_APPLICATION_OVERLAY的新窗口类型。

点击这个寻找答案

Android 8.0 行为变更

修改的代码

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
            params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
        }


    /**
     * 创建一个Channel类型
     */
    @TargetApi(Build.VERSION_CODES.O)
    public static void createChannel() {

        String channelName = "聊天消息";
        int importance = NotificationManager.IMPORTANCE_MAX;
        setChannel(CHAT_ChANNEL_ID, channelName, importance);

        channelName = "新闻";
        importance = NotificationManager.IMPORTANCE_DEFAULT;
        setChannel(NEWS_ChANNEL_ID, channelName, importance);
    }


    /**
     * 创建Channel类型
     *
     * @param id
     * @param name
     * @param importance
     */
    @TargetApi(Build.VERSION_CODES.O)
    private static void setChannel(String id, String name, int importance) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManager nm = (NotificationManager) BaseApplication.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE);
            if (nm == null) {
                return;
            }
            NotificationChannel channel = new NotificationChannel(id, name, importance);
            channel.setShowBadge(true);
            nm.createNotificationChannel(channel);
        }
    }





    /**
     * 判断 是否关闭了通知
     * <p>
     * 是否允许通知
     *
     * @param context
     * @return true 可用 false 不可用
     */
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static boolean isNotifyEnable(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            ///< 8.0手机以上
            NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            Log.d("feng", "mNm: "+notificationManager);
            if (notificationManager.getImportance() == NotificationManager.IMPORTANCE_NONE) {
                return false;
            }
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            AppOpsManager opsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
            ApplicationInfo info = context.getApplicationInfo();
            String packageName = context.getPackageName();
            int uid = info.uid;
            try {
                Class<?> appOpsClass = Class.forName(AppOpsManager.class.getName());
                Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class);
                Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);
                int value = (Integer) opPostNotificationValue.get(Integer.class);
                return ((Integer) checkOpNoThrowMethod.invoke(opsManager, value, uid, packageName) == AppOpsManager.MODE_ALLOWED);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return true;

    }


    /**
     * 判断channel是否可用
     *
     * @param channelId
     * @return true 可用  false 不可用
     */
    public static boolean isChannelEnable(String channelId) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManager nm = (NotificationManager) BaseApplication.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE);
            NotificationChannel channel = nm.getNotificationChannel(channelId);
            return !(channel.getImportance() == NotificationManager.IMPORTANCE_NONE);
        }
        return true;
    }


    /**
     * 如果用户关闭了Channel通道可以根据这个方法跳转到设置页面
     *
     * @param channelId
     */
    @TargetApi(Build.VERSION_CODES.O)
    public static void openNotifyChannel(String channelId) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManager nm = (NotificationManager) BaseApplication.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE);
            Log.d("feng", "mNm: openNotifyChannel "+nm);
            NotificationChannel channel = nm.getNotificationChannel(channelId);
            if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
                Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.putExtra(Settings.EXTRA_APP_PACKAGE, BaseApplication.getAppContext().getPackageName());
                intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel.getId());
                BaseApplication.getAppContext().startActivity(intent);
            }
        }
    }

defaultNotify8.0适配

image.png

元素:

  1. 标题 Title/Name

  2. 大图标 Icon/Photo

  3. 内容文字

  4. 内容信息 MESSAGE

  5. 小图标 Secondary Icon

  6. 通知的时间 Timestamp,默认为系统发出通知的时间,也可通过setWhen()来设置

自定义通知布局的可用高度取决于通知视图。普通视图布局限制为 64 dp,扩展视图布局限制为 256 dp。

Notification

通知是您可以在应用的常规 UI 外部向用户显示的消息。当您告知系统发出通知时,它将先以图标的形式显示在通知区域中。用户可以打开抽屉式通知栏查看通知的详细信息。 通知区域和抽屉式通知栏均是由系统控制的区域,用户可以随时查看。

一个最简单的通知栏。

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        builder.setContentText("今天中午吃什么?")
                .setSmallIcon(R.drawable.test_ic_launcher_background)
                .setContentTitle("我是标题");


        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        notificationManager.notify(100, builder.build());

这几行代码就可以显示出一个通知栏。

必需设置的通知内容

少一个都报错。

setContentIntent

现在我们加入意图:

.setContentIntent(getPendingIntent())//设置意图

获取一个PendiingIntent包含着点击之后的行为

private PendingIntent getPendingIntent() {
        Intent intent = new Intent(this, TestPluginMainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 200, intent, 0);
        return pendingIntent;
    }

其实Pendding就是Intent的包装,下面会说,我们的行为定义了打开一个Activity。

现在点击发送按钮,会发送一条通知,通知栏显示出我们发送的通知

findViewById(R.id.app_test_btn_send_notify).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                showNotify();
            }

        });

点击通知,触发定义的行为,跳转到TestPluginMainActivity类中。

请注意,现在没有对通知的消失做任何处理,所点点击通知,通知栏不会消失。

image.png

官方网站是这样获取pendingIntent

public PendingIntent getTaskStackPending(String action) {
        Intent resultIntent = new Intent(this, TestPluginMainActivity.class);
        TaskStackBuilder builder = TaskStackBuilder.create(this);
        builder.addParentStack(TestPluginMainActivity.class);
        builder.addNextIntent(resultIntent);
        return builder.getPendingIntent(200, PendingIntent.FLAG_UPDATE_CURRENT);
    }

行为是一样的,有个知识点TaskStackBuilder一会在说,先留意下。

只有一条通知?

在内容上在加入时间,点击发送 在发送一条, 会发现只是内容做了替换,但是还是只有一条消息。

这样可不行,做成这样,需求会打死我的。

其实很好解决,在发送通知的时候有个参数id

NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        notificationManager.notify(100, builder.build());

我这里写死了 是100,所以才会只有一条消息。

修改之后

notificationManager.notify(id++, builder.build());

效果

image.png image.png

发送的内容过多时,会自动折叠,展开后,显示每条数据。

setDeleteIntent

当通知被删除时触发。

.setDeleteIntent(getPendingIntent("onDelete"))//设置删除意图

可以在通知被删除时做一些行为。
稍微修改下getPendingIntent()

.setContentIntent(getPendingIntent("onClick"))//设置意图
.setDeleteIntent(getPendingIntent("onDelete"))//设置删除意图

发送时加入一个action,在接受端 打印这个action。

private PendingIntent getPendingIntent(String action) {
        Intent intent = new Intent(this, TestPluginMainActivity.class);
        intent.setAction(action);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 200, intent, 0);
        return pendingIntent;
    }

可以发现 点击通知栏时,在TestPluginMainActivity类,toast弹出onClick ,删除通知时,弹出onDelete。

.setPriority() //设置优先级

其它flag

提醒标志符成员:

Notification.FLAG_SHOW_LIGHTS
//三色灯提醒,在使用三色灯提醒时候必须加该标志符

setDefaults 需要的flags

震动

setDefaults 和 setVibrate 如果都设置 setDefaults生效,setVibrate不生效。

铃声

三色灯

setOngoing(boolean ongoing)

设置为ture,表示它为一个正在进行的通知。他们通常是用来表示 一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载, 同步操作,主动网络连接)

setProgress()

max:进度条最大数值 、progress:当前进度、indeterminate:表示进度是否不确定,true为不确定,如下所示 ,false为确定 如下所示

image.png image.png

功能:设置带进度条的通知,可以在下载中使用

public void showProgressNotify() {
        mNotifyManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mBuilder = new NotificationCompat.Builder(this);
        mBuilder.setContentTitle("Picture Download")
                .setContentText("Download in progress")
                .setSmallIcon(R.drawable.test_ic_launcher_background);
// Start a lengthy operation in a background thread
        new Thread(
                new Runnable() {
                    @SuppressLint("LongLogTag")
                    @Override
                    public void run() {
                        int incr;
                        // Do the "lengthy" operation 20 times
                        for (incr = 0; incr <= 100; incr += 5) {
                            // Sets the progress indicator to a max value, the
                            // current completion percentage, and "determinate"
                            // state
                            mBuilder.setProgress(100, incr, true);
                            // Displays the progress bar for the first time.
                            mNotifyManager.notify(0, mBuilder.build());
                            // Sleeps the thread, simulating an operation
                            // that takes time
                            try {
                                // Sleep for 5 seconds
                                Thread.sleep(5 * 1000);
                            } catch (InterruptedException e) {
                                Log.d(TAG, "sleep failure");
                            }
                        }
                        // When the loop is finished, updates the notification
                        mBuilder.setContentText("Download complete")
                                // Removes the progress bar
                                .setProgress(0, 0, false);
                        mNotifyManager.notify(id++, mBuilder.build());
                    }
                }
// Starts the thread by calling the run() method in its Runnable
        ).start();
    }

setTicker

在 api 21 后不再显示,仅用于辅助服务。

builder.setTicker("this is ticker");

PendingIntent

PendingIntent 是一种特殊的 Intent ,字面意思可以解释为延迟的 Intent ,用于在某个事件结束后执行特定的 Action

PendingIntent 是 Android 系统管理并持有的用于描述和获取原始数据的对象的标志(引用)。也就是说,即便创建该PendingIntent对象的进程被杀死了,这个PendingItent对象在其他进程中还是可用的。 日常使用中的短信、闹钟等都用到了 PendingIntent。

//获取一个用于启动 Activity 的 PendingIntent 对象

public static PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags);

//获取一个用于启动 Service 的 PendingIntent 对象

public static PendingIntent getService(Context context, int requestCode, Intent intent, int flags);


//获取一个用于向 BroadcastReceiver 广播的 PendingIntent 对象

public static PendingIntent getBroadcast(Context context, int requestCode, Intent intent, int flags)
Intent intent = new Intent(this, TestReceiveActivity.class);
        intent.setAction(action);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 200, intent, FLAG_CANCEL_CURRENT);
Intent和PendingIntent的区别

TaskStackBuilder

有三个界面 A主界面,B发送通知栏界面,C 通知栏跳转界面。
现在 我需要 进入A界面,在跳转B界面,发送一个通知栏,点击通知栏进入C界面,注意 现在我们在C界面,如果点击返回按钮,如何返回到A界面?

设置特殊 Activity PendingIntent

浮动通知

实现的方法有两种:

  1. 通知拥有高优先级而且使用了铃声和震动。
  2. setFullScreenIntent(),如以下例子:

锁定屏幕通知

RemoteViews

Notification的自定义布局是RemoteViews,和其他RemoteViews一样,在自定义视图布局文件中,仅支持FrameLayout、LinearLayout、RelativeLayout三种布局控件和AnalogClock、Chronometer、Button、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView和AdapterViewFlipper这些显示控件,不支持这些类的子类或Android提供的其他控件。否则会引起ClassNotFoundException异常

image.png image.png
上一篇 下一篇

猜你喜欢

热点阅读