应用程序关闭后无法保持 android 服务活动
Cannot keep android service alive after app is closed
我正在尝试生成一个始终保持活动状态的服务,即使用户关闭应用程序也是如此。根据这些线程
Keep location service alive when the app is closed
Android Service Stops When App Is Closed
Android: keep Service running when app is killed
这可以通过 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 OS 应用程序管理器。见下图
最后,driveractivity(不多)
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);
}
这是我使用的前台服务示例,它可以正常工作,当应用程序关闭时它仍然处于活动状态。当然,它也必须启动,对于该任务,应用程序必须乍一看 运行ning,或者必须设置启动事件的接收器,但这是另一回事。
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);
请注意用作操作的两个常量,这些是必须以包名称开头的字符串。
意图服务
使用 IntentService
可能不是最好的方法。默认情况下 IntentService
在 onHandleIntent(Intent)
return 秒后自行停止并且没有任何工作要做(即请求队列为空)。这在 official docs of IntentService:
中有解释
When all requests have been handled, the IntentService stops itself, so you should not call stopSelf().
在您的情况下,onHandleIntent(Intent)
创建了一个线程,但 return 立即停止,这使其自行停止。
服务 + startForeground()
在前台模式下使用常规 Service
应该可以,只要您将该服务 运行 保留在单独的进程中即可。为此,您需要:
- 制作
onStartCommand()
return START_STICKY
.
- 在
onCreate()
中调用显示通知的方法。
- 运行 单独进程中的服务(使用
android:process=":something"
)。
根据 post,您似乎已经单独尝试了其中的一些步骤,但从未同时尝试过所有这些步骤。
您只需在 activity 中的 onStop() 方法中调用您的服务即可。
即使用户停止应用程序,服务仍将是 运行.
如果上述 none 答案有效,则可能是 制造商特定问题 。例如,某些 MI 手机会在用户通过 任务管理器.
终止应用程序时终止前台服务
我建议您在虚拟设备上测试该应用程序,这样您就可以检查它是否属于此类问题。
希望对您有所帮助!
试试这个类似问题的答案:
我正在尝试生成一个始终保持活动状态的服务,即使用户关闭应用程序也是如此。根据这些线程
Keep location service alive when the app is closed
Android Service Stops When App Is Closed
Android: keep Service running when app is killed
这可以通过 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 OS 应用程序管理器。见下图
最后,driveractivity(不多)
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);
}
这是我使用的前台服务示例,它可以正常工作,当应用程序关闭时它仍然处于活动状态。当然,它也必须启动,对于该任务,应用程序必须乍一看 运行ning,或者必须设置启动事件的接收器,但这是另一回事。
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);
请注意用作操作的两个常量,这些是必须以包名称开头的字符串。
意图服务
使用 IntentService
可能不是最好的方法。默认情况下 IntentService
在 onHandleIntent(Intent)
return 秒后自行停止并且没有任何工作要做(即请求队列为空)。这在 official docs of IntentService:
When all requests have been handled, the IntentService stops itself, so you should not call stopSelf().
在您的情况下,onHandleIntent(Intent)
创建了一个线程,但 return 立即停止,这使其自行停止。
服务 + startForeground()
在前台模式下使用常规 Service
应该可以,只要您将该服务 运行 保留在单独的进程中即可。为此,您需要:
- 制作
onStartCommand()
returnSTART_STICKY
. - 在
onCreate()
中调用显示通知的方法。 - 运行 单独进程中的服务(使用
android:process=":something"
)。
根据 post,您似乎已经单独尝试了其中的一些步骤,但从未同时尝试过所有这些步骤。
您只需在 activity 中的 onStop() 方法中调用您的服务即可。 即使用户停止应用程序,服务仍将是 运行.
如果上述 none 答案有效,则可能是 制造商特定问题 。例如,某些 MI 手机会在用户通过 任务管理器.
终止应用程序时终止前台服务我建议您在虚拟设备上测试该应用程序,这样您就可以检查它是否属于此类问题。
希望对您有所帮助!
试试这个类似问题的答案: