diff options
author | daniel oeh <daniel.oeh@gmail.com> | 2012-11-11 17:45:48 +0100 |
---|---|---|
committer | daniel oeh <daniel.oeh@gmail.com> | 2012-11-11 17:45:48 +0100 |
commit | 7f92cdce70cb6b9d84186a7aa2b4cd58e03b6b69 (patch) | |
tree | ab84de04edbe526e59fb4635bbcb1e337b26493c /src/de/danoeh/antennapod/feed | |
parent | 1210c7a8a4448ba2b0ac017bd7cb16ea4a5704e8 (diff) | |
parent | 8e7a4025543840b7f984fed1db9b9ea08e03a679 (diff) | |
download | AntennaPod-7f92cdce70cb6b9d84186a7aa2b4cd58e03b6b69.zip |
Merge branch 'description_update' into develop
Conflicts:
src/de/danoeh/antennapod/feed/FeedItem.java
Diffstat (limited to 'src/de/danoeh/antennapod/feed')
-rw-r--r-- | src/de/danoeh/antennapod/feed/Feed.java | 9 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/feed/FeedItem.java | 67 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/feed/FeedManager.java | 188 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/feed/FeedSearcher.java | 157 |
4 files changed, 333 insertions, 88 deletions
diff --git a/src/de/danoeh/antennapod/feed/Feed.java b/src/de/danoeh/antennapod/feed/Feed.java index 6cea571f6..55256ea31 100644 --- a/src/de/danoeh/antennapod/feed/Feed.java +++ b/src/de/danoeh/antennapod/feed/Feed.java @@ -144,6 +144,15 @@ public class Feed extends FeedFile { return download_url; } } + + /** Calls cacheDescriptions on all items. */ + protected void cacheDescriptionsOfItems() { + if (items != null) { + for (FeedItem item : items) { + item.cacheDescriptions(); + } + } + } @Override public int getTypeAsInt() { diff --git a/src/de/danoeh/antennapod/feed/FeedItem.java b/src/de/danoeh/antennapod/feed/FeedItem.java index 93655f8cb..6227298df 100644 --- a/src/de/danoeh/antennapod/feed/FeedItem.java +++ b/src/de/danoeh/antennapod/feed/FeedItem.java @@ -1,5 +1,6 @@ package de.danoeh.antennapod.feed; +import java.lang.ref.SoftReference; import java.util.Date; import java.util.List; @@ -13,11 +14,23 @@ import de.danoeh.antennapod.PodcastApp; */ public class FeedItem extends FeedComponent { - /** The id/guid that can be found in the rss/atom feed. Might not be set.*/ + /** The id/guid that can be found in the rss/atom feed. Might not be set. */ private String itemIdentifier; private String title; + /** + * The description of a feeditem. This field should only be set by the + * parser. + */ private String description; + /** + * The content of the content-encoded tag of a feeditem. This field should + * only be set by the parser. + */ private String contentEncoded; + + private SoftReference<String> cachedDescription; + private SoftReference<String> cachedContentEncoded; + private String link; private Date pubDate; private FeedMedia media; @@ -30,16 +43,19 @@ public class FeedItem extends FeedComponent { this.read = true; } - public FeedItem(String title, String description, String link, - Date pubDate, FeedMedia media, Feed feed) { - super(); - this.title = title; - this.description = description; - this.link = link; - this.pubDate = pubDate; - this.media = media; - this.feed = feed; - this.read = true; + /** + * Moves the 'description' and 'contentEncoded' field of feeditem to their + * SoftReference fields. + */ + protected void cacheDescriptions() { + if (description != null) { + cachedDescription = new SoftReference<String>(description); + } + if (contentEncoded != null) { + cachedContentEncoded = new SoftReference<String>(contentEncoded); + } + description = null; + contentEncoded = null; } /** Get the chapter that fits the position. */ @@ -62,11 +78,12 @@ public class FeedItem extends FeedComponent { public Chapter getCurrentChapter() { return getCurrentChapter(media.getPosition()); } - - /** Returns the value that uniquely identifies this FeedItem. - * If the itemIdentifier attribute is not null, it will be returned. - * Else it will try to return the title. If the title is not given, it will - * use the link of the entry. + + /** + * Returns the value that uniquely identifies this FeedItem. If the + * itemIdentifier attribute is not null, it will be returned. Else it will + * try to return the title. If the title is not given, it will use the link + * of the entry. * */ public String getIdentifyingValue() { if (itemIdentifier != null) { @@ -87,6 +104,9 @@ public class FeedItem extends FeedComponent { } public String getDescription() { + if (description == null && cachedDescription != null) { + return cachedDescription.get(); + } return description; } @@ -131,6 +151,10 @@ public class FeedItem extends FeedComponent { } public String getContentEncoded() { + if (contentEncoded == null && cachedContentEncoded != null) { + return cachedContentEncoded.get(); + + } return contentEncoded; } @@ -161,7 +185,7 @@ public class FeedItem extends FeedComponent { public void setItemIdentifier(String itemIdentifier) { this.itemIdentifier = itemIdentifier; } - + public boolean isPlaying() { if (media != null) { if (PodcastApp.getCurrentlyPlayingMediaId() == media.getId()) { @@ -170,6 +194,13 @@ public class FeedItem extends FeedComponent { } return false; } - + + public void setCachedDescription(String d) { + cachedDescription = new SoftReference<String>(d); + } + + public void setCachedContentEncoded(String c) { + cachedContentEncoded = new SoftReference<String>(c); + } } diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index 3f774b4bd..7f4a1c5aa 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -774,6 +774,7 @@ public class FeedManager { PodDBAdapter adapter = new PodDBAdapter(context); adapter.open(); adapter.setCompleteFeed(feed); + feed.cacheDescriptionsOfItems(); adapter.close(); } }); @@ -867,6 +868,7 @@ public class FeedManager { public void setFeed(Feed feed, PodDBAdapter adapter) { if (adapter != null) { adapter.setFeed(feed); + feed.cacheDescriptionsOfItems(); } else { Log.w(TAG, "Adapter in setFeed was null"); } @@ -914,6 +916,7 @@ public class FeedManager { PodDBAdapter adapter = new PodDBAdapter(context); adapter.open(); adapter.setFeed(feed); + feed.cacheDescriptionsOfItems(); adapter.close(); } }); @@ -1009,6 +1012,19 @@ public class FeedManager { return null; } + /** Get a FeedItem by its id and the id of its feed. */ + public FeedItem getFeedItem(long itemId, long feedId) { + Feed feed = getFeed(feedId); + if (feed != null && feed.getItems() != null) { + for (FeedItem item : feed.getItems()) { + if (item.getId() == itemId) { + return item; + } + } + } + return null; + } + /** Get a FeedMedia object by the id of the Media object and the feed object */ public FeedMedia getFeedMedia(long id, Feed feed) { if (feed != null) { @@ -1129,37 +1145,34 @@ public class FeedManager { do { FeedItem item = new FeedItem(); - item.id = itemlistCursor.getLong(PodDBAdapter.KEY_ID_INDEX); + item.id = itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_ID); item.setFeed(feed); item.setTitle(itemlistCursor - .getString(PodDBAdapter.KEY_TITLE_INDEX)); + .getString(PodDBAdapter.IDX_FI_SMALL_TITLE)); item.setLink(itemlistCursor - .getString(PodDBAdapter.KEY_LINK_INDEX)); - item.setDescription(itemlistCursor - .getString(PodDBAdapter.KEY_DESCRIPTION_INDEX)); - item.setContentEncoded(itemlistCursor - .getString(PodDBAdapter.KEY_CONTENT_ENCODED_INDEX)); + .getString(PodDBAdapter.IDX_FI_SMALL_LINK)); item.setPubDate(new Date(itemlistCursor - .getLong(PodDBAdapter.KEY_PUBDATE_INDEX))); + .getLong(PodDBAdapter.IDX_FI_SMALL_PUBDATE))); item.setPaymentLink(itemlistCursor - .getString(PodDBAdapter.KEY_PAYMENT_LINK_INDEX)); + .getString(PodDBAdapter.IDX_FI_SMALL_PAYMENT_LINK)); long mediaId = itemlistCursor - .getLong(PodDBAdapter.KEY_MEDIA_INDEX); + .getLong(PodDBAdapter.IDX_FI_SMALL_MEDIA); if (mediaId != 0) { mediaIds.add(String.valueOf(mediaId)); item.setMedia(new FeedMedia(mediaId, item)); } - item.read = (itemlistCursor.getInt(PodDBAdapter.KEY_READ_INDEX) > 0) ? true + item.read = (itemlistCursor + .getInt(PodDBAdapter.IDX_FI_SMALL_READ) > 0) ? true : false; item.setItemIdentifier(itemlistCursor - .getString(PodDBAdapter.KEY_ITEM_IDENTIFIER_INDEX)); + .getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER)); if (!item.read) { unreadItems.add(item); } // extract chapters boolean hasSimpleChapters = itemlistCursor - .getInt(PodDBAdapter.KEY_HAS_SIMPLECHAPTERS_INDEX) > 0; + .getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0; if (hasSimpleChapters) { Cursor chapterCursor = adapter .getSimpleChaptersOfFeedItemCursor(item); @@ -1325,6 +1338,57 @@ public class FeedManager { cursor.close(); } + public void loadExtraInformationOfItem(final Context context, + final FeedItem item, FeedManager.TaskCallback callback) { + if (AppConfig.DEBUG) + Log.d(TAG, + "Loading extra information of item with id " + item.getId()); + dbExec.execute(new FeedManager.Task(new Handler(), callback) { + + @Override + public void execute() { + PodDBAdapter adapter = new PodDBAdapter(context); + adapter.open(); + Cursor extraCursor = adapter.getExtraInformationOfItem(item); + if (extraCursor.moveToFirst()) { + item.setCachedDescription(extraCursor + .getString(PodDBAdapter.IDX_FI_EXTRA_DESCRIPTION)); + item.setCachedContentEncoded(extraCursor + .getString(PodDBAdapter.IDX_FI_EXTRA_CONTENT_ENCODED)); + } + adapter.close(); + } + }); + } + + public void searchFeedItemDescription(final Context context, + final Feed feed, final String query, + FeedManager.QueryTaskCallback callback) { + dbExec.execute(new FeedManager.QueryTask(context, new Handler(), callback) { + + @Override + public void execute(PodDBAdapter adapter) { + Cursor searchResult = adapter.searchItemDescriptions(feed, + query); + setResult(searchResult); + } + }); + } + + public void searchFeedItemContentEncoded(final Context context, + final Feed feed, final String query, + FeedManager.QueryTaskCallback callback) { + dbExec.execute(new FeedManager.QueryTask(context, new Handler(), callback) { + + @Override + public void execute(PodDBAdapter adapter) { + Cursor searchResult = adapter.searchItemContentEncoded(feed, + query); + setResult(searchResult); + } + }); + } + public List<Feed> getFeeds() { return feeds; } @@ -1345,4 +1409,102 @@ public class FeedManager { return playbackHistory; } + /** Is called by a FeedManagerTask after completion. */ + public interface TaskCallback { + void onCompletion(Cursor result); + } + + /** Is called by a FeedManager.QueryTask after completion. */ + public interface QueryTaskCallback { + void handleResult(Cursor result); + void onCompletion(); + } + + /** A runnable that can post a callback to a handler after completion. */ + abstract class Task implements Runnable { + private Handler handler; + private TaskCallback callback; + + /** + * Standard contructor. No callbacks are going to be posted to a + * handler. + */ + public Task() { + super(); + } + + /** + * The Task will post a Runnable to 'handler' that will execute the + * 'callback' after completion. + */ + public Task(Handler handler, TaskCallback callback) { + super(); + this.handler = handler; + this.callback = callback; + } + + @Override + public final void run() { + execute(); + if (handler != null && callback != null) { + handler.post(new Runnable() { + @Override + public void run() { + callback.onCompletion(null); + } + }); + } + } + + /** This method will be executed in the same thread as the run() method. */ + public abstract void execute(); + } + + /** + * A runnable which should be used for database queries. The onCompletion + * method is executed on the database executor to handle Cursors correctly. + * This class automatically creates a PodDBAdapter object and closes it when + * it is no longer in use. + */ + abstract class QueryTask implements Runnable { + private QueryTaskCallback callback; + private Cursor result; + private Context context; + private Handler handler; + + public QueryTask(Context context, Handler handler, QueryTaskCallback callback) { + this.callback = callback; + this.context = context; + this.handler = handler; + } + + @Override + public final void run() { + PodDBAdapter adapter = new PodDBAdapter(context); + adapter.open(); + execute(adapter); + callback.handleResult(result); + if (result != null && !result.isClosed()) { + result.close(); + } + adapter.close(); + if (handler != null && callback != null) { + handler.post(new Runnable() { + + @Override + public void run() { + callback.onCompletion(); + } + + }); + } + } + + public abstract void execute(PodDBAdapter adapter); + + protected void setResult(Cursor c) { + result = c; + } + } + } diff --git a/src/de/danoeh/antennapod/feed/FeedSearcher.java b/src/de/danoeh/antennapod/feed/FeedSearcher.java index f53ff5ae7..ab7c174bc 100644 --- a/src/de/danoeh/antennapod/feed/FeedSearcher.java +++ b/src/de/danoeh/antennapod/feed/FeedSearcher.java @@ -5,10 +5,14 @@ import java.util.Collections; import java.util.regex.Matcher; import java.util.regex.Pattern; +import android.content.Context; +import android.database.Cursor; +import android.os.Looper; import android.util.Log; import de.danoeh.antennapod.AppConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.storage.PodDBAdapter; import de.danoeh.antennapod.util.comparator.SearchResultValueComparator; /** Performs search on Feeds and FeedItems */ @@ -23,10 +27,10 @@ public class FeedSearcher { private static final int VALUE_WORD_MATCH = 4; /** Performs a search in all feeds or one specific feed. */ - public static ArrayList<SearchResult> performSearch(final String query, - Feed selectedFeed) { - String lcQuery = query.toLowerCase(); - ArrayList<SearchResult> result = new ArrayList<SearchResult>(); + public static ArrayList<SearchResult> performSearch(final Context context, + final String query, final Feed selectedFeed) { + final String lcQuery = query.toLowerCase(); + final ArrayList<SearchResult> result = new ArrayList<SearchResult>(); if (selectedFeed == null) { if (AppConfig.DEBUG) Log.d(TAG, "Performing global search"); @@ -45,14 +49,40 @@ public class FeedSearcher { Log.d(TAG, "Searching item-chaptertitles"); searchFeedItemChapters(lcQuery, result, selectedFeed); - if (AppConfig.DEBUG) - Log.d(TAG, "Searching item descriptions"); - searchFeedItemDescription(lcQuery, result, selectedFeed); + final FeedManager manager = FeedManager.getInstance(); + Looper.prepare(); + manager.searchFeedItemDescription(context, selectedFeed, lcQuery, + new FeedManager.QueryTaskCallback() { - if (AppConfig.DEBUG) - Log.d(TAG, "Searching item content encoded data"); - searchFeedItemContentEncoded(lcQuery, result, selectedFeed); + @Override + public void handleResult(Cursor cResult) { + searchFeedItemContentEncodedCursor(lcQuery, result, + selectedFeed, cResult); + + } + @Override + public void onCompletion() { + manager.searchFeedItemContentEncoded(context, + selectedFeed, lcQuery, + new FeedManager.QueryTaskCallback() { + + @Override + public void handleResult(Cursor cResult) { + searchFeedItemDescriptionCursor( + lcQuery, result, selectedFeed, + cResult); + } + + @Override + public void onCompletion() { + Looper.myLooper().quit(); + } + }); + } + }); + + Looper.loop(); if (AppConfig.DEBUG) Log.d(TAG, "Sorting results"); Collections.sort(result, new SearchResultValueComparator()); @@ -127,61 +157,74 @@ public class FeedSearcher { } } - private static void searchFeedItemDescription(String query, - ArrayList<SearchResult> destination, Feed selectedFeed) { + private static void searchFeedItemDescriptionCursor(String query, + ArrayList<SearchResult> destination, Feed feed, Cursor cursor) { FeedManager manager = FeedManager.getInstance(); - if (selectedFeed == null) { - for (Feed feed : manager.getFeeds()) { - searchFeedItemDescriptionSingleFeed(query, destination, feed); - } - } else { - searchFeedItemDescriptionSingleFeed(query, destination, - selectedFeed); - } - } - - private static void searchFeedItemDescriptionSingleFeed(String query, - ArrayList<SearchResult> destination, Feed feed) { - for (FeedItem item : feed.getItems()) { - if (item.getDescription() != null) { - SearchResult result = createSearchResult(item, query, item - .getDescription().toLowerCase(), VALUE_ITEM_DESCRIPTION); - if (result != null) { - result.setSubtitle(PodcastApp.getInstance().getString( - R.string.found_in_shownotes_label)); - destination.add(result); + if (cursor.moveToFirst()) { + do { + final long itemId = cursor + .getLong(PodDBAdapter.IDX_FI_EXTRA_ID); + String content = cursor + .getString(PodDBAdapter.IDX_FI_EXTRA_DESCRIPTION); + if (content != null) { + content = content.toLowerCase(); + final long feedId = cursor + .getLong(PodDBAdapter.IDX_FI_EXTRA_FEED); + FeedItem item = null; + if (feed == null) { + item = manager.getFeedItem(itemId, feedId); + } else { + item = manager.getFeedItem(itemId, feed); + } + if (item != null) { + SearchResult searchResult = createSearchResult(item, + query, content, VALUE_ITEM_DESCRIPTION); + if (searchResult != null) { + searchResult.setSubtitle(PodcastApp.getInstance() + .getString( + R.string.found_in_shownotes_label)); + destination.add(searchResult); + + } + } } - } + } while (cursor.moveToNext()); } } - private static void searchFeedItemContentEncoded(String query, - ArrayList<SearchResult> destination, Feed selectedFeed) { + private static void searchFeedItemContentEncodedCursor(String query, + ArrayList<SearchResult> destination, Feed feed, Cursor cursor) { FeedManager manager = FeedManager.getInstance(); - if (selectedFeed == null) { - for (Feed feed : manager.getFeeds()) { - searchFeedItemContentEncodedSingleFeed(query, destination, feed); - } - } else { - searchFeedItemContentEncodedSingleFeed(query, destination, - selectedFeed); - } - } - - private static void searchFeedItemContentEncodedSingleFeed(String query, - ArrayList<SearchResult> destination, Feed feed) { - for (FeedItem item : feed.getItems()) { - if (!destination.contains(item) && item.getContentEncoded() != null) { - SearchResult result = createSearchResult(item, query, item - .getContentEncoded().toLowerCase(), - VALUE_ITEM_DESCRIPTION); - if (result != null) { - result.setSubtitle(PodcastApp.getInstance().getString( - R.string.found_in_shownotes_label)); - destination.add(result); + if (cursor.moveToFirst()) { + do { + final long itemId = cursor + .getLong(PodDBAdapter.IDX_FI_EXTRA_ID); + String content = cursor + .getString(PodDBAdapter.IDX_FI_EXTRA_CONTENT_ENCODED); + if (content != null) { + content = content.toLowerCase(); + + final long feedId = cursor + .getLong(PodDBAdapter.IDX_FI_EXTRA_FEED); + FeedItem item = null; + if (feed == null) { + item = manager.getFeedItem(itemId, feedId); + } else { + item = manager.getFeedItem(itemId, feed); + } + if (item != null) { + SearchResult searchResult = createSearchResult(item, + query, content, VALUE_ITEM_DESCRIPTION); + if (searchResult != null) { + searchResult.setSubtitle(PodcastApp.getInstance() + .getString( + R.string.found_in_shownotes_label)); + destination.add(searchResult); + } + } } - } + } while (cursor.moveToNext()); } } |