rewrote Downloading process
This commit is contained in:
parent
d1db888141
commit
491f2a2f58
|
@ -27,10 +27,5 @@
|
||||||
<activity android:name="de.podfetcher.activity.AddFeedActivity"/>
|
<activity android:name="de.podfetcher.activity.AddFeedActivity"/>
|
||||||
|
|
||||||
<service android:enabled="true" android:name="de.podfetcher.service.DownloadService" />
|
<service android:enabled="true" android:name="de.podfetcher.service.DownloadService" />
|
||||||
<service android:enabled="true" android:name="de.podfetcher.service.FeedSyncService" >
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="action.de.podfetcher.storage.feed_download_completed"></action>
|
|
||||||
</intent-filter>
|
|
||||||
</service>
|
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package de.podfetcher.feed;
|
package de.podfetcher.feed;
|
||||||
|
|
||||||
|
/** Represents a component of a Feed that has to be downloaded*/
|
||||||
public abstract class FeedFile extends FeedComponent {
|
public abstract class FeedFile extends FeedComponent {
|
||||||
protected String file_url;
|
protected String file_url;
|
||||||
protected String download_url;
|
protected String download_url;
|
||||||
|
protected long downloadId; // temporary id given by the Android DownloadManager
|
||||||
|
|
||||||
public String getFile_url() {
|
public String getFile_url() {
|
||||||
return file_url;
|
return file_url;
|
||||||
|
@ -16,7 +18,12 @@ public abstract class FeedFile extends FeedComponent {
|
||||||
public void setDownload_url(String download_url) {
|
public void setDownload_url(String download_url) {
|
||||||
this.download_url = download_url;
|
this.download_url = download_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public long getDownloadId() {
|
||||||
|
return downloadId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDownloadId(long downloadId) {
|
||||||
|
this.downloadId = downloadId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
package de.podfetcher.service;
|
package de.podfetcher.service;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import de.podfetcher.feed.*;
|
import de.podfetcher.feed.*;
|
||||||
import de.podfetcher.storage.DownloadRequester;
|
import de.podfetcher.storage.DownloadRequester;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
|
@ -21,14 +23,19 @@ import android.util.Log;
|
||||||
public class DownloadService extends Service {
|
public class DownloadService extends Service {
|
||||||
|
|
||||||
public static String ACTION_ALL_FEED_DOWNLOADS_COMPLETED = "action.de.podfetcher.storage.all_feed_downloads_completed";
|
public static String ACTION_ALL_FEED_DOWNLOADS_COMPLETED = "action.de.podfetcher.storage.all_feed_downloads_completed";
|
||||||
|
public static final String ACTION_FEED_SYNC_COMPLETED = "action.de.podfetcher.service.feed_sync_completed";
|
||||||
|
|
||||||
|
private volatile ScheduledThreadPoolExecutor syncExecutor;
|
||||||
private DownloadRequester requester;
|
private DownloadRequester requester;
|
||||||
private FeedManager manager;
|
private FeedManager manager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
Log.d(this.toString(), "Service started");
|
Log.d(this.toString(), "Service started");
|
||||||
registerReceiver(receiver, createIntentFilter());
|
registerReceiver(downloadReceiver, createIntentFilter());
|
||||||
|
syncExecutor = new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors() + 2);
|
||||||
|
manager = FeedManager.getInstance();
|
||||||
|
requester = DownloadRequester.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -38,49 +45,62 @@ public class DownloadService extends Service {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
unregisterReceiver(receiver);
|
Log.d(this.toString(), "Service shutting down");
|
||||||
|
sendBroadcast(new Intent(ACTION_FEED_SYNC_COMPLETED));
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntentFilter createIntentFilter() {
|
private IntentFilter createIntentFilter() {
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
|
|
||||||
filter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
|
filter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
|
||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BroadcastReceiver receiver = new BroadcastReceiver() {
|
/** Shuts down Executor service and prepares for shutdown */
|
||||||
|
private void initiateShutdown() {
|
||||||
|
Log.d(this.toString(), "Initiating shutdown");
|
||||||
|
// Wait until PoolExecutor is done
|
||||||
|
Thread waiter = new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
syncExecutor.shutdown();
|
||||||
|
try {
|
||||||
|
syncExecutor.awaitTermination(20, TimeUnit.SECONDS);
|
||||||
|
stopSelf();
|
||||||
|
}catch(InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
waiter.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
|
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
|
||||||
requester = DownloadRequester.getInstance();
|
Feed feed = requester.getFeed(downloadId);
|
||||||
manager = FeedManager.getInstance();
|
if(feed != null) {
|
||||||
Intent item_intent = requester.getItemIntent(id);
|
handleCompletedFeedDownload(context, feed);
|
||||||
String action = item_intent.getAction();
|
}else {
|
||||||
if(action.equals(DownloadRequester.ACTION_FEED_DOWNLOAD_COMPLETED)) {
|
FeedImage image = requester.getFeedImage(downloadId);
|
||||||
handleCompletedFeedDownload(context, item_intent);
|
if(image != null) {
|
||||||
if(requester.getNumberOfFeedDownloads() == 0) {
|
handleCompletedImageDownload(context, image);
|
||||||
sendBroadcast(new Intent(ACTION_ALL_FEED_DOWNLOADS_COMPLETED));
|
|
||||||
}
|
}
|
||||||
} else if(action.equals(DownloadRequester.ACTION_MEDIA_DOWNLOAD_COMPLETED)) {
|
|
||||||
requester.removeMediaByID(item_intent.getLongExtra(DownloadRequester.EXTRA_ITEM_ID, -1));
|
|
||||||
} else if(action.equals(DownloadRequester.ACTION_IMAGE_DOWNLOAD_COMPLETED)) {
|
|
||||||
handleCompletedImageDownload(context, item_intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there's something else to download, otherwise stop
|
// Check if there's something else to download, otherwise stop
|
||||||
if(requester.getNumberOfDownloads() == 0) {
|
if(requester.getNumberOfDownloads() == 0) {
|
||||||
stopSelf();
|
unregisterReceiver(downloadReceiver);
|
||||||
|
initiateShutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Is called whenever a Feed is downloaded */
|
/** Is called whenever a Feed is downloaded */
|
||||||
private void handleCompletedFeedDownload(Context context, Intent intent) {
|
private void handleCompletedFeedDownload(Context context, Feed feed) {
|
||||||
requester.removeFeedByID(intent.getLongExtra(DownloadRequester.EXTRA_ITEM_ID, -1));
|
requester.removeFeed(feed);
|
||||||
// Get Feed Information
|
// Get Feed Information
|
||||||
Feed feed = manager.getFeed(intent.getLongExtra(DownloadRequester.EXTRA_ITEM_ID, -1));
|
|
||||||
feed.setFile_url((new File(requester.getFeedfilePath(context), requester.getFeedfileName(feed.getId()))).toString());
|
feed.setFile_url((new File(requester.getFeedfilePath(context), requester.getFeedfileName(feed.getId()))).toString());
|
||||||
// Update Information in Database
|
// Update Information in Database
|
||||||
manager.setFeed(context, feed);
|
manager.setFeed(context, feed);
|
||||||
|
@ -88,15 +108,39 @@ public class DownloadService extends Service {
|
||||||
if(feed.getImage() != null) {
|
if(feed.getImage() != null) {
|
||||||
requester.downloadImage(context, feed.getImage());
|
requester.downloadImage(context, feed.getImage());
|
||||||
}
|
}
|
||||||
context.startService(intent);
|
syncExecutor.submit(new FeedSyncThread(feed, this));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Is called whenever a Feed-Image is downloaded */
|
/** Is called whenever a Feed-Image is downloaded */
|
||||||
private void handleCompletedImageDownload(Context context, Intent intent) {
|
private void handleCompletedImageDownload(Context context, FeedImage image) {
|
||||||
requester.removeImageByID(intent.getLongExtra(DownloadRequester.EXTRA_ITEM_ID, -1));
|
requester.removeFeedImage(image);
|
||||||
FeedImage image = manager.getFeedImage(intent.getLongExtra(DownloadRequester.EXTRA_ITEM_ID, -1));
|
|
||||||
image.setFile_url(requester.getImagefilePath(context) + requester.getImagefileName(image.getId()));
|
image.setFile_url(requester.getImagefilePath(context) + requester.getImagefileName(image.getId()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Takes a single Feed, parses the corresponding file and refreshes information in the manager */
|
||||||
|
class FeedSyncThread implements Runnable {
|
||||||
|
|
||||||
|
private Feed feed;
|
||||||
|
private DownloadService service;
|
||||||
|
|
||||||
|
public FeedSyncThread(Feed feed, DownloadService service) {
|
||||||
|
this.feed = feed;
|
||||||
|
this.service = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
FeedManager manager = FeedManager.getInstance();
|
||||||
|
FeedHandler handler = new FeedHandler();
|
||||||
|
|
||||||
|
feed = handler.parseFeed(feed);
|
||||||
|
Log.d(this.toString(), feed.getTitle() + " parsed");
|
||||||
|
// Add Feeditems to the database
|
||||||
|
for(FeedItem item : feed.getItems()) {
|
||||||
|
manager.addFeedItem(service, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,7 @@ public class FeedSyncService extends Service {
|
||||||
|
|
||||||
/** Prepares itself for stopping */
|
/** Prepares itself for stopping */
|
||||||
private void initiateShutdown() {
|
private void initiateShutdown() {
|
||||||
|
Log.d(this.toString(), "Initiating shutdown");
|
||||||
// Wait until PoolExecutor is done
|
// Wait until PoolExecutor is done
|
||||||
Thread waiter = new Thread() {
|
Thread waiter = new Thread() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -3,11 +3,10 @@ package de.podfetcher.storage;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import de.podfetcher.feed.Feed;
|
import de.podfetcher.feed.*;
|
||||||
import de.podfetcher.feed.FeedImage;
|
|
||||||
import de.podfetcher.feed.FeedMedia;
|
|
||||||
import de.podfetcher.service.DownloadService;
|
import de.podfetcher.service.DownloadService;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
import android.app.DownloadManager;
|
import android.app.DownloadManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
@ -30,14 +29,14 @@ public class DownloadRequester {
|
||||||
|
|
||||||
private static DownloadRequester downloader;
|
private static DownloadRequester downloader;
|
||||||
|
|
||||||
public ArrayList<Intent> feeds;
|
public ArrayList<FeedFile> feeds;
|
||||||
public ArrayList<Intent> images;
|
public ArrayList<FeedFile> images;
|
||||||
public ArrayList<Intent> media;
|
public ArrayList<FeedFile> media;
|
||||||
|
|
||||||
private DownloadRequester(){
|
private DownloadRequester(){
|
||||||
feeds = new ArrayList<Intent>();
|
feeds = new ArrayList<FeedFile>();
|
||||||
images = new ArrayList<Intent>();
|
images = new ArrayList<FeedFile>();
|
||||||
media = new ArrayList<Intent>();
|
media = new ArrayList<FeedFile>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,89 +47,81 @@ public class DownloadRequester {
|
||||||
return downloader;
|
return downloader;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void download(Context context, ArrayList<Intent> type, String str_uri, File dest, boolean visibleInUI, String action, long id) {
|
private void download(Context context, ArrayList<FeedFile> type, FeedFile item, File dest, boolean visibleInUI) {
|
||||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(str_uri));
|
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(item.getDownload_url()));
|
||||||
//request.allowScanningByMediaScanner();
|
//request.allowScanningByMediaScanner();
|
||||||
|
|
||||||
request.setDestinationUri(Uri.fromFile(dest));
|
request.setDestinationUri(Uri.fromFile(dest));
|
||||||
request.setVisibleInDownloadsUi(visibleInUI);
|
request.setVisibleInDownloadsUi(visibleInUI);
|
||||||
// TODO Set Allowed Network Types
|
// TODO Set Allowed Network Types
|
||||||
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||||
Intent i = new Intent(action);
|
|
||||||
context.startService(new Intent(context, DownloadService.class));
|
context.startService(new Intent(context, DownloadService.class));
|
||||||
i.putExtra(EXTRA_DOWNLOAD_ID, manager.enqueue(request));
|
item.setDownloadId(manager.enqueue(request));
|
||||||
i.putExtra(EXTRA_ITEM_ID, id);
|
type.add(item);
|
||||||
type.add(i);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
public void downloadFeed(Context context, Feed feed) {
|
public void downloadFeed(Context context, Feed feed) {
|
||||||
download(context, feeds, feed.getDownload_url(),
|
download(context, feeds, feed,
|
||||||
new File(getFeedfilePath(context), getFeedfileName(feed.getId())),
|
new File(getFeedfilePath(context), getFeedfileName(feed.getId())),
|
||||||
true, ACTION_FEED_DOWNLOAD_COMPLETED, feed.getId());
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void downloadImage(Context context, FeedImage image) {
|
public void downloadImage(Context context, FeedImage image) {
|
||||||
download(context, images, image.getDownload_url(),
|
download(context, images, image,
|
||||||
new File(getImagefilePath(context), getImagefileName(image.getId())),
|
new File(getImagefilePath(context), getImagefileName(image.getId())),
|
||||||
true, ACTION_IMAGE_DOWNLOAD_COMPLETED, image.getId());
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void downloadMedia(Context context, FeedMedia feedmedia) {
|
public void downloadMedia(Context context, FeedMedia feedmedia) {
|
||||||
download(context, media, feedmedia.getDownload_url(),
|
download(context, media, feedmedia,
|
||||||
new File(context.getExternalFilesDir(MEDIA_DOWNLOADPATH), "media-" + feedmedia.getId()),
|
new File(context.getExternalFilesDir(MEDIA_DOWNLOADPATH), "media-" + feedmedia.getId()),
|
||||||
true, ACTION_MEDIA_DOWNLOAD_COMPLETED, feedmedia.getId());
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeFeedByID(long id) {
|
/** Get a Feed by its download id */
|
||||||
int len = feeds.size();
|
public Feed getFeed(long id) {
|
||||||
for(int x = 0; x < len; x++) {
|
for(FeedFile f: feeds) {
|
||||||
if(feeds.get(x).getLongExtra(EXTRA_ITEM_ID, -1) == id) {
|
if(f.getDownloadId() == id) {
|
||||||
feeds.remove(x);
|
return (Feed) f;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeMediaByID(long id) {
|
|
||||||
int len = media.size();
|
|
||||||
for(int x = 0; x < len; x++) {
|
|
||||||
if(media.get(x).getLongExtra(EXTRA_ITEM_ID, -1) == id) {
|
|
||||||
media.remove(x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeImageByID(long id) {
|
|
||||||
int len = images.size();
|
|
||||||
for(int x = 0; x < len; x++) {
|
|
||||||
if(images.get(x).getLongExtra(EXTRA_ITEM_ID, -1) == id) {
|
|
||||||
images.remove(x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the stored intent by looking for the right download id */
|
|
||||||
public Intent getItemIntent(long id) {
|
|
||||||
for(Intent i : feeds) {
|
|
||||||
if(i.getLongExtra(EXTRA_DOWNLOAD_ID, -1) == id) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(Intent i : media) {
|
|
||||||
if(i.getLongExtra(EXTRA_DOWNLOAD_ID, -1) == id) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(Intent i : images) {
|
|
||||||
if(i.getLongExtra(EXTRA_DOWNLOAD_ID, -1) == id) {
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get a FeedImage by its download id */
|
||||||
|
public FeedImage getFeedImage(long id) {
|
||||||
|
for(FeedFile f: images) {
|
||||||
|
if(f.getDownloadId() == id) {
|
||||||
|
return (FeedImage) f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Get media by its download id */
|
||||||
|
public FeedMedia getFeedMedia(long id) {
|
||||||
|
for(FeedFile f: media) {
|
||||||
|
if(f.getDownloadId() == id) {
|
||||||
|
return (FeedMedia) f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFeed(Feed f) {
|
||||||
|
feeds.remove(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFeedMedia(FeedMedia m) {
|
||||||
|
media.remove(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFeedImage(FeedImage fi) {
|
||||||
|
images.remove(fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Get the number of uncompleted Downloads */
|
/** Get the number of uncompleted Downloads */
|
||||||
public int getNumberOfDownloads() {
|
public int getNumberOfDownloads() {
|
||||||
return feeds.size() + images.size() + media.size();
|
return feeds.size() + images.size() + media.size();
|
||||||
|
|
Loading…
Reference in New Issue