从最近清除应用程序时如何处理作为前台运行的服务?

Posted

技术标签:

【中文标题】从最近清除应用程序时如何处理作为前台运行的服务?【英文标题】:How to handle services that run as foreground when an app is cleared from recent? 【发布时间】:2019-01-05 19:54:36 【问题描述】:

我的 android 应用正在播放音频,而该应用在后台运行,服务作为前台运行,类似于许多其他应用,例如 Google Play 音乐、Spotify 和其他音乐播放器/播客播放器应用。

我检查过的大多数应用程序(包括 Google Play 音乐)都会使服务继续运行,即使该应用程序已从最近的应用程序中清除。另一方面,有些人会停止音频并关闭服务(我只发现 Spotify 会这样做)。

我想知道处理这个问题的正确方法是什么?尽管大多数应用程序都将服务保持打开状态,但用户似乎希望音频停止并且通知与应用程序一起从状态栏中消失。

这里有正确的方法吗?

【问题讨论】:

【参考方案1】:

您可以查看此link 以查看从应用程序中删除时进程会发生什么

最近的列表。

即使 onTaskRemoved() 被调用,在这种情况下应用程序也不会被杀死。该服务继续存在。可以通过去隐藏的开发者菜单查看正在运行的进程来证明。

您可以在此回调方法中执行一些代码,并获得所需的行为。

【讨论】:

感谢您的链接,但这实际上并不能回答我的问题。如果需要,您可以在从最近清除应用程序时停止服务。默认情况下它不会停止。问题是首选/正确的行为是什么,如果有的话。【参考方案2】:

由于这是一个意见问题,我将作为一名开发人员,同时也是一名智能手机用户(好吧,现在不是):

tl;dr:让它继续运行

=================================

更长的版本

将手机用作音乐播放器的意义在于,在您进行其他活动(例如跑步、浏览、发短信甚至为通过扬声器连接的其他人播放音乐)时为您提供音频,成为“dj”你的组。您很少将音乐播放器用作主要任务,而我希望在您尝试找出歌词或观看视频剪辑(因此,您将使用 YouTube)之类的事情时这样做。 因此,我认为您的音乐播放器应该有一个独立于手机其他活动的生命周期。 想象一下为他人播放音乐而音乐突然停止的噩梦,而您却在处理不相关的事情在您的手机上。

但是,当您提到“用户似乎希望音频停止并且通知与应用程序一起从状态栏中消失”时,您有一点意思。我不认为整个陈述都是真的,而是提取要点:用户希望轻松停止他们的音乐应用

从这个意义上说,您应该尽可能轻松地停止播放以优化您的用户体验。在我的脑海中,我想最好的方法是在通知扩展(甚至紧凑)版本中使用一个不错的“X”按钮。然后,用户可以直接从状态栏停止播放,而不必将应用程序置于最前面。

如果您确实想更进一步,您可以在设置中选择使用前台或后台服务 - 为了让用户更容易理解,您可以使用“最近时停止音乐”这样的措辞应用程序被清除”,因此根据他们的需要将选择委托给您的用户。当然,这会给您的用户增加复杂性和过多的功能,因此您需要自己决定是否需要它。

【讨论】:

感谢您的全面回复!你让我相信播放器应该有一个单独的生命周期,并且 Android 用户不一定希望音频在这种情况下停止,而是希望轻松停止音乐,而这已经通过使用“X”来实现通知中的按钮。我也非常喜欢你的“更进一步”的想法!【参考方案3】:

让它继续运行,并发出通知。

一切尽在名下。 根据Android Developers,

“最近的屏幕(也称为概述屏幕,最近 任务列表或最近的应用程序)是列出最近的系统级 UI 访问的活动和任务。”

将任务从该列表中滑出只是将其从列表中删除,而不是从执行中删除。

Notifications(当然在 Oreo 下)是您让用户知道您仍在运行服务的地方。使用通知允许他们重新打开任务,然后在他们认为合适的时候终止服务。

【讨论】:

【参考方案4】:

您正在制作类似音乐播放器的应用程序,因此大多数时候用户希望即使应用程序从最近的任务中关闭,也会播放音乐。现在您正在使用前台服务,因此将显示通知,在此通知中您提供 STOP 按钮,以便用户可以从那里停止音乐。

但是,如果您希望您的应用的后台服务在从最近的任务中删除后停止,那么,

public class CustomService extends Service 

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

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

    @Override
    public void onCreate() 
        super.onCreate();
    

    @Override
    public void onTaskRemoved(Intent rootIntent) 
        super.onTaskRemoved(rootIntent);
        //stop service
        stopService(new Intent(this, CustomService.class));
    

    @Override
    public void onDestroy() 
        super.onDestroy();
        Log.d("CustomService", "Service Destroyed");
    

现在在 AndroidMenifest.xml 中声明服务

<service android:name=".CustomService" android:stopWithTask="false" />

android:stopWithTask="false" 会在 onTaskRemoved() 上进行回调,所以在那边处理停止服务。

【讨论】:

【参考方案5】:

当应用程序从最近清除时保持服务运行,用户可以通过一个按钮完全停止通知中的音频和服务,就像这样: Here is a picture -> QQ Music

【讨论】:

【参考方案6】:
public class OnClearFromRecentService extends Service 

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


@Override
public int onStartCommand(Intent intent, int flags, int startId) 
    Log.d("ClearFromRecentService", "Service Started");
    return START_NOT_STICKY;


@Override
public void onDestroy() 
    super.onDestroy();
    Log.d("ClearFromRecentService", "Service Destroyed");


@Override
public void onTaskRemoved(Intent rootIntent) 
    Log.e("ClearFromRecentService", "END");
    //Code here
    stopSelf();



像这样在 Manifest.xml 中注册这个服务

<service android:name="com.example.OnClearFromRecentService" android:stopWithTask="false" />

然后在您的活动上启动此服务

startService(new Intent(getBaseContext(), OnClearFromRecentService.class));

现在,只要你从 android 最近清除你的应用程序然后这个方法 onTaskRemoved() 就会执行。

【讨论】:

以上是关于从最近清除应用程序时如何处理作为前台运行的服务?的主要内容,如果未能解决你的问题,请参考以下文章

IOS,应用启动时如何处理多个本地通知?

UILocalNotification - 应用程序未运行时如何处理?

应用程序关闭时如何处理localNotifications

从 Spark 写入镶木地板时如何处理空值

当我的应用程序激活时如何处理推送通知?

从套接字读取时如何处理阻塞的 read() 调用?