Android 前台服务

这篇具有很好参考价值的文章主要介绍了Android 前台服务。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

零、前言

1.服务是什么(Service)

Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。

2.前台服务(ForegroundService)是什么?

前台服务执行一些用户能注意到的操作。例如,音频应用会使用前台服务来播放音频曲目。前台服务必须显示通知。即使用户停止与应用的交互,前台服务仍会继续运行。

应用场景

最常见的表现形式就是音乐播放服务,应用程序后台运行时,用户可以通过通知栏,知道当前播放内容,并进行暂停、继续、切歌等相关操作。

3.为什么用前台服务

后台运行的Service系统优先级相对较低,当系统内存不足时,在后台运行的Service就有可能被回收,为了保持后台服务的正常运行及相关操作,可以选择将需要保持运行的Service设置为前台服务,从而使APP长时间处于后台或者关闭(进程未被清理)时,服务能够保持工作。

4.小结

前台服务可以给用户提供界面上的操作。 每个前台服务都必须要在通知栏显示一个通知(notification)。用户可以感知到app的前台服务正在运行。 这个通知(notification)默认是不能移除的。服务停止后,通知会被系统移除。 当用户不需要直接操作app,app需要给用户一个状态显示的时候,可以用前台服务。

一、创建服务

import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
import android.os.IBinder;
import android.text.TextUtils;
​
import com.zg.fragmentdemo.MainActivity;
import com.zg.fragmentdemo.R;
import com.zg.fragmentdemo.utils.NotificationUtils;
​
import static android.app.Notification.VISIBILITY_SECRET;
​
/***
 * @Description: 前台服务
 * channelId必须要一致,否则会报 android.app.RemoteServiceException: Bad notification for startForeground 错误
 * 8.0之上一定要使用 NotificationChannel 适配下才行
 * 步骤
 * 1.通过 “通知服务” 创建 NotificationChannel
 * 2.通过 Notification.Builder 构造器 创建 Notification
 * 3.通过 startForeground 开启服务
 * 4.高于9.0的版本 manifest需要增加  <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
 *
 * 在onCreate中创建一个广播接收器,试试能不能接收到 开单或者预约结束后的通知
 */
public class ForeService extends Service {
​
    private MessageReceiver mMsgRecv;
​
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
​
    @Override
    public void onCreate() {
        super.onCreate();
        startForeground(1, getNotification("标题", "内容"));
​
        //注册广播
        mMsgRecv = new MessageReceiver();
        IntentFilter mFilter = new IntentFilter();
        mFilter.addAction(MessageReceiver.MESSAGE_ACTION);
        registerReceiver(mMsgRecv, mFilter);
    }
​
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }
​
    @Override
    public void onDestroy() {
        super.onDestroy();
        //取消监听广播
        unregisterReceiver(mMsgRecv);
        //停止的时候销毁前台服务
        stopForeground(true);
    }
​
    private Notification getNotification(String title, String message) {
        createNotificationChannel();
        //创建一个跳转到活动页面的意图
        Intent clickIntent = new Intent(this, MainActivity.class);
        //clickIntent.putExtra("flag", count);//这里可以传值
        //创建一个用于页面跳转的延迟意图
        PendingIntent contentIntent = PendingIntent.getActivity(this, 1012, clickIntent
                , PendingIntent.FLAG_UPDATE_CURRENT);
        //创建一个通知消息的构造器
        Notification.Builder builder = new Notification.Builder(this);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            //Android8.0开始必须给每个通知分配对应的渠道
            builder = new Notification.Builder(this, "f_channel_id");
        }
        builder.setContentIntent(contentIntent)//设置内容的点击意图
                .setAutoCancel(true)//设置是否允许自动清除
                .setSmallIcon(R.mipmap.ic_launcher)//设置状态栏里的小图标
                .setTicker("提示消息来啦")//设置状态栏里面的提示文本
                .setWhen(System.currentTimeMillis())//设置推送时间,格式为"小时:分钟"
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))//设置通知栏里面的大图标
                .setContentTitle(title)//设置通知栏里面的标题文本
                .setContentText(message);//设置通知栏里面的内容文本
        //根据消息构造器创建一个通知对象
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
            Notification notify = builder.build();
            return notify;
        }
        return null;
    }
​
    @TargetApi(Build.VERSION_CODES.O)
    private void createNotificationChannel() {
        NotificationChannel channel = new NotificationChannel("f_channel_id", "CHANNEL_NAME", NotificationManager.IMPORTANCE_HIGH);
        //是否绕过请勿打扰模式
        channel.canBypassDnd();
        //闪光灯
        channel.enableLights(true);
        //锁屏显示通知
        channel.setLockscreenVisibility(VISIBILITY_SECRET);
        //闪关灯的灯光颜色
        channel.setLightColor(Color.RED);
        //桌面launcher的消息角标
        channel.canShowBadge();
        //是否允许震动
        channel.enableVibration(true);
        //获取系统通知响铃声音的配置
        channel.getAudioAttributes();
        //获取通知取到组
        channel.getGroup();
        //设置可绕过  请勿打扰模式
        channel.setBypassDnd(true);
        //设置震动模式
        channel.setVibrationPattern(new long[]{100, 100, 200});
        //是否会有灯光
        channel.shouldShowLights();
        getManager().createNotificationChannel(channel);
    }
​
    private NotificationManager mManager;
​
    private NotificationManager getManager() {
        if (mManager == null) {
            mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        }
        return mManager;
    }
}

AndroidManifest.xml文件中使用前台服务

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="...">
 
    <!--  前台服务权限  -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
 
    <application ...  >
 
        <service
            android:name=".jpush.ForeService"
            android:enabled="true"
            android:exported="true" />
 
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTask" />
 
    </application>
</manifest>

在manifest里注册MainActivityForeService。并且申请权限FOREGROUND_SERVICE

Activity的启动模式我们选择了singleTop。是为了方便演示点击通知时候的跳转效果。

广播接收器

public class MessageReceiver extends BroadcastReceiver {
​
    public static final String MESSAGE_ACTION = "MESSAGE_ACTION";
    public static final String MESSAGE_ID = "MESSAGE_ID";
​
    @Override
    public void onReceive(Context context, Intent intent) {
        if (MESSAGE_ACTION == intent.getAction()) {
            String messageid = intent.getStringExtra(MESSAGE_ID);
            if (!TextUtils.isEmpty(messageid)) {
                new NotificationUtils(context).sendNotification("提示", messageid);
            }
        }
    }
}

二、使用服务

Intent mForegroundService = new Intent(this, ForeService.class);
mForegroundService.putExtra("","")//传值
​
// Android 8.0使用startForegroundService在前台启动新服务
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
    startForegroundService(mForegroundService);
} else {
    startService(mForegroundService);
}

ForeService

外面调用服务,在service中,需要对应地使用startForeground方法。

@Override
public void onCreate() {
   super.onCreate();
   startForeground(1, getNotification("标题", "内容"));
}

三、暂停服务

ForeService

@Override
public void onDestroy() {
    super.onDestroy();
    //停止的时候销毁前台服务。这里只是 “是否取消掉前台服务的通知”。false表示保留通知。true不保留
    stopForeground(true);
    //stopForeground(false);//服务变成了后台服务,并没有退出。此时对应的通知可以滑动取消掉。
}

在其他的地方暂停服务

//停止服务,是停止整个服务
mForegroundService = new Intent(this, ForeService.class);
stopService(mForegroundService)

四、注意

8.0适配:通知需要加上NotificationChannel,开启前台服务的方式startForegroundService()

9.0适配:manifest.xml文件中需要增加权限

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

五、发送广播

同一个手机上另外一个程序使用广播可以推送消息给前台服务

//发送广播,跨进程通信
Intent broadcast = new Intent();
broadcast.setAction("MESSAGE_ACTION");
broadcast.putExtra("MESSAGE_ID",
        "您有新的订单");
sendOrderedBroadcast(broadcast, null);

注意:其他的手机上的应用不行。

六、通知工具类

package com.zg.fragmentdemo.utils;
​
import android.annotation.TargetApi;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
​
import androidx.core.app.NotificationCompat;
​
import com.zg.fragmentdemo.MainActivity;
import com.zg.fragmentdemo.R;
​
import static android.app.Notification.PRIORITY_DEFAULT;
import static android.app.Notification.VISIBILITY_SECRET;
​
public class NotificationUtils extends ContextWrapper {
​
    public static final String CHANNEL_ID = "default";
    private static final String CHANNEL_NAME = "Default Channel";
    private static final String CHANNEL_DESCRIPTION = "this is default channel!";
    private NotificationManager mManager;
​
    public NotificationUtils(Context base) {
        super(base);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createNotificationChannel();
        }
    }
​
    @TargetApi(Build.VERSION_CODES.O)
    private void createNotificationChannel() {
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
        //是否绕过请勿打扰模式
        channel.canBypassDnd();
        //闪光灯
        channel.enableLights(true);
        //锁屏显示通知
        channel.setLockscreenVisibility(VISIBILITY_SECRET);
        //闪关灯的灯光颜色
        channel.setLightColor(Color.RED);
        //桌面launcher的消息角标
        channel.canShowBadge();
        //是否允许震动
        channel.enableVibration(true);
        //获取系统通知响铃声音的配置
        channel.getAudioAttributes();
        //获取通知取到组
        channel.getGroup();
        //设置可绕过  请勿打扰模式
        channel.setBypassDnd(true);
        //设置震动模式
        channel.setVibrationPattern(new long[]{100, 100, 200});
        //是否会有灯光
        channel.shouldShowLights();
        getManager().createNotificationChannel(channel);
    }
​
    private NotificationManager getManager() {
        if (mManager == null) {
            mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        }
        return mManager;
    }
​
    /**
     * 发送通知
     */
    public void sendNotification(String title, String content) {
        NotificationCompat.Builder builder = getNotification(title, content);
        getManager().notify(1, builder.build());
    }
​
    private NotificationCompat.Builder getNotification(String title, String content) {
        NotificationCompat.Builder builder = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
        } else {
            builder = new NotificationCompat.Builder(getApplicationContext());
            builder.setPriority(PRIORITY_DEFAULT);
        }
        //标题
        builder.setContentTitle(title);
        //文本内容
        //builder.setContentText(content);
        builder.setStyle(new NotificationCompat.BigTextStyle().bigText(content));
        //小图标
        builder.setSmallIcon(R.mipmap.logo);
        //设置点击信息后自动清除通知
        builder.setAutoCancel(true);
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, -1,
                intent, PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(pendingIntent);
        return builder;
    }
​
    /**
     * 发送通知
     */
    public void sendNotification(int notifyId, String title, String content) {
        NotificationCompat.Builder builder = getNotification(title, content);
        getManager().notify(notifyId, builder.build());
    }
​
    /**
     * 发送带有进度的通知
     */
    public void sendNotificationProgress(String title, String content, int progress, PendingIntent intent) {
        NotificationCompat.Builder builder = getNotificationProgress(title, content, progress, intent);
        getManager().notify(0, builder.build());
    }
​
    /**
     * 获取带有进度的Notification
     */
    private NotificationCompat.Builder getNotificationProgress(String title, String content,
                                                               int progress, PendingIntent intent) {
        NotificationCompat.Builder builder = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
        } else {
            builder = new NotificationCompat.Builder(getApplicationContext());
            builder.setPriority(PRIORITY_DEFAULT);
        }
        //标题
        builder.setContentTitle(title);
        //文本内容
        builder.setContentText(content);
        //小图标
        builder.setSmallIcon(R.mipmap.ic_launcher);
        //设置大图标,未设置时使用小图标代替,拉下通知栏显示的那个图标
        //设置大图片 BitmpFactory.decodeResource(Resource res,int id) 根据给定的资源Id解析成位图
        builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
        if (progress > 0 && progress < 100) {
            //一种是有进度刻度的(false),一种是循环流动的(true)
            //设置为false,表示刻度,设置为true,表示流动
            builder.setProgress(100, progress, false);
        } else {
            //0,0,false,可以将进度条隐藏
            builder.setProgress(0, 0, false);
            builder.setContentText("下载完成");
        }
        //设置点击信息后自动清除通知
        builder.setAutoCancel(true);
        //通知的时间
        builder.setWhen(System.currentTimeMillis());
        //设置点击信息后的跳转(意图)
        builder.setContentIntent(intent);
        return builder;
    }
}

参考

Android前台服务的使用(一)

Android前台服务讲解一

Android 使用前台服务文章来源地址https://www.toymoban.com/news/detail-594007.html

到了这里,关于Android 前台服务的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android app保活(前台服务)

    国内厂商定制,除非厂商给app白名单,否则只能用户手动添加白名单(应用自启和后台运行),才能通过前台服务实现app保活。 这里介绍前台服务相关实现方式。 开启服务: 服务: 清单文件

    2024年02月09日
    浏览(42)
  • Android14前台服务适配指南

    Android 10引入了 android:foregroundServiceType 属性,用于帮助开发者更有目的地定义前台服务。这个属性在Android 14中被强制要求,必须指定适当的前台服务类型。以下是可选择的前台服务类型: camera : 相机应用。 connectedDevice : 与连接的设备相关的应用。 dataSync : 数据同步应用。

    2024年01月22日
    浏览(42)
  • Android service(服务)中的前台服务

    紧接上文 概述 前台服务是用户主动意识到的一种服务,因此在内存不足时,系统也不会考虑将其终止。前台服务必须为状态栏提供通知,将其放在运行中的标题下方。这意味着除非将服务停止或从前台移除,否则不能清除该通知。 针对上一篇文章中的案例我们可以发现,系

    2024年02月14日
    浏览(41)
  • Android入门教程 | 四大组件之Service(前台服务,后台服务)

    Service是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可在后台处理网络事务、播放

    2024年02月05日
    浏览(56)
  • Android进程类型及优先级(前台进程/可见进程/服务进程/缓存进程/空进程)

    Android 进程优先级 :前台进程 可见进程 服务进程 缓存进程 空进程 ; 关键优先级进程 : 活动进程 ; 高优先级进程 : 可见进程 , 服务进程 ; 低优先级进程 : 后台进程 , 空进程 ; Android 系统中会尽量保证优先级高的进程的存在时间尽可能长 ;如果资源不足 ( 这里的资源最主要的是内

    2024年04月12日
    浏览(38)
  • 车机 Android 环境下利用 CarAudioService 实现自定义 Java 服务自启动

    注意:本文基于 Android 11/R 进行分析 Qidi 2023.11.28 (MarkDown Haroopad) Overlay 实现的效果正如其字面意思,就是“在原有效果的基础上再叠加一些效果”。 Android 提供了两种实现方式: 编译时:https://source.android.com/docs/setup/create/new-device#use-resource-overlays 运行时:https://source.android.c

    2024年02月05日
    浏览(43)
  • Android移动应用开发——开灯与关灯(小兔子)——实验八——服务的启动与关闭

        掌握布局和基本控件的属性功能及使用方法     掌握startService()方法与stopService()方法启动和关闭服务 通过线性布局和相对布局来搭建一个界面,界面效果如下图所示。当点击“关灯”按钮后,转变到第二个状态。在第二个状态中,点击“开灯”按钮后,跳转回第一

    2024年02月05日
    浏览(56)
  • Android 安卓开发语言kotlin与Java该如何选择

            如今在Android开发中,应用层开发语言主要是Java和Kotlin,Kotlin是后来加入的,主导的语言还是Java。kotlin的加入仿佛让会kotlin语言的开发者更屌一些,其实不然。         有人说kotlin的引入是解决开发者复杂的逻辑,并且对空指针控制的比较友好,但是我们在开

    2024年02月11日
    浏览(66)
  • Android APP开机启动,安卓APP开发自启动,安卓启动后APP自动启动 Android让程序开机自动运行APP

    第一步设置获取广播后的业务 第二查权限给APP 理论以上两步做完就可以了。APP也能收到广播信息了, 但是APP没有在桌面启动。 经过再研究,发现要在手机再设置自动开启等业务,以下是小米、魅族的系统设置的一些内容,其它平台自己研究。 这里已经显示收到广播信息  

    2024年02月06日
    浏览(57)
  • Flutter混合开发:Android中如何启动Flutter

    如果你想在你的Android应用中使用Flutter,则需要遵循以下步骤: 1. 配置Flutter环境 在Android Studio中安装Flutter和Dart插件,并确保Flutter SDK已安装并配置好环境变量。这些步骤可以通过Flutter官方文档提供的说明来完成。 2. 创建Flutter Module 使用Flutter命令行工具创建一个Flutter Modul

    2024年02月10日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包