应用关闭后无法保持Android服务运行

17

我正在尝试生成一个能够一直保持运行的服务,即使用户关闭了应用程序。根据这些线程

在应用程序关闭时保持位置服务活动

Android应用关闭时服务停止运行

Android: 在应用被杀死时保持服务运行

这可以通过IntentServices或Service.START_STICKY来实现。

然而,我尝试过这两种类型的服务,但都没有成功。换句话说,当用户关闭应用程序时,我的服务被终止了。是否有人可以指出如何实现这一点?以下是我尝试但未成功的内容:

使用IntentService:

public class MyIntentService extends IntentService {
    private final int mPollingTimeMS = 500;
    private int mInitializationPollingCount = 0;
    private Thread mPollThread;
    public MyIntentService() {
        super("MyIntentService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        mPollThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        Log.e(Constants.Engine.LOGGER_TAG_DEV,
                                "SDK Service Running: " +
                                        mInitializationPollingCount * mPollingTimeMS +
                                        "ms have elapsed");
                        mInitializationPollingCount++;
                        sleep(mPollingTimeMS);

                    } catch (Exception e) {
                        StackTraceElement trace = new Exception().getStackTrace()[0];
                        Logger.e(Constants.Engine.LOGGER_TAG_APP, "[Exception:" + e.toString() + "]" +
                                trace.getClassName() + "->" + trace.getMethodName() + ":" + trace.getLineNumber());
                    }
                }
            }
        };
        mPollThread.start();
    }
}

以及与服务相关的内容:

public class MyService extends Service {
    public MyService() {
    }
    private final int mPollingTimeMS = 500;
    private int mInitializationPollingCount = 0;
    private Thread mPollThread;
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mPollThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        Log.e(Constants.Engine.LOGGER_TAG_DEV,
                                "SDK Service Running: " +
                                        mInitializationPollingCount * mPollingTimeMS +
                                        "ms have elapsed");
                        mInitializationPollingCount++;
                        sleep(mPollingTimeMS);

                    } catch (Exception e) {
                        StackTraceElement trace = new Exception().getStackTrace()[0];
                        Logger.e(Constants.Engine.LOGGER_TAG_APP, "[Exception:" + e.toString() + "]" +
                                trace.getClassName() + "->" + trace.getMethodName() + ":" + trace.getLineNumber());
                    }
                }
            }
        };
        mPollThread.start();
        return Service.START_STICKY;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // I tried to return null here, but this
        // service gets killed no matter what.
        return null;
    }
}

这里是清单:

    <service
        android:name=".mycompany.MyService"
        android:enabled="true"
        android:exported="true"
        android:process=":process1">
    </service>
    <service
        android:name=".mycompany.MyIntentService"
        android:process=":process2"
        android:exported="false">
    </service>

我要补充一点,我关闭测试应用程序时不使用关闭按钮,而是使用Android操作系统的应用程序管理器。请参见下面的图片

在此输入图片描述

最后,驱动程序活动(内容不多)。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent1 = new Intent(getBaseContext(), MyService.class);
        startService(intent1);
        Intent intent2 = new Intent(getBaseContext(), MyIntentService.class);
        startService(intent2);

    }
}

我也尝试添加通知并将其变成前台服务,但仍然是同样的问题。一旦我关闭应用程序,一切都被杀死了。这是我添加的内容:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    showNotification();
...etc..

private void showNotification() {
    Intent notificationIntent = new Intent(this, MainActivity.class);
    notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
            notificationIntent, 0);
    int iconId = R.mipmap.ic_launcher;
    int uniqueCode = new Random().nextInt(Integer.MAX_VALUE);
    Notification notification = new NotificationCompat.Builder(this)
            .setSmallIcon(iconId)
            .setContentText("Context Text")
            .setContentIntent(pendingIntent).build();
    startForeground(uniqueCode, notification);
}

有时候如果你的内存不足,服务将会停止,无论如何。如果你需要它持久存在,可以尝试将其作为前台服务运行,你可以通过创建一个通知并调用服务来实现。有很多相关文档可供参考。 - Anindya Dutta
@AnindyaDutta 我怀疑这不是问题所在。手机只运行一个应用程序,并且它总是关闭服务。 - gmmo
1
你不需要一个 IntentService 来完成这个。 - Tim
5个回答

22

这是一个我使用并且成功的前台服务示例,在应用程序关闭时保持活动状态。当然,它也必须被启动,对于这个任务,应用程序必须在第一视角下运行,或者必须设置一个引导事件的接收器,但这是另外一个故事。

public class MyService extends Service {
static final int NOTIFICATION_ID = 543;

public static boolean isServiceRunning = false;

@Override
public void onCreate() {
    super.onCreate();
    startServiceWithNotification();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent != null && intent.getAction().equals(C.ACTION_START_SERVICE)) {
        startServiceWithNotification();
    }
    else stopMyService();
    return START_STICKY;
}

// In case the service is deleted or crashes some how
@Override
public void onDestroy() {
    isServiceRunning = false;
    super.onDestroy();
}

@Override
public IBinder onBind(Intent intent) {
    // Used only in case of bound services.
    return null;
}


void startServiceWithNotification() {
    if (isServiceRunning) return;
    isServiceRunning = true;

    Intent notificationIntent = new Intent(getApplicationContext(), MyActivity.class);
    notificationIntent.setAction(C.ACTION_MAIN);  // A string containing the action name
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    PendingIntent contentPendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.my_icon);

    Notification notification = new NotificationCompat.Builder(this)
            .setContentTitle(getResources().getString(R.string.app_name))
            .setTicker(getResources().getString(R.string.app_name))
            .setContentText(getResources().getString(R.string.my_string))
            .setSmallIcon(R.drawable.my_icon)
            .setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
            .setContentIntent(contentPendingIntent)
            .setOngoing(true)
//                .setDeleteIntent(contentPendingIntent)  // if needed
            .build();
    notification.flags = notification.flags | Notification.FLAG_NO_CLEAR;     // NO_CLEAR makes the notification stay when the user performs a "delete all" command
    startForeground(NOTIFICATION_ID, notification);
}

void stopMyService() {
    stopForeground(true);
    stopSelf();
    isServiceRunning = false;
}
}

然后我使用以下命令运行它:

    Intent startIntent = new Intent(getApplicationContext(), MyService.class);
    startIntent.setAction(C.ACTION_START_SERVICE);
    startService(startIntent);
请注意这两个用作操作的常量,它们是必须以包名开头的字符串。

1
不。图标的原因是因为根据Android政策,用户必须控制应用程序并能够终止它。 - Beppi's
13
C.ACTION_START_SERVICE中的"C"代表"CATEGORY",意为操作被归类为启动服务。 - Viks
1
@Heena C.ACTION_START_SERVICE只是一个常量,指向他的类C。你可以随意命名它。 - Bibin Johny
2
Android 8.1:它不起作用。也许问题出在我的手机(SMJ610)上。它的表现与预期不符。当我启动应用程序时,它会开始一系列命令,应该创建服务并运行命令。我可以在通知栏中看到通知,甚至无法删除它(这很好)。但是一旦我关闭应用程序,通知就被删除了,音乐也停止了(我正在制作一个音频播放器)。 - alexanderktx
如果我想在以后更改通知文本,那么在startServiceWithNotification中创建的哪些对象我应该保留,以便能够更新通知? - undefined
显示剩余4条评论

7

IntentService

使用IntentService可能不是最佳方法。默认情况下,一旦没有工作需要完成(即请求队列为空),IntentService会在onHandleIntent(Intent)返回后停止自己。这在 IntentService 的官方文档中有解释:

当所有请求已被处理时,IntentService 停止自身,因此您不应调用 stopSelf()。

在您的情况下,onHandleIntent(Intent) 创建一个线程,但立即返回,这使得服务自动停止。< / p>

Service + startForeground()

在前台模式下使用常规的Service 应该可以正常工作,只要您将该服务保持在单独的进程上运行。为此,您需要:

  1. onStartCommand()返回START_STICKY
  2. onCreate()中调用显示通知的方法。
  3. 在单独的进程中运行服务(使用android:process=":something")。

根据帖子,似乎您已经尝试了其中一些步骤,但从未尝试过同时执行它们。


在单独的进程中运行服务... @MikeLaren,我不明白...? - gumuruh
默认情况下,Android上的服务与UI的其余部分在同一个(操作系统级别)进程中运行。但是,您可以使用AndroidManifest.xml中服务声明中的“android:process”属性更改此行为。这样做有一些优点,但也有缺点。请查看android:process属性的文档以及https://dev59.com/A2w05IYBdhLWcg3wmC-_等问题,详细了解这样做的利弊。 - Mike Laren
好的 @MikeLaren,谢谢你提供的信息。不过,如果从任务管理器中关闭活动,则似乎没有任何影响。它所有的服务也都被关闭了... - gumuruh

3
如果上面没有一个答案有效的话,可能是一个制造商特定问题。例如,一些小米手机在用户通过任务管理器关闭应用程序时会杀死前台服务。
我建议您在虚拟设备上测试应用程序,这样您就可以检查是否存在这种问题。
希望能够帮助到您!

1

1

您可以在活动的onStop()方法中简单地调用您的服务。即使用户停止了应用程序,服务仍将继续运行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接