如何在前台服务中将多个任务排队,让它们一个一个执行?
How to queue multiple tasks in a foreground service, so that they execute one by one?
public class CopyService extends Service {
private List<CustomFile> taskList;
private AsyncTask fileTask;
@Override
public void onCreate() {
super.onCreate();
taskList = new ArrayList<>();
fileTask = new fileTaskAsync();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String filePath = intent.getStringExtra("filePath");
String fileType = intent.getStringExtra("fileType");
String taskType = intent.getStringExtra("taskType");
String fileName = intent.getStringExtra("fileName");
CustomFile customFile = new CustomFile();
customFile.filePath = filePath;
customFile.fileType = fileType;
customFile.taskType = taskType;
customFile.fileName = fileName;
taskList.add(customFile);
Notification notification = getNotification();
startForeground(787, notification);
if (fileTask.getStatus() != AsyncTask.Status.RUNNING) {
CustomFile current = taskList.get(0);
taskList.remove(current);
fileTask = new fileTaskAsync().execute(current);
}
stopSelf();
return START_NOT_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private class fileTaskAsync extends AsyncTask<CustomFile, Void, String> {
@Override
protected String doInBackground(CustomFile... customFiles) {
CustomFile customFile = customFiles[0];
FileUtils.doFileTask(customFile.filePath, customFile.fileType,
customFile.taskType);
return customFile.fileName;
}
@Override
protected void onPostExecute(String name) {
sendResult(name);
if (!taskList.isEmpty()) {
CustomFile newCurrent = taskList.get(0);
taskList.remove(newCurrent);
fileTask = new fileTaskAsync().execute(newCurrent);
}
}
}
private void sendResult(String name) {
Intent intent = new Intent("taskStatus");
intent.putExtra("taskName", name);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
我需要在一个服务中一个一个地执行多个任务。任务是复制或移动本地文件。假设,用户正在复制一个大文件,他想复制或移动其他文件。我需要后续任务一个一个排队执行
目前,我正在服务中创建一个列表,运行 一个异步任务。在 onPostExecute 中,我检查列表中的剩余任务并从那里再次启动异步任务。如代码所示。
但是,我担心内存泄漏。而且我对编程很陌生,所以我不知道在这种情况下最好的做法是什么。
我不能使用 IntentService,因为我希望即使用户按下主页按钮打开其他应用程序,任务也能继续。
正如我在评论中所说,我认为你的解决方案是合理的。前景 Service
适合需要立即执行的长时间 运行 工作,根据您的描述,您的文件复制任务符合该条件。
也就是说,我认为 AsyncTask
不适合您的问题。当您需要在主线程之外做一些快速工作时,最好部署 AsyncTasks,最多大约几百毫秒,而您的复制任务可能需要几秒钟。
由于您有多个任务要完成,这些任务并不直接相互依赖,我建议您使用线程池来完成这项工作。为此,您可以使用 ExecutorService
:
public class CopyService extends Service {
private final Deque<CustomFile> tasks = new ArrayDeque<>();
private final Deque<Future<?>> futures = new LinkedBlockingDequeue<>();
private final ExecutorService executor = Executors.newCachedThreadPool();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//May as well add a factory method to your CustomFile that creates one from an Intent
CustomFile customFile = CustomFile.fromIntent(intent);
tasks.offer(customFile);
//...Add any other tasks to this queue...
Notification notification = getNotification();
startForeground(787, notification);
for(CustomFile file : tasks) {
final Future<?> future = executor.submit(new Runnable() {
@Override
public void run() {
final CustomFile file = tasks.poll();
//Ddo work with the file...
LocalBroadcastManager.getInstance(CopyService.this).sendBroadcast(...);
//Check to see whether we've now executed all tasks. If we have, kill the Service.
if(tasks.isEmpty()) stopSelf();
}
});
futures.offer(future);
}
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
//Clear pending and active work if the Service is being shutdown
//You may want to think about whether you want to reschedule any work here too
for(Future<?> future : futures) {
if(!future.isDone() && !future.isCancelled()) {
future.cancel(true); //May pass "false" here. Terminating work immediately may produce side effects.
}
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
这不应导致任何内存泄漏,因为任何待处理的工作都会随服务一起销毁。
public class CopyService extends Service {
private List<CustomFile> taskList;
private AsyncTask fileTask;
@Override
public void onCreate() {
super.onCreate();
taskList = new ArrayList<>();
fileTask = new fileTaskAsync();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String filePath = intent.getStringExtra("filePath");
String fileType = intent.getStringExtra("fileType");
String taskType = intent.getStringExtra("taskType");
String fileName = intent.getStringExtra("fileName");
CustomFile customFile = new CustomFile();
customFile.filePath = filePath;
customFile.fileType = fileType;
customFile.taskType = taskType;
customFile.fileName = fileName;
taskList.add(customFile);
Notification notification = getNotification();
startForeground(787, notification);
if (fileTask.getStatus() != AsyncTask.Status.RUNNING) {
CustomFile current = taskList.get(0);
taskList.remove(current);
fileTask = new fileTaskAsync().execute(current);
}
stopSelf();
return START_NOT_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private class fileTaskAsync extends AsyncTask<CustomFile, Void, String> {
@Override
protected String doInBackground(CustomFile... customFiles) {
CustomFile customFile = customFiles[0];
FileUtils.doFileTask(customFile.filePath, customFile.fileType,
customFile.taskType);
return customFile.fileName;
}
@Override
protected void onPostExecute(String name) {
sendResult(name);
if (!taskList.isEmpty()) {
CustomFile newCurrent = taskList.get(0);
taskList.remove(newCurrent);
fileTask = new fileTaskAsync().execute(newCurrent);
}
}
}
private void sendResult(String name) {
Intent intent = new Intent("taskStatus");
intent.putExtra("taskName", name);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
我需要在一个服务中一个一个地执行多个任务。任务是复制或移动本地文件。假设,用户正在复制一个大文件,他想复制或移动其他文件。我需要后续任务一个一个排队执行
目前,我正在服务中创建一个列表,运行 一个异步任务。在 onPostExecute 中,我检查列表中的剩余任务并从那里再次启动异步任务。如代码所示。
但是,我担心内存泄漏。而且我对编程很陌生,所以我不知道在这种情况下最好的做法是什么。
我不能使用 IntentService,因为我希望即使用户按下主页按钮打开其他应用程序,任务也能继续。
正如我在评论中所说,我认为你的解决方案是合理的。前景 Service
适合需要立即执行的长时间 运行 工作,根据您的描述,您的文件复制任务符合该条件。
也就是说,我认为 AsyncTask
不适合您的问题。当您需要在主线程之外做一些快速工作时,最好部署 AsyncTasks,最多大约几百毫秒,而您的复制任务可能需要几秒钟。
由于您有多个任务要完成,这些任务并不直接相互依赖,我建议您使用线程池来完成这项工作。为此,您可以使用 ExecutorService
:
public class CopyService extends Service {
private final Deque<CustomFile> tasks = new ArrayDeque<>();
private final Deque<Future<?>> futures = new LinkedBlockingDequeue<>();
private final ExecutorService executor = Executors.newCachedThreadPool();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//May as well add a factory method to your CustomFile that creates one from an Intent
CustomFile customFile = CustomFile.fromIntent(intent);
tasks.offer(customFile);
//...Add any other tasks to this queue...
Notification notification = getNotification();
startForeground(787, notification);
for(CustomFile file : tasks) {
final Future<?> future = executor.submit(new Runnable() {
@Override
public void run() {
final CustomFile file = tasks.poll();
//Ddo work with the file...
LocalBroadcastManager.getInstance(CopyService.this).sendBroadcast(...);
//Check to see whether we've now executed all tasks. If we have, kill the Service.
if(tasks.isEmpty()) stopSelf();
}
});
futures.offer(future);
}
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
//Clear pending and active work if the Service is being shutdown
//You may want to think about whether you want to reschedule any work here too
for(Future<?> future : futures) {
if(!future.isDone() && !future.isCancelled()) {
future.cancel(true); //May pass "false" here. Terminating work immediately may produce side effects.
}
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
这不应导致任何内存泄漏,因为任何待处理的工作都会随服务一起销毁。