我创建了一个使用对象DownloadService1
的服务downloadData1
。现在我想通过使用对象simultaneously
和downloadData1
执行2次下载操作downloadData2
,但我不想创建extact
的DownloadService1
副本,说DownloadService2
将与downloadData2
一起使用。有没有办法创建多个服务实例来实现我想要的?
如何在Android中创建多个服务实例?
AFAIK无法创建多个服务实例
只运行一个服务实例
如果多次调用startService()
不会导致启动多个服务。
当你打电话给startService()
时,有两种可能性
如果Service in之前未启动,则它将按服务生命周期启动
如果先前已启动Service,则只会调用
onStartCammand()
并将其传递给您所需的意图。
欲了解更多信息,请阅读docs service
如何创建一个可以同时处理多个下载的对象,然后您可以在服务中使用此对象。您可以查看我的解决方法以进行下载:
public class MediaDownloadClient extends MediaDownloadListener implements Runnable {
private static final int DOWNLOAD_TRACKER_BREAK = 500; //ms
private static MediaDownloadClient singleton;
private final Object lock = new Object();
private OkHttpClient mHttpClient;
private Thread downloadThread;//main download thread
private ExecutorService threadPool = Executors.newCachedThreadPool();
private boolean downloading = false, running = false;
private Queue<MediaDownloadEntry> downloadQueue = new ArrayDeque<>();
private int stopDownloadId = 0;
private MediaDownloadClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(15000, TimeUnit.SECONDS);
builder.readTimeout(15000, TimeUnit.SECONDS);
mHttpClient = builder.build();
}
public static MediaDownloadClient getInstance() {
if (singleton == null) {
singleton = new MediaDownloadClient();
singleton.start();
}
return singleton;
}
public static boolean download(String url, String toPath) throws IOException {
if (url == null || toPath == null) return false;
OkHttpClient okHttpClient = new OkHttpClient();
Request.Builder builder = new Request.Builder().url(url);
Response response = okHttpClient.newCall(builder.build()).execute();
if (!response.isSuccessful()) return false;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(response.body().byteStream());
bos = new BufferedOutputStream(new FileOutputStream(toPath));
byte[] buffer = new byte[1024 * 200];
int read;
while ((read = bis.read(buffer)) != -1) {
bos.write(buffer, 0, read);
}
} finally {
if (bos != null) bos.close();
if (bis != null) bis.close();
}
return true;
}
public void addListener(Listener listener) {
super.addListener(listener);
}
public void removeListener(Listener listener) {
super.removeListener(listener);
}
public void queue(MediaModel item, String toPath) {
MediaDownloadEntry download = new MediaDownloadEntry();
download.setMedia(item);
//serving as downloadId.. to keep track of the download
download.downloadId = 2 + new Random().nextInt(Integer.MAX_VALUE);
download.downloadTo = toPath;
download.downloadState = MediaDownloadEntry.STATE_QUEUED;
downloadQueue.add(download);
dispatchDownloadEvent(download, MediaDownloadEntry.STATE_QUEUED);
synchronized (lock) {
lock.notify();
}
}
public void queue(String url, String fileName, String toPath, int mediaType) {
MediaDownloadEntry model = new MediaDownloadEntry();
model.dataUrl = url;
model.mediaType = mediaType;
model.fileName = fileName;
queue(model, toPath);
}
@Override
public void run() {
while (running) {
synchronized (lock) {
while (downloading || downloadQueue.size() == 0) {
try {
lock.wait();
} catch (Exception ignored) {
}
}
try {
MediaDownloadEntry queue = downloadQueue.poll();
if (queue != null) {
downloading = true;
download(queue);
}
} catch (Exception ignored) {
}
downloading = false;
lock.notify();
}
}
}
private void start() {
if (downloadThread == null)
downloadThread = new Thread(this);
downloadThread.start();
running = true;
}
private void download(MediaDownloadEntry queue) {
DownloadTracker tracker = new DownloadTracker(queue);
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
Request.Builder builder = new Request.Builder().url(queue.dataUrl);
Response response = mHttpClient.newCall(builder.build()).execute();
bis = new BufferedInputStream(response.body().byteStream());
bos = new BufferedOutputStream(new FileOutputStream(queue.downloadTo));
if (queue.fileSize == 0) {
String len = response.header("Content-Length", "0");
queue.fileSize = Integer.parseInt(len);
}
if (queue.fileName == null) {
queue.fileName = response.header("Content-Name", "file");
}
if (queue.mimeType == null) {
queue.mimeType = response.header("Content-Type", "media");
}
queue.downloadState = MediaDownloadEntry.STATE_START;
dispatchDownloadEvent(queue, MediaDownloadEntry.STATE_START);
downloadTracker(tracker);//start download tracking
byte[] buffer = new byte[1024 * 1000];//1MB buffer allocated
while ((tracker.read = bis.read(buffer)) != -1) {
if (stopDownloadId == queue.downloadId) {
queue.downloadState = MediaDownloadEntry.ERROR;
dispatchDownloadEvent(queue, MediaDownloadEntry.ERROR);
break;
}
tracker.count += tracker.read;
bos.write(buffer, 0, tracker.read);
}
queue.downloadState = MediaDownloadEntry.STATE_COMPLETED;
dispatchDownloadEvent(queue, MediaDownloadEntry.STATE_COMPLETED);
} catch (Exception e) {
tracker.read = -1;//to terminate tracker
queue.downloadState = MediaDownloadEntry.ERROR;
dispatchDownloadEvent(queue, MediaDownloadEntry.ERROR);
} finally {
try {
if (bis != null) bis.close();
if (bos != null) bos.close();
} catch (Exception ignored) {
}
}
}
public void stopDownload(int downloadId) {
stopDownloadId = downloadId;
}
private void downloadTracker(final DownloadTracker tracker) {
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(DOWNLOAD_TRACKER_BREAK); //pause to allow first updateLike
while (tracker.read != -1) {
tracker.download.downloadCount = tracker.count;
tracker.download.downloadState = MediaDownloadEntry.STATE_PROGRESS;
dispatchDownloadEvent(tracker.download, MediaDownloadEntry.STATE_PROGRESS);
Thread.sleep(DOWNLOAD_TRACKER_BREAK); //break for another 300ms
}
} catch (Exception ignored) {
}
}//end run
});
}
public void terminate() {
running = false;
downloadQueue = null;
}
private class DownloadTracker {
int read, count;
MediaDownloadEntry download;
DownloadTracker(MediaDownloadEntry model) {
this.download = model;
}
}
}
public class MediaDownloadEntry extends MediaModel {
public static final int ERROR = -1;
public static final int STATE_QUEUED = 0;
public static final int STATE_PROGRESS = 1;
public static final int STATE_START = 1;
public static final int STATE_COMPLETED = 2;
public int downloadCount, downloadState;
public int downloadId;
public String downloadUrl, downloadTo;
@Override
public boolean equals(Object o) {
return ((MediaDownloadEntry) o).downloadId == downloadId;
}
}