android Foreground Service 前台服务/notification全局通知

  • 前言
  • 要素简介
    • 前台服务(Foreground Service)
    • 全局通知(notification)
  • 功能实现
    • 声明服务与获取权限
    • Notification 初始化
    • NotificationChannel 通知渠道
    • update
    • 移除通知
    • 启动服务
  • 完整AppService.java代码
  • 效果演示图
  • 结语

前言

我在设计一款自用的用于自我管理的app,为了增强自我反馈,我想要这个软件能够持续的显示我执行某一个事件所用的时间。并且为了使得软件不会被系统自动关闭,百般斟酌后我选了前台服务方案。

要素简介

前台服务(Foreground Service)

前台服务(Foreground Service)相比起后台服务(Service),拥有一个优势那就是在系统内存不足的时候不允许系统杀死的服务,并且在运行时需要能被用户所知,需要在状态栏创建一个通知来管理。

全局通知(notification)

全局通知(notification),常用于告知用户某些事件在某个事件发生,在发动时会在状态栏和通知栏都显示信息,用户可以点击信息进行某些功能的管理

功能实现

声明服务与获取权限

声明权限

 <!-- 通知权限 -->
<!--    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>--><!-- 前台权限权限 --><uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

声明service

<service android:name=".AppService"/>

在最新版本中notification已被启用,改为使用NotificationCompat
案例如下:

Notification 初始化

     registerNotificationChannel();notifyId = 0x975;//(int) System.currentTimeMillis();Intent nfIntent = new Intent(this, HostActivity.class);mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);mBuilder.setContentIntent(PendingIntent.getActivity(this, 0, nfIntent, 0)) // 设置PendingIntent.setLargeIcon(BitmapFactory.decodeResource(this.getResources(),R.mipmap.ic_launcher)) // 设置下拉列表中的图标(大图标).setContentTitle("下拉列表中的Title") // 设置下拉列表里的标题.setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标.setContentText("要显示的内容") // 设置上下文内容.setWhen(System.currentTimeMillis()) // 设置该通知发生的时间//.setPriority(Notification.PRIORITY_MIN) //设定为最低优先级.setPriority(Notification.PRIORITY_HIGH) //设定为最高优先级.setOngoing(true)//设定为点击后不消失;if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {mBuilder.setContentTitle(getResources().getString(R.string.app_name));}//notificationManager.notify(notifyId, mBuilder.build());startForeground(notifyId, mBuilder.build());
  1. 其中notifyId是通知的唯一标识当通知的notify一致时,再发布通知则会覆盖原有的通知内容。这个方法也常用于实时更新通知内容
  2. 前台服务发布通知的方法为startForeground,使用方法和notificationManager.notify类似,不需要另外再注册Manager。

NotificationChannel 通知渠道

而在高版本的安卓中,还需要注册通知渠道:

     /*** 注册通知通道*/private void registerNotificationChannel() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);NotificationChannel notificationChannel = notificationManager.getNotificationChannel(CHANNEL_ID);if (notificationChannel == null) {NotificationChannel channel = new NotificationChannel(CHANNEL_ID,CHANNEL_NAME,NotificationManager.IMPORTANCE_HIGH//NotificationManager.IMPORTANCE_MIN);//NotificationManager.IMPORTANCE_HIGH //NONE 为不弹出横幅,HIGH为弹出横幅;//是否在桌面icon右上角展示小红点channel.enableLights(true);//小红点颜色channel.setLightColor(Color.RED);//通知显示channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);//是否在久按桌面图标时显示此渠道的通知channel.setShowBadge(true);notificationManager.createNotificationChannel(channel);}}}

update

用于刷新通知内容

/*** 主自定义线程启动函数*/private void startMyThread() {stopThread=false;Thread dateFlash=new Thread() {@Overridepublic void run() {super.run();while (!stopThread) {try {Thread.sleep(1000);//每1s刷新一次} catch (InterruptedException e) {e.printStackTrace();}updateUI();startForeground(notifyId, mBuilder.build());}}};dateFlash.start();}

移除通知

stopForeground(true);
//true表示移除

启动服务

启动前台服务的方法和一般方法相同

    /*** 启动前台服务*/private  void show2(){Intent mIntent=new Intent(MainActivity.this,AppService.class) ;//        mIntent.putExtra("startId",now_Event.getEvent_id());
//        mIntent.putExtra("startHour",now_Event.getStart_hour());
//        mIntent.putExtra("startMin",now_Event.getStart_min());startService(mIntent);//直接启动服务方式启动//mAppService.startForeground(110, notification);// 开始前台服务}

完整AppService.java代码

package com.example.myapplication;import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;import java.util.Calendar;import androidx.core.app.NotificationCompat;public class AppService extends Service {public static final String CHANNEL_ID = " com.example.myapplication.AppService";public static final String CHANNEL_NAME = " com.example.myapplication";@Overridepublic IBinder onBind(Intent intent) {return null;}private static final String TAG = AppService.class.getSimpleName();@Overridepublic void onCreate() {super.onCreate();Log.d(TAG, "onCreate()");registerNotificationChannel();notifyId = 0x975;//(int) System.currentTimeMillis();Intent nfIntent = new Intent(this, HostActivity.class);mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);mBuilder.setContentIntent(PendingIntent.getActivity(this, 0, nfIntent, 0)) // 设置PendingIntent.setLargeIcon(BitmapFactory.decodeResource(this.getResources(),R.mipmap.ic_launcher)) // 设置下拉列表中的图标(大图标).setContentTitle("下拉列表中的Title") // 设置下拉列表里的标题.setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标.setContentText("要显示的内容") // 设置上下文内容.setWhen(System.currentTimeMillis()) // 设置该通知发生的时间//.setPriority(Notification.PRIORITY_MIN) //设定为最低优先级.setPriority(Notification.PRIORITY_HIGH) //设定为最低优先级.setOngoing(true)//设定为点击后不消失;if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {mBuilder.setContentTitle(getResources().getString(R.string.app_name));}//notificationManager.notify(notifyId, mBuilder.build());startForeground(notifyId, mBuilder.build());startMyThread();            //启动主线程}@Overridepublic void onDestroy() {Log.d(TAG, "onDestroy()");stopForeground(true);super.onDestroy();}/*** 自定义变量群*/boolean stopThread=false;NotificationCompat.Builder mBuilder;NotificationManager notificationManager;int notifyId;int test_cnt=0;Calendar calendar = Calendar.getInstance();/*** 主自定义线程启动函数*/private void startMyThread() {stopThread=false;Thread dateFlash=new Thread() {@Overridepublic void run() {super.run();while (!stopThread) {try {Thread.sleep(1000);//每1s刷新一次} catch (InterruptedException e) {e.printStackTrace();}updateUI();startForeground(notifyId, mBuilder.build());}}};dateFlash.start();}/*** 注册通知通道*/private void registerNotificationChannel() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);NotificationChannel notificationChannel = notificationManager.getNotificationChannel(CHANNEL_ID);if (notificationChannel == null) {NotificationChannel channel = new NotificationChannel(CHANNEL_ID,CHANNEL_NAME,NotificationManager.IMPORTANCE_HIGH//NotificationManager.IMPORTANCE_MIN);//NotificationManager.IMPORTANCE_HIGH //NONE 为不弹出横幅,HIGH为弹出横幅;//是否在桌面icon右上角展示小红点channel.enableLights(true);//小红点颜色channel.setLightColor(Color.RED);//通知显示channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);//是否在久按桌面图标时显示此渠道的通知channel.setShowBadge(true);notificationManager.createNotificationChannel(channel);}}}private void updateUI() {/*** 显示当前任务和执行时间*/mEvent now_Event = MainActivity.now_Event;String event_time = "";//Log.i(TAG, "--------flash--------");if (now_Event == null)return;String event_name = "";switch (now_Event.getEvent_id()) {case 10001:event_name = "休眠";break;case 10002:event_name = "恰饭";break;case 10003:event_name = "其他生理需求";break;case 10004:event_name ="开发项目 ";break;case 10005:event_name ="巩固技术 ";break;case 10006:event_name ="其他工作任务 ";break;case 10007:event_name ="满足求知欲 ";break;case 10008:event_name ="满足好胜心 ";break;case 10009:event_name="休闲娱乐 ";break;case 10010:event_name="学习";break;case 10011:event_name="锻炼";break;case 10012:event_name="自我提升 ";break;}calendar = Calendar.getInstance();int n_hour = calendar.get(Calendar.HOUR_OF_DAY);int n_minute = calendar.get(Calendar.MINUTE);int show_hour;int show_minute;int set_hour = now_Event.getStart_hour();int set_minute = now_Event.getStart_min();if (n_minute < set_minute) {show_hour = n_hour - set_hour - 1;show_minute = n_minute + 60 - set_minute;} else {show_hour = n_hour - set_hour;show_minute = n_minute - set_minute;}event_time = ""+show_hour + "小时" + show_minute+"分钟";//记录时间mBuilder.setContentTitle(event_name); // 设置下拉列表里的标题mBuilder.setContentText("执行了:"+ event_time);// 设置上下文内容}}

效果演示图

某个正在执行的任务:

通知栏状态显示:

完整工程下载(待完成)

结语

完整的APP还在制作中,但是这一部分功能还是成功实现了。
在实现的过程中遇到了一个难题:无法隐藏或者显示横幅
生成通知时会产生一个横幅,有时候又不生成。我期望是不生成的,期望通过app内设置能够实现,但是目前设置均无效,渴望路过的大神能够解惑(〃‘▽’〃)

android Foreground Service 前台服务/notification全局通知相关推荐

  1. Android Foreground Service (前台服务)-by:nixs

    一.如何保活后台服务 在Android Services (后台服务) 里面,我们了解了Android四大组件之一的Service,知道如何使用后台服务进行来完成一些特定的任务.但是后台服务在系统内存 ...

  2. Foreground Service前台服务

    Foreground Service前台服务 介绍前台服务 模拟播放器前台服务发送通知 介绍前台服务 前台服务是那些被认为用户知道(用户所认可的)且在系统内存不足的时候不允许系统杀死的服务.前台服务必 ...

  3. 邊實驗邊分析 - Android Foreground Service的使用

    邊實驗邊分析 - Android Foreground Service的使用 一.簡述 二.Android LowMemoryKiller 介紹 三.startService方法的調用行爲測試 給Se ...

  4. Android Service前台服务 StartForeground

    前言 前面写了一个脚本 来执行自动打卡 效果还不错 又学习了一些android的体系知识点 其中就用到了前台服务 利用播放器的模式 来消除被杀的可能 提高Service的优先级 如何保活Service ...

  5. Android Foreground Service

    为了防止后台服务被系统干掉,我们需要将服务提升为前台服务. 示例代码: 需要在AndroidManifest 添加 前台服务的权限 : <uses-permission android:name ...

  6. android q启动前台服务,Android 启动前台服务,适配 vivo 与 OPPO 手机,第一期

    Android 启动前台服务,华为.小米.三星.OPPO.VIVO的配合程度接 这是前文链接,我先甩在这里,上篇文章主要分析了几种品牌手机关于通知的配合程度,这篇文章先写第一期的解决方案,毕竟需求还是 ...

  7. Android 如何屏蔽联通服务信息WAP通知信息http://g.iuni.com.cn, 百度无耻不让发贴批拼联通

    如何屏蔽联通服务信息WAP通知信息http://g.iuni.com.cn, 百度知道无耻不让发贴批拼联通. 如是你用联通的卡,你经常甚至每天都收到多条垃圾短信,其中有一种是看不到发送方的号码的,这就 ...

  8. Service前台服务

    让服务以notification的形式,显示在前台,不容易被杀死 只需在Service的inCreate里面,构建notification,不是用NotificationManager启动,而是用st ...

  9. Android前台服务讲解二之自定义通知视图(RemoteViews)及数据UI更新

    Notification支持文字内容显示.震动.三色灯.铃声等多种提示形式,在默认情况下,Notification仅显示消息标题.消息内容.送达时间这3项内容. 1.更新系统通知Notificatio ...

最新文章

  1. ant design pro 加载慢_ant design pro (九)引入外部模块
  2. openssl生成https证书
  3. python打开figure对象_Python ——绘图 plt.figure()的使用
  4. html5生日时间怎么写代码,用JavaScript写得比较日期,计算生日的函数,
  5. 电路常识性概念(2)-电容
  6. Halcon:Image、region、xld常用的处理
  7. Jenkins修改管理员密码
  8. python实现批量更改xml文件中内容替换
  9. Docker安装Mysql 案例和Tomcat测试
  10. Spring学习总结(29)——Spring异步处理@Async的使用以及原理、源码分析(@EnableAsync)
  11. 9 月,有远见的程序员,都关注了这个人!
  12. Android自动化测试之Monkey
  13. 【Pandas分组聚合】进阶:透视表、交叉表(pivot_table() 、crosstab())
  14. GitHub 这8大超实用小技巧,99.9%的人都不知道!
  15. 【解决】client does not support authentication转载的两种解法
  16. 一个window下的简单的全局快捷键向指定的进程发送的c代码与exe程序下载(二)
  17. Dell PowerEdge™ R510 Servers 安装 Ubuntu Server 10.04 LTS 笔记
  18. 计算机网络——知识点
  19. 网络重置导致无法联网
  20. SpringBoot整合RabbitMQ 访问保错: reply-text=NOT_ALLOWED - access to vhost '/' refused for user 'cuit'

热门文章

  1. php如何升级swoole,升级 Swoole
  2. Python 模拟鼠标点击(可后台)
  3. HY000][1129] null, message from server: Host '192.168.109.3' is blocked because of many connection
  4. linux基础56——uniq
  5. 鬼脚七:淘宝卖家需知的搜索知识(上)
  6. vue/uniapp - 返回上一页并onLoad刷新数据
  7. 半路出家: 如何转行成为软件开发者
  8. 《CSDN社区电子杂志——移动开发杂志》总第2期发布!
  9. 常见决策树分类算法都有哪些?
  10. iOS Swift 5中的键盘处理