Android的前台服务

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

概述

前台服务是用户主动意识到的一种服务,因此在内存不足时,系统也不会考虑将其终止。前台服务必须为状态栏提供通知,将其放在运行中的标题下方。这意味着除非将服务停止或从前台移除,否则不能清除该通知。

在 Android 8.0(API 级别 26)及更高版本中,系统对后台服务进行了限制,如果想要一直保持服务的运行就需要将服务设置为前台服务。前台服务与普通服务的区别在于它会有个通知在状态栏显示。当然有时可能也不仅仅是为了防止服务被回收才使用前台服务,有些项目的需要要求必须使用前台服务。如音乐播放、小说听书、天气等软件,这些都需要设置为前台服务,跟随进程的销毁而销毁。有些不仅仅是依赖应用进程,也可设置为系统白名单,保持一直运行的状态。

需要注意的是:应尽量限制应用使用前台服务。只有当应用执行的任务需供用户查看(即使该任务未直接与应用交互)时,您才应使用前台服务。因此,前台服务必须显示优先级为 PRIORITY_LOW 或更高的状态栏通知,这有助于确保用户知道应用正在执行的任务。如果某操作不是特别重要,您希望使用最低优先级通知,则可能不适合使用服务;此时,您可以考虑使用WorkManager、JobScheduler

每个运行服务的应用都会给系统带来额外负担,从而消耗系统资源。如果应用尝试使用低优先级通知隐藏其服务,则可能会降低用户正在主动交互的应用的性能。因此,如果某个应用尝试运行拥有最低优先级通知的服务,则系统会在抽屉式通知栏的底部调用出该应用的行为。

例如,应将服务播放音乐的音乐播放器设置为在前台运行,因为用户会明确意识到其操作。状态栏中的通知可能表示正在播放的歌曲,并且其允许用户通过启动 Activity 与音乐播放器进行交互。同样,如果应用允许用户追踪其运行,则需通过前台服务来追踪用户的位置。

注意:如果应用面向 Android 9(API 级别 28)或更高版本并使用前台服务,则其必须请求 FOREGROUND_SERVICE 权限。这是一种普通权限,因此,系统会自动为请求权限的应用授予此权限。如果面向 API 级别 28 或更高版本的应用试图创建前台服务但未请求 FOREGROUND_SERVICE,则系统会抛出 SecurityException。

有关前台服务的通知:如果您的应用正在运行“前台服务”(一种长时间在后台运行且用户可以察觉到的 Service,如媒体播放器),则需要发出通知。不能像关闭其他通知那样关闭这种通知。要移除此类通知,必须停止运行服务或者将其从“前台”状态中移除。如要从前台移除服务,请调用 stopForeground()。此方法接受布尔值参数,指示是否需同时移除状态栏通知。

应用场景

前台服务执行用户可以注意到的操作。前台服务显示一个状态栏通知,让用户知道你的应用程序正在前台执行任务,正在消耗系统资源。

应用程序使用前台服务的例子包括:

  • 一个在前台服务中播放音乐的音乐播放器应用程序。通知可能会显示当前正在播放的歌曲。
  • 一种健身应用程序,在获得用户的许可后,在前台服务中记录用户的跑步情况。该通知可能会显示用户在当前健身会话中走过的距离。

只有当你的应用需要执行用户可以注意到的任务时,才使用前台服务,即使他们没有直接与应用程序交互。如果操作的重要性足够低,你想使用最低优先级通知,那么创建一个后台任务。

本文介绍了使用前台服务所需的权限,以及如何启动前台服务并将其从后台移除。它还描述了如何将某些用例与前台服务类型相关联,以及当您从正在后台运行的应用程序启动前台服务时生效的访问限制。

前台服务的特点

默认情况下用户可取消前台服务

从Android 13 (API级别33)开始,默认情况下用户可以取消与前台服务相关的通知。此时只需要用户在通知上执行滑动手势即可。通常情况下,除非前台服务停止或从前台删除,否则通知不会被取消。

如果您希望通知不被用户划掉,则在使用notification.builder创建通知时将true传递给setOngoing() 方法。

立即显示通知的服务

如果前台服务有以下特征之一,系统在服务启动后立即显示相关的通知,即使在运行Android 12或更高版本的设备上:

  • 该服务与包含操作按钮的通知相关联。
  • 该服务的前台服务类型为mediaPlayback、mediaProjection或phoneCall。
  • 该服务提供了与电话呼叫、导航或媒体播放相关的用例,这些用例在通知的category属性中定义。
  • 在设置通知时,服务通过将FOREGROUND_SERVICE_IMMEDIATE传递给setForegroundServiceBehavior()来选择退出行为。
<manifest ...>
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
    <application ...>
      <service
          android:name=".MyMediaPlaybackService"
          android:foregroundServiceType="mediaPlayback"
          android:exported="false">
      </service>
    </application>
</manifest>

在Android 13 (API级别33)或更高版本上,如果用户拒绝通知权限,他们仍然会在任务管理器中看到与前台服务相关的通知,但在通知抽屉中看不到它们。

申请前台服务权限

针对Android 9 (API级别28)或更高版本并使用前台服务的应用程序需要请求FOREGROUND_SERVICE权限,如下面的代码片段所示。这是一个正常的权限,所以系统会自动将其授予请求应用程序。

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>

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

注意:如果目标API级别为28或更高的应用程序试图创建前台服务而没有请求FOREGROUND_SERVICE权限,系统将抛出一个SecurityException。

启动一个前台服务

  • 紧接上文的案例,这里首先添加前台服务的权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
  • 在请求系统将某个服务作为前台服务运行之前,请先启动该服务本身: 在MainActivity中修改启动服务的方式如下:
//启动一个普通后台服务
//startService(startIntent);
 //启动一个前台服务 在api大于26才可使用startForegroundService此方法
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
     startForegroundService(startIntent);
 }else{
     startService(startIntent);
 }

  • 在服务内部,通常是在onStartCommand() 中,你可以请求你的服务在前台运行。为此,调用startForeground()。此方法接受两个参数:一个在状态栏中唯一标识通知的正整数和notification对象本身。接着修改服务内部的代码:

首先创建一个通知,在MyService的oncreate方法和onStartCommand()方法中做如下修改:

public class MyService extends Service {

    public MyService() {
    }

    private Looper serviceLooper;
    private ServiceHandler serviceHandler;
    private NotificationManager manager;

    // 从当前线程接收消息的处理程序
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            try {
                Thread.sleep(5000);
                Log.i("Myservice","当前进程编号"+ Thread.currentThread().getName()+" ·····正在处理任务");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
          //服务处理完成后,使用startId停止服务,这样我们就不会在停止处理另一个作业的服务
//            stopSelf(msg.arg1);
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        manager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Log.i("Myservice","onCreate");
        //启动运行该服务的线程。因为默认情况下服务通常运行在进程的主线程中,我们不希望阻塞主线程。所以创建了一个单独的线程,
        // 我们还将其设置为后台优先级,这样cpu密集型工作就不会破坏我们的UI。
        HandlerThread thread = new HandlerThread("ServiceStartArguments",
                Process.THREAD_PRIORITY_BACKGROUND);
        thread.start();

        // Get the HandlerThread's Looper and use it for our Handler
        serviceLooper = thread.getLooper();
        serviceHandler = new ServiceHandler(serviceLooper);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("Myservice","onStartCommand");

        // If the notification supports a direct reply action, use
// PendingIntent.FLAG_MUTABLE instead.
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent =
                PendingIntent.getActivity(this, 0, notificationIntent,
                        PendingIntent.FLAG_IMMUTABLE);

        Notification notification =
                null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {

            //只在Android O之上需要渠道
            NotificationChannel notificationChannel = new NotificationChannel("channelid1","channelname",NotificationManager.IMPORTANCE_HIGH);
            //如果这里用IMPORTANCE_NOENE就需要在系统的设置里面开启渠道,通知才能正常弹出
            manager.createNotificationChannel(notificationChannel);

            notification = new Notification.Builder(this, "channelid1")
                    .setContentTitle(getText(R.string.notification_title))
                    .setContentText(getText(R.string.notification_message))
                    .setSmallIcon(R.drawable.ic_launcher_background)
                    .setContentIntent(pendingIntent)
                    .setTicker(getText(R.string.ticker_text))
                    .build();
        }

// Notification ID cannot be 0.
        startForeground(1, notification);

        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

//对于每个开始请求,发送一个消息来开始一个作业,并传递启动ID,这样我们就知道当我们完成作业时我们正在停止哪个请求
        Message msg = serviceHandler.obtainMessage();
        msg.arg1 = startId;
        //在当前线程下执行服务的任务。
        serviceHandler.sendMessage(msg);

        // If we get killed, after returning from here, restart
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("Myservice","onDestroy");
    }
}

经过上述三步,我们来测试一下效果:

Android的前台服务,Android程序,android,四大组件

Android的前台服务,Android程序,android,四大组件

这会在前台开启一个通知,日志可见并没有进行销毁。服务列表中也可查看当前前台服务运行的时间:

Android的前台服务,Android程序,android,四大组件

这样一个前台任务就创建好了。

注意:状态栏通知必须使用优先级为PRIORITY_LOW或更高。如果你的应用程序试图使用一个优先级较低的通知,系统会在通知抽屉中添加一条消息,提醒用户应用程序使用了前台服务。

后台启动限制

针对Android 12 (API级别31)或更高版本的应用程序不能在后台运行时启动前台服务,除非有一些特殊情况。如果应用程序在后台运行时试图启动前台服务,而前台服务不满足前文中的情况,系统将抛出ForegroundServiceStartNotAllowedException异常。

注意:如果一个应用程序调用Context.startForegroundService()来启动另一个应用程序拥有的前台服务,这里限制只适用于两个应用程序都针对Android 12或更高版本。

检查应用程序是否执行后台启动

为了更好地验证当你的应用程序试图在后台运行时启动前台服务,可以在连接到测试设备或模拟器的开发机器上执行以下ADB命令,每当这种行为发生时就会出现通知:

adb shell device_config put activity_manager \ default_fgs_starts_restriction_notification_enabled true
免除后台启动限制

在以下情况下,即使你的应用程序在后台运行,应用程序也可以启动前台服务:

  • 你的应用从一个用户可见的状态转换,比如一个活动。
  • 当应用程序在一个现有任务的后台堆栈中有一个活动时,服务可以从后台启动一个活动。
  • 您的应用程序使用云消息接收高优先级消息。

注意:如果应用程序没有使用高优先级消息向用户显示时间敏感的内容,系统可以将高优先级消息降级为正常优先级。如果消息的优先级被降级,你的应用程序不能启动前台服务,并且试图启动前台服务会导致ForegroundServiceStartNotAllowedException异常。

因此,在尝试启动前台服务之前,建议检查RemoteMessage.getPriority() 的结果,并确认它是PRIORITY_HIGH。

  • 用户在与应用程序相关的UI元素上执行操作。例如,他们可能与气泡、通知、小部件或活动交互。
  • 应用程序调用精确的Alarm来完成用户请求的操作。
  • 应用程序是设备当前的输入法。
  • 应用程序接收到一个与地理围栏或活动识别转换相关的事件。
  • 在设备重启并在广播接收器中接收到ACTION_BOOT_COMPLETED、ACTION_LOCKED_BOOT_COMPLETED或action_my_package_replace意图动作后。
  • 应用程序在广播接收器中接收ACTION_TIMEZONE_CHANGED、ACTION_TIME_CHANGED或ACTION_LOCALE_CHANGED意图动作。
  • 具有特定系统角色或权限的应用程序,例如设备所有者和配置文件所有者。
  • ........

从前台删除一个服务

要从前台删除服务,请调用stopForeground()。此方法接受一个布尔值,该值指示是否也删除状态栏通知。如果在前台运行时停止服务,则会删除其通知。

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            stopForeground(Service.STOP_FOREGROUND_REMOVE);
        }
        Log.i("Myservice","onDestroy");
    }

Android的前台服务,Android程序,android,四大组件

此时通知也会被移除。文章来源地址https://www.toymoban.com/news/detail-771151.html

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

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

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

相关文章

  • Android 四大组件之广播

    在Android应用开发中,广播组件是一项关键技术,被广泛用于各种任务和场景。无论是发送系统级广播,还是在应用内部实现组件间的通信,了解和掌握广播组件的工作原理和使用方法对于每个Android开发者来说都是至关重要的。本文旨在帮助你深入了解Android广播组件,并给出

    2024年02月06日
    浏览(46)
  • Android 四大组件启动

    service: startService启动过程分析 - Gityuan博客 | 袁辉辉的技术博客 在整个startService过程,从进程角度看服务启动过程 Process A进程: 是指调用startService命令所在的进程,也就是启动服务的发起端进程,比如点击桌面App图标,此处Process A便是Launcher所在进程。 system_server进程: 系统

    2024年04月11日
    浏览(38)
  • Android中级——四大组件工作过程

    startActivity()最终都会调用到startActivityForResult() 上面调用Instrumentation的execStartActivity() 上面获取ActivityTaskManagerService,是IPC过程,调用其startActivity()启动,然后调到startActivityAsUser() 上面通过ActivityStartController获取ActivityStarter,调用execute(),调用resolveActivity()根据Intent匹配到对应的

    2024年02月11日
    浏览(38)
  • Android 四大组件之Activity详解

      最近在整理Android方面的知识,也算是对Android知识的一个复习总结。   Activity是Android组件中最基本也是最为常见用的四大组件之一,它提供一个可视化的用户界面,放置各种UI组件,与用户进行交互。一般来说,你所能看到界面都属于Activity。 右击包名——New——Acti

    2024年04月15日
    浏览(72)
  • Android复习(Android基础-四大组件)——Service与Activity通信

    我们前面学会了启动和停止服务的方法,但是服务虽然是在活动里启动的,但是启动服务之后,活动与服务之间基本没什么关系了。 正常情况,我们在Activity里调用startService()方法启动MyService这个服务,然后MyService的onCreate()和onStartCommand()方法就会得到执行。之后服务会一直处

    2024年02月13日
    浏览(41)
  • Android的前台服务

    概述 前台服务是用户主动意识到的一种服务,因此在内存不足时,系统也不会考虑将其终止。前台服务必须为状态栏提供通知,将其放在运行中的标题下方。这意味着除非将服务停止或从前台移除,否则不能清除该通知。 在 Android 8.0(API 级别 26)及更高版本中,系统对后台

    2024年02月03日
    浏览(42)
  • Android 前台服务

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

    2024年02月16日
    浏览(46)
  • Android 前台服务讲解

    目录 Android 前台服务和后台服务区别 前台服务(Foreground Service): 后台服务(Background Service): 总结: 前台服务更新: JobScheduler、WorkManager 区别和使用方式 android.app.ForegroundServiceStartNotAllowedException: Service.startForeground() 咋解决? WorkManager 在 Android 中,前台服务(Foreground

    2024年02月13日
    浏览(36)
  • Android app保活(前台服务)

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

    2024年02月09日
    浏览(41)
  • Android启动前台服务(startForegroundService)

    问题: 注意事项: 8.0适配:通知需要加上NotificationChannel,开启前台服务的方式startForegroundService() 9.0适配:manifest.xml文件中需要增加权限:FOREGROUND_SERVICE Android之 Service服务详解 1、前台权限: 2、Service中开启通知: 3、启动Service: Android O对后台Service限制怎么解决 4、其他方

    2024年02月16日
    浏览(41)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包