Как я уже сказал в комментариях, я думаю, что ваше решение является разумным.Foreground Service
является хорошим кандидатом для длительной работы, которая должна быть выполнена немедленно, и из вашего описания ваша задача копирования файлов соответствует этому критерию.
Тем не менее, я не верю, что AsyncTask
хороший кандидат на вашу проблему.AsyncTasks лучше всего развертывать, когда вам нужно выполнить некоторую быструю работу вне основного потока, порядка нескольких сотен миллисекунд, в то время как ваша задача копирования может занять несколько секунд.
Поскольку у вас есть несколько задач дляcomplete, которые напрямую не зависят друг от друга, я бы порекомендовал вам использовать пул потоков для выполнения этой работы.Для этого вы можете использовать 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;
}
Это не должно вызывать утечек памяти, так как любая ожидающая работа уничтожается вместе со службой.