在应用程序关闭后保持活动且不锁定 UI 的服务
Service that stays alive after app closure and doesn't lock the UI
在我的 Android 项目中,我需要启动一个 Service
:
- 即使在应用程序关闭后仍保持活动状态
- 不阻塞主线程
我针对这个问题分析了服务、IntentServices 和线程:
使用 Service
并覆盖
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Some nasty code
return START_STICKY;
}
我实现了第一个目标,但是我在启动服务时阻塞了主线程
使用 IntentService
并覆盖
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
@Override
protected void onHandleIntent(Intent intent) {
// Same nasty code as before
}
我实现了第二个目标,因为我没有阻止 UI 但是当我终止应用程序时服务终止。
然后我尝试使用 Service
启动 Thread
,如下所示:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//The usual nasty code
}
});
thread.start();
return START_STICKY;
}
我得到了与第一种情况相同的结果(我屏蔽了 UI)。
我用myActivity.startService(myActivity, MyService.class)
启动服务
我是不是遗漏了什么明显的东西?有没有办法同时实现这两个目标?
如果您使用 IntentService
,onHandleIntent
方法中的所有内容都会自动在第二个工作程序 Thread
中进行。所以不需要自己创建 Thread
。还要确保您在 onHandleIntent
中完成了实际工作。这是您应该执行后台工作的地方。
此处是在关闭应用程序时终止服务进程时重新启动服务的代码。在您的服务中,添加以下代码。
@Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
您可以按照以下步骤操作:
第 1 步:创建 IntentService
public class DownloadService extends IntentService {
@Override
protected void onHandleIntent(Intent intent) {
// Gets data from incoming Intent
String yourDataString = intent.getDataString();
...
// manipulate intent
...
}
}
步骤二:在Manifest中记录IntentService
<application
android:icon="@drawable/icon"
android:label="@string/app_name">
...
<service
android:name=".DownloadService"
android:exported="false"/>
...
<application/>
步骤 3:向 IntentService 发送请求
/* Starting Service */
Intent intent = new Intent(Intent.ACTION_SYNC, null, this, DownloadService.class);
/* You can send Extras to IntentService if needed */
intent.putExtra("url", url);
intent.putExtra("receiver", mReceiver);
intent.putExtra("requestId", 101);
startService(intent);
Note: android.permission.INTERNET permission required.
您可以检查 here 表格更多
对于这种情况:
Stays alive even after the application closure.
您需要使用Service
而不是IntentService
,因为IntentService
总是在onHandleIntent
中的代码完全执行后自行终止。通过在 Service
的 onStartCommand
方法中调用 startForeground(int notification_id, Notification notification)
,将使您的 Service
仍然存在而不会阻塞 UI 线程。但是您需要创建一个通知 startForeground
方法。在完成 Service
后,不要忘记在 Service
的 onDestroy()
方法中调用 stopForeground(true)
。请记住,如果您要执行的代码是异步的,请创建一个私有 class ServiceHandler
扩展 Handler
和 运行 handleMessage
方法中的代码。
实现此模式的应用是 DU Battery Saver。
在我的 Android 项目中,我需要启动一个 Service
:
- 即使在应用程序关闭后仍保持活动状态
- 不阻塞主线程
我针对这个问题分析了服务、IntentServices 和线程:
使用 Service
并覆盖
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Some nasty code
return START_STICKY;
}
我实现了第一个目标,但是我在启动服务时阻塞了主线程
使用 IntentService
并覆盖
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
@Override
protected void onHandleIntent(Intent intent) {
// Same nasty code as before
}
我实现了第二个目标,因为我没有阻止 UI 但是当我终止应用程序时服务终止。
然后我尝试使用 Service
启动 Thread
,如下所示:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//The usual nasty code
}
});
thread.start();
return START_STICKY;
}
我得到了与第一种情况相同的结果(我屏蔽了 UI)。
我用myActivity.startService(myActivity, MyService.class)
我是不是遗漏了什么明显的东西?有没有办法同时实现这两个目标?
如果您使用 IntentService
,onHandleIntent
方法中的所有内容都会自动在第二个工作程序 Thread
中进行。所以不需要自己创建 Thread
。还要确保您在 onHandleIntent
中完成了实际工作。这是您应该执行后台工作的地方。
此处是在关闭应用程序时终止服务进程时重新启动服务的代码。在您的服务中,添加以下代码。
@Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
您可以按照以下步骤操作:
第 1 步:创建 IntentService
public class DownloadService extends IntentService {
@Override
protected void onHandleIntent(Intent intent) {
// Gets data from incoming Intent
String yourDataString = intent.getDataString();
...
// manipulate intent
...
}
}
步骤二:在Manifest中记录IntentService
<application
android:icon="@drawable/icon"
android:label="@string/app_name">
...
<service
android:name=".DownloadService"
android:exported="false"/>
...
<application/>
步骤 3:向 IntentService 发送请求
/* Starting Service */
Intent intent = new Intent(Intent.ACTION_SYNC, null, this, DownloadService.class);
/* You can send Extras to IntentService if needed */
intent.putExtra("url", url);
intent.putExtra("receiver", mReceiver);
intent.putExtra("requestId", 101);
startService(intent);
Note: android.permission.INTERNET permission required.
您可以检查 here 表格更多
对于这种情况:
Stays alive even after the application closure.
您需要使用Service
而不是IntentService
,因为IntentService
总是在onHandleIntent
中的代码完全执行后自行终止。通过在 Service
的 onStartCommand
方法中调用 startForeground(int notification_id, Notification notification)
,将使您的 Service
仍然存在而不会阻塞 UI 线程。但是您需要创建一个通知 startForeground
方法。在完成 Service
后,不要忘记在 Service
的 onDestroy()
方法中调用 stopForeground(true)
。请记住,如果您要执行的代码是异步的,请创建一个私有 class ServiceHandler
扩展 Handler
和 运行 handleMessage
方法中的代码。
实现此模式的应用是 DU Battery Saver。