rewrote Downloading process

This commit is contained in:
Daniel Oeh 2011-12-29 21:05:22 +01:00
parent d1db888141
commit 491f2a2f58
5 changed files with 139 additions and 101 deletions

View File

@ -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>

View File

@ -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;
@ -17,6 +19,11 @@ public abstract class FeedFile extends FeedComponent {
this.download_url = download_url; this.download_url = download_url;
} }
public long getDownloadId() {
return downloadId;
}
public void setDownloadId(long downloadId) {
this.downloadId = downloadId;
}
} }

View File

@ -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);
}
}
}
} }

View File

@ -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

View File

@ -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();