Merge pull request #1419 from mfietz/issue/1412-performance

Solve performance issues
This commit is contained in:
Tom Hennen 2015-11-27 09:15:22 -05:00
commit f08f5f8d8f
33 changed files with 591 additions and 670 deletions

View File

@ -28,6 +28,7 @@ dependencies {
compile "com.squareup.okio:okio:$okioVersion"
compile "de.greenrobot:eventbus:$eventbusVersion"
compile "io.reactivex:rxandroid:$rxAndroidVersion"
compile "io.reactivex:rxjava:$rxJavaVersion"
compile "com.joanzapata.iconify:android-iconify-fontawesome:2.1.0"
compile "com.afollestad:material-dialogs:0.7.8.1"
compile "com.yqritc:recyclerview-flexibledivider:1.2.6"

View File

@ -772,7 +772,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
private DBReader.NavDrawerData navDrawerData;
private void loadData() {
subscription = Observable.defer(() -> Observable.just(DBReader.getNavDrawerData()))
subscription = Observable.fromCallable(() -> DBReader.getNavDrawerData())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {

View File

@ -41,10 +41,9 @@ import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.ProgressEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
@ -76,9 +75,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
private static final String TAG = "MainActivity";
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
| EventDistributor.DOWNLOAD_QUEUED
| EventDistributor.FEED_LIST_UPDATE
private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE
| EventDistributor.UNREAD_ITEMS_UPDATE;
public static final String PREF_NAME = "MainActivityPrefs";
@ -639,7 +636,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
};
private void loadData() {
subscription = Observable.defer(() -> Observable.just(DBReader.getNavDrawerData()))
subscription = Observable.fromCallable(() -> DBReader.getNavDrawerData())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {

View File

@ -41,6 +41,7 @@ import java.util.Map;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.FeedItemlistDescriptionAdapter;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
@ -63,6 +64,7 @@ import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.core.util.URLChecker;
import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer;
import de.danoeh.antennapod.dialog.AuthenticationDialog;
import de.greenrobot.event.EventBus;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
@ -86,7 +88,7 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
// Optional argument: specify a title for the actionbar.
public static final String ARG_TITLE = "title";
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | EventDistributor.DOWNLOAD_QUEUED | EventDistributor.FEED_LIST_UPDATE;
private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE;
public static final int RESULT_ERROR = 2;
@ -105,11 +107,16 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
private Subscription parser;
private Subscription updater;
public void onEventMainThread(DownloadEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
setSubscribeButtonState(feed);
}
private EventDistributor.EventListener listener = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((arg & EventDistributor.FEED_LIST_UPDATE) != 0) {
updater = Observable.defer(() -> Observable.just(DBReader.getFeedList()))
updater = Observable.fromCallable(() -> DBReader.getFeedList())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(feeds -> {
@ -180,7 +187,7 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
super.onResume();
isPaused = false;
EventDistributor.getInstance().register(listener);
EventBus.getDefault().register(this);
}
@Override
@ -188,6 +195,7 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
super.onPause();
isPaused = true;
EventDistributor.getInstance().unregister(listener);
EventBus.getDefault().unregister(this);
}
@Override

View File

@ -7,14 +7,10 @@ import android.widget.ImageButton;
import org.apache.commons.lang3.Validate;
import java.lang.ref.WeakReference;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.LongList;
/**
* Utility methods for the action button that is displayed on the right hand side
@ -51,7 +47,7 @@ public class ActionButtonUtils {
* Sets the displayed bitmap and content description of the given
* action button so that it matches the state of the FeedItem.
*/
public void configureActionButton(ImageButton butSecondary, FeedItem item) {
public void configureActionButton(ImageButton butSecondary, FeedItem item, boolean isInQueue) {
Validate.isTrue(butSecondary != null && item != null, "butSecondary or item was null");
final FeedMedia media = item.getMedia();
@ -66,9 +62,8 @@ public class ActionButtonUtils {
butSecondary.setContentDescription(context.getString(labels[1]));
} else {
// item is not downloaded and not being downloaded
LongList queueIds = DBReader.getQueueIDList();
if(DefaultActionButtonCallback.userAllowedMobileDownloads() ||
!DefaultActionButtonCallback.userChoseAddToQueue() || queueIds.contains(item.getId())) {
!DefaultActionButtonCallback.userChoseAddToQueue() || isInQueue) {
butSecondary.setVisibility(View.VISIBLE);
butSecondary.setImageDrawable(drawables.getDrawable(2));
butSecondary.setContentDescription(context.getString(labels[2]));

View File

@ -3,14 +3,12 @@ package de.danoeh.antennapod.adapter;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
@ -34,7 +32,6 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.NetworkUtils;
@ -166,13 +163,14 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.txtvDuration.setVisibility(View.GONE);
}
if (itemAccess.isInQueue(item)) {
boolean isInQueue = itemAccess.isInQueue(item);
if (isInQueue) {
holder.queueStatus.setVisibility(View.VISIBLE);
} else {
holder.queueStatus.setVisibility(View.INVISIBLE);
}
actionButtonUtils.configureActionButton(holder.butSecondary, item);
actionButtonUtils.configureActionButton(holder.butSecondary, item, isInQueue);
holder.butSecondary.setFocusable(false);
holder.butSecondary.setTag(item);
holder.butSecondary.setOnClickListener(secondaryActionListener);

View File

@ -7,11 +7,11 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconButton;
import java.util.Date;
@ -50,7 +50,7 @@ public class DownloadLogAdapter extends BaseAdapter {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.downloadlog_item, parent, false);
holder.icon = (TextView) convertView.findViewById(R.id.txtvIcon);
holder.retry = (Button) convertView.findViewById(R.id.btnRetry);
holder.retry = (IconButton) convertView.findViewById(R.id.btnRetry);
holder.date = (TextView) convertView.findViewById(R.id.txtvDate);
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
holder.type = (TextView) convertView.findViewById(R.id.txtvType);
@ -96,8 +96,6 @@ public class DownloadLogAdapter extends BaseAdapter {
if(status.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE &&
!newerWasSuccessful(position, status.getFeedfileType(), status.getFeedfileId())) {
holder.retry.setVisibility(View.VISIBLE);
holder.retry.setText("{fa-repeat}");
Iconify.addIcons(holder.retry);
holder.retry.setOnClickListener(clickListener);
ButtonHolder btnHolder;
if(holder.retry.getTag() != null) {
@ -161,7 +159,7 @@ public class DownloadLogAdapter extends BaseAdapter {
static class Holder {
TextView icon;
Button retry;
IconButton retry;
TextView title;
TextView type;
TextView date;

View File

@ -176,7 +176,8 @@ public class FeedItemlistAdapter extends BaseAdapter {
}
}
actionButtonUtils.configureActionButton(holder.butAction, item);
boolean isInQueue = itemAccess.isInQueue(item);
actionButtonUtils.configureActionButton(holder.butAction, item, isInQueue);
holder.butAction.setFocusable(false);
holder.butAction.setTag(item);
holder.butAction.setOnClickListener(butActionListener);

View File

@ -4,14 +4,12 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.support.v4.view.MotionEventCompat;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
@ -37,7 +35,6 @@ import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.LongList;
@ -251,7 +248,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
}
}
actionButtonUtils.configureActionButton(butSecondary, item);
actionButtonUtils.configureActionButton(butSecondary, item, true);
butSecondary.setFocusable(false);
butSecondary.setTag(item);
butSecondary.setOnClickListener(secondaryActionListener);

View File

@ -5,7 +5,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.LinearLayoutManager;
@ -30,8 +29,10 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
@ -43,8 +44,10 @@ import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.greenrobot.event.EventBus;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
@ -57,9 +60,7 @@ public class AllEpisodesFragment extends Fragment {
public static final String TAG = "AllEpisodesFragment";
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
EventDistributor.FEED_LIST_UPDATE |
EventDistributor.DOWNLOAD_QUEUED |
private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE |
EventDistributor.UNREAD_ITEMS_UPDATE |
EventDistributor.PLAYER_STATUS_UPDATE;
@ -80,8 +81,6 @@ public class AllEpisodesFragment extends Fragment {
private AtomicReference<MainActivity> activity = new AtomicReference<MainActivity>();
private DownloadObserver downloadObserver = null;
private boolean isUpdatingFeeds;
protected Subscription subscription;
@ -101,10 +100,6 @@ public class AllEpisodesFragment extends Fragment {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
this.activity.set((MainActivity) getActivity());
if (downloadObserver != null) {
downloadObserver.setActivity(getActivity());
downloadObserver.onResume();
}
if (viewsCreated && itemsLoaded) {
onFragmentLoaded();
}
@ -113,6 +108,7 @@ public class AllEpisodesFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
EventBus.getDefault().registerSticky(this);
loadItems();
registerForContextMenu(recyclerView);
}
@ -120,6 +116,7 @@ public class AllEpisodesFragment extends Fragment {
@Override
public void onPause() {
super.onPause();
EventBus.getDefault().unregister(this);
saveScrollPosition();
unregisterForContextMenu(recyclerView);
}
@ -180,9 +177,6 @@ public class AllEpisodesFragment extends Fragment {
listAdapter = null;
activity.set(null);
viewsCreated = false;
if (downloadObserver != null) {
downloadObserver.onPause();
}
}
@ -330,8 +324,6 @@ public class AllEpisodesFragment extends Fragment {
listAdapter = new AllEpisodesRecycleAdapter(activity.get(), activity.get(), itemAccess,
new DefaultActionButtonCallback(activity.get()), showOnlyNewEpisodes());
recyclerView.setAdapter(listAdapter);
downloadObserver = new DownloadObserver(activity.get(), new Handler(), downloadObserverCallback);
downloadObserver.onResume();
}
listAdapter.notifyDataSetChanged();
restoreScrollPosition();
@ -339,21 +331,11 @@ public class AllEpisodesFragment extends Fragment {
updateShowOnlyEpisodesListViewState();
}
private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
@Override
public void onContentChanged(List<Downloader> downloaderList) {
AllEpisodesFragment.this.downloaderList = downloaderList;
if (listAdapter != null) {
listAdapter.notifyDataSetChanged();
}
}
};
protected AllEpisodesRecycleAdapter.ItemAccess itemAccess = new AllEpisodesRecycleAdapter.ItemAccess() {
@Override
public int getCount() {
if (itemsLoaded) {
if (episodes != null) {
return episodes.size();
}
return 0;
@ -361,7 +343,7 @@ public class AllEpisodesFragment extends Fragment {
@Override
public FeedItem getItem(int position) {
if (itemsLoaded) {
if (episodes != null && position < episodes.size()) {
return episodes.get(position);
}
return null;
@ -389,6 +371,39 @@ public class AllEpisodesFragment extends Fragment {
}
};
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
if(episodes == null || listAdapter == null) {
return;
}
for(int i=0, size = event.items.size(); i < size; i++) {
FeedItem item = event.items.get(i);
int pos = FeedItemUtil.indexOfItemWithId(episodes, item.getId());
if(pos >= 0) {
episodes.remove(pos);
episodes.add(pos, item);
listAdapter.notifyItemChanged(pos);
}
}
}
public void onEventMainThread(DownloadEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
if(update.feedIds.length > 0) {
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
getActivity().supportInvalidateOptionsMenu();
}
}
if(update.mediaIds.length > 0) {
if(listAdapter != null) {
listAdapter.notifyDataSetChanged();
}
}
}
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
@ -412,7 +427,7 @@ public class AllEpisodesFragment extends Fragment {
recyclerView.setVisibility(View.GONE);
progLoading.setVisibility(View.VISIBLE);
}
subscription = Observable.defer(() -> Observable.just(loadData()))
subscription = Observable.fromCallable(() -> loadData())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {

View File

@ -156,7 +156,7 @@ public class CompletedDownloadsFragment extends ListFragment {
if (!itemsLoaded && viewCreated) {
setListShown(false);
}
subscription = Observable.defer(() -> Observable.just(DBReader.getDownloadedItems()))
subscription = Observable.fromCallable(() -> DBReader.getDownloadedItems())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {

View File

@ -147,7 +147,7 @@ public class DownloadLogFragment extends ListFragment {
if(subscription != null) {
subscription.unsubscribe();
}
subscription = Observable.defer(() -> Observable.just(DBReader.getDownloadLog()))
subscription = Observable.fromCallable(() -> DBReader.getDownloadLog())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {

View File

@ -17,7 +17,6 @@ import de.danoeh.antennapod.core.event.FavoritesEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.greenrobot.event.EventBus;
/**
@ -38,22 +37,10 @@ public class FavoriteEpisodesFragment extends AllEpisodesFragment {
protected String getPrefName() { return PREF_NAME; }
public void onEvent(FavoritesEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
loadItems();
}
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
@Override
protected void resetViewState() {
super.resetViewState();

View File

@ -8,7 +8,6 @@ import android.content.res.TypedArray;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.util.Pair;
@ -35,12 +34,16 @@ import android.widget.Toast;
import com.bumptech.glide.Glide;
import org.apache.commons.lang3.ArrayUtils;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.FeedItem;
@ -72,9 +75,7 @@ public class ItemFragment extends Fragment {
private static final String TAG = "ItemFragment";
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
EventDistributor.DOWNLOAD_QUEUED |
EventDistributor.UNREAD_ITEMS_UPDATE;
private static final int EVENTS = EventDistributor.UNREAD_ITEMS_UPDATE;
private static final String ARG_FEEDITEM = "feeditem";
@ -97,7 +98,6 @@ public class ItemFragment extends Fragment {
private FeedItem item;
private LongList queue;
private String webviewData;
private DownloadObserver downloadObserver;
private List<Downloader> downloaderList;
private ViewGroup root;
@ -263,11 +263,7 @@ public class ItemFragment extends Fragment {
public void onResume() {
super.onResume();
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
if (downloadObserver != null) {
downloadObserver.setActivity(getActivity());
downloadObserver.onResume();
}
EventBus.getDefault().registerSticky(this);
if(itemsLoaded) {
updateAppearance();
}
@ -294,9 +290,6 @@ public class ItemFragment extends Fragment {
}
private void resetViewState() {
if (downloadObserver != null) {
downloadObserver.onPause();
}
Toolbar toolbar = ((MainActivity) getActivity()).getToolbar();
toolbar.removeView(header);
}
@ -319,8 +312,6 @@ public class ItemFragment extends Fragment {
"utf-8", "about:blank");
}
updateAppearance();
downloadObserver = new DownloadObserver(getActivity(), new Handler(), downloadObserverCallback);
downloadObserver.onResume();
}
private void updateAppearance() {
@ -486,7 +477,32 @@ public class ItemFragment extends Fragment {
public void onEventMainThread(QueueEvent event) {
if(event.contains(itemID)) {
updateAppearance();
load();
}
}
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
for(FeedItem item : event.items) {
if(itemID == item.getId()) {
load();
return;
}
}
}
public void onEventMainThread(DownloadEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
if(item == null || item.getMedia() == null) {
return;
}
long mediaId = item.getMedia().getId();
if(ArrayUtils.contains(update.mediaIds, mediaId)) {
if (itemsLoaded && getActivity() != null) {
updateAppearance();
}
}
}
@ -495,18 +511,7 @@ public class ItemFragment extends Fragment {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((arg & EVENTS) != 0) {
updateAppearance();
}
}
};
private final DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
@Override
public void onContentChanged(List<Downloader> downloaderList) {
ItemFragment.this.downloaderList = downloaderList;
if (itemsLoaded && getActivity() != null) {
updateAppearance();
load();
}
}
};
@ -515,7 +520,7 @@ public class ItemFragment extends Fragment {
if(subscription != null) {
subscription.unsubscribe();
}
subscription = Observable.defer(() -> Observable.just(loadInBackground()))
subscription = Observable.fromCallable(() -> loadInBackground())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {

View File

@ -9,7 +9,6 @@ import android.graphics.Color;
import android.graphics.LightingColorFilter;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.ListFragment;
import android.support.v4.util.Pair;
@ -46,17 +45,19 @@ import de.danoeh.antennapod.activity.FeedInfoActivity;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedItemFilter;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.glide.FastBlurTransformation;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@ -66,6 +67,7 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil;
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
@ -85,9 +87,7 @@ import rx.schedulers.Schedulers;
public class ItemlistFragment extends ListFragment {
private static final String TAG = "ItemlistFragment";
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
| EventDistributor.DOWNLOAD_QUEUED
| EventDistributor.UNREAD_ITEMS_UPDATE
private static final int EVENTS = EventDistributor.UNREAD_ITEMS_UPDATE
| EventDistributor.PLAYER_STATUS_UPDATE;
public static final String EXTRA_SELECTED_FEEDITEM = "extra.de.danoeh.antennapod.activity.selected_feeditem";
@ -104,7 +104,6 @@ public class ItemlistFragment extends ListFragment {
private boolean itemsLoaded = false;
private boolean viewsCreated = false;
private DownloadObserver downloadObserver;
private List<Downloader> downloaderList;
private MoreContentListFooterUtil listFooter;
@ -147,11 +146,7 @@ public class ItemlistFragment extends ListFragment {
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
if (downloadObserver != null) {
downloadObserver.setActivity(getActivity());
downloadObserver.onResume();
}
EventBus.getDefault().registerSticky(this);
if (viewsCreated && itemsLoaded) {
onFragmentLoaded();
}
@ -193,9 +188,6 @@ public class ItemlistFragment extends ListFragment {
adapter = null;
viewsCreated = false;
listFooter = null;
if (downloadObserver != null) {
downloadObserver.onPause();
}
}
private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker = new MenuItemUtils.UpdateRefreshMenuItemChecker() {
@ -394,29 +386,54 @@ public class ItemlistFragment extends ListFragment {
}
public void onEvent(QueueEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
loadItems();
}
public void onEvent(FeedEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
if(event.feedId == feedID) {
loadItems();
}
}
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
boolean queueChanged = false;
if(feed == null || feed.getItems() == null || adapter == null) {
return;
}
for(FeedItem item : event.items) {
int pos = FeedItemUtil.indexOfItemWithId(feed.getItems(), item.getId());
if(pos >= 0) {
loadItems();
return;
}
}
}
public void onEventMainThread(DownloadEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
if(update.feedIds.length > 0) {
updateProgressBarVisibility();
}
if(update.mediaIds.length > 0) {
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
}
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((EVENTS & arg) != 0) {
Log.d(TAG, "Received contentUpdate Intent. arg " + arg);
if ((EventDistributor.DOWNLOAD_QUEUED & arg) != 0) {
updateProgressBarVisibility();
} else {
loadItems();
updateProgressBarVisibility();
}
loadItems();
updateProgressBarVisibility();
}
}
};
@ -444,8 +461,6 @@ public class ItemlistFragment extends ListFragment {
setupFooterView();
adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(getActivity()), false, true);
setListAdapter(adapter);
downloadObserver = new DownloadObserver(getActivity(), new Handler(), downloadObserverCallback);
downloadObserver.onResume();
}
refreshHeaderView();
setListShown(true);
@ -485,22 +500,10 @@ public class ItemlistFragment extends ListFragment {
txtvInformation.setVisibility(View.GONE);
}
} else {
txtvInformation.setVisibility(View.GONE);
}
}
private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
@Override
public void onContentChanged(List<Downloader> downloaderList) {
ItemlistFragment.this.downloaderList = downloaderList;
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
};
private void setupHeaderView() {
if (getListView() == null || feed == null) {
Log.e(TAG, "Unable to setup listview: recyclerView = null or feed = null");
@ -624,7 +627,7 @@ public class ItemlistFragment extends ListFragment {
subscription.unsubscribe();
}
subscription = Observable.defer(() -> Observable.just(loadData()))
subscription = Observable.fromCallable(() -> loadData())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {

View File

@ -14,14 +14,12 @@ import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
import de.danoeh.antennapod.adapter.QueueRecyclerAdapter;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.greenrobot.event.EventBus;
/**
@ -42,22 +40,10 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
protected String getPrefName() { return PREF_NAME; }
public void onEvent(QueueEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
loadItems();
}
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
@Override
protected void resetViewState() {
super.resetViewState();

View File

@ -3,7 +3,6 @@ package de.danoeh.antennapod.fragment;
import android.app.Activity;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.support.v4.util.Pair;
import android.support.v4.view.MenuItemCompat;
@ -21,7 +20,8 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
@ -52,71 +52,24 @@ public class PlaybackHistoryFragment extends ListFragment {
private AtomicReference<Activity> activity = new AtomicReference<Activity>();
private DownloadObserver downloadObserver;
private List<Downloader> downloaderList;
private Subscription subscription;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
}
@Override
public void onResume() {
super.onResume();
loadItems();
}
@Override
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
if(subscription != null) {
subscription.unsubscribe();
}
}
@Override
public void onDetach() {
super.onDetach();
if(subscription != null) {
subscription.unsubscribe();
}
activity.set(null);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.activity.set(activity);
if (downloadObserver != null) {
downloadObserver.setActivity(activity);
downloadObserver.onResume();
}
if (viewsCreated && itemsLoaded) {
onFragmentLoaded();
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
adapter = null;
viewsCreated = false;
if (downloadObserver != null) {
downloadObserver.onPause();
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
}
@Override
@ -135,6 +88,60 @@ public class PlaybackHistoryFragment extends ListFragment {
}
}
@Override
public void onResume() {
super.onResume();
EventBus.getDefault().registerSticky(this);
loadItems();
}
@Override
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
}
@Override
public void onPause() {
super.onPause();
EventBus.getDefault().unregister(this);
}
@Override
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
if(subscription != null) {
subscription.unsubscribe();
}
}
@Override
public void onDetach() {
super.onDetach();
if(subscription != null) {
subscription.unsubscribe();
}
activity.set(null);
}
@Override
public void onDestroyView() {
super.onDestroyView();
adapter = null;
viewsCreated = false;
}
public void onEvent(DownloadEvent event) {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
@ -205,24 +212,12 @@ public class PlaybackHistoryFragment extends ListFragment {
// it harder to read.
adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(activity.get()), true, false);
setListAdapter(adapter);
downloadObserver = new DownloadObserver(activity.get(), new Handler(), downloadObserverCallback);
downloadObserver.onResume();
}
setListShown(true);
adapter.notifyDataSetChanged();
getActivity().supportInvalidateOptionsMenu();
}
private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
@Override
public void onContentChanged(List<Downloader> downloaderList) {
PlaybackHistoryFragment.this.downloaderList = downloaderList;
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
};
private FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() {
@Override
public boolean isInQueue(FeedItem item) {
@ -257,7 +252,7 @@ public class PlaybackHistoryFragment extends ListFragment {
if(subscription != null) {
subscription.unsubscribe();
}
subscription = Observable.defer(() -> Observable.just(loadData()))
subscription = Observable.fromCallable(() -> loadData())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {

View File

@ -4,7 +4,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
@ -31,8 +30,9 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.QueueRecyclerAdapter;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
@ -67,7 +67,6 @@ public class QueueFragment extends Fragment {
public static final String TAG = "QueueFragment";
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
EventDistributor.DOWNLOAD_QUEUED |
EventDistributor.PLAYER_STATUS_UPDATE;
private TextView infoBar;
@ -85,13 +84,6 @@ public class QueueFragment extends Fragment {
private static final String PREF_SCROLL_POSITION = "scroll_position";
private static final String PREF_SCROLL_OFFSET = "scroll_offset";
private DownloadObserver downloadObserver = null;
/**
* Download observer updates won't result in an upate of the list adapter if this is true.
*/
private boolean blockDownloadObserverUpdate = false;
private Subscription subscription;
private LinearLayoutManager layoutManager;
private ItemTouchHelper itemTouchHelper;
@ -107,10 +99,6 @@ public class QueueFragment extends Fragment {
@Override
public void onStart() {
super.onStart();
if (downloadObserver != null) {
downloadObserver.setActivity(getActivity());
downloadObserver.onResume();
}
if (queue != null) {
onFragmentLoaded();
}
@ -122,7 +110,7 @@ public class QueueFragment extends Fragment {
recyclerView.setAdapter(recyclerAdapter);
loadItems();
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
EventBus.getDefault().registerSticky(this);
}
@Override
@ -137,7 +125,10 @@ public class QueueFragment extends Fragment {
}
public void onEventMainThread(QueueEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
if(queue == null || recyclerAdapter == null) {
return;
}
switch(event.action) {
case ADDED:
queue.add(event.position, event.item);
@ -169,7 +160,10 @@ public class QueueFragment extends Fragment {
}
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
if(queue == null || recyclerAdapter == null) {
return;
}
for(int i=0, size = event.items.size(); i < size; i++) {
FeedItem item = event.items.get(i);
int pos = FeedItemUtil.indexOfItemWithId(queue, item.getId());
@ -181,6 +175,21 @@ public class QueueFragment extends Fragment {
}
}
public void onEventMainThread(DownloadEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
if (update.feedIds.length > 0) {
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
getActivity().supportInvalidateOptionsMenu();
}
} else if (update.mediaIds.length > 0) {
if (recyclerAdapter != null) {
recyclerAdapter.notifyDataSetChanged();
}
}
}
private void saveScrollPosition() {
int firstItem = layoutManager.findFirstVisibleItemPosition();
View firstItemView = layoutManager.findViewByPosition(firstItem);
@ -209,10 +218,6 @@ public class QueueFragment extends Fragment {
private void resetViewState() {
recyclerAdapter = null;
blockDownloadObserverUpdate = false;
if (downloadObserver != null) {
downloadObserver.onPause();
}
}
@Override
@ -451,8 +456,6 @@ public class QueueFragment extends Fragment {
recyclerAdapter = new QueueRecyclerAdapter(activity, itemAccess,
new DefaultActionButtonCallback(activity), itemTouchHelper);
recyclerView.setAdapter(recyclerAdapter);
downloadObserver = new DownloadObserver(activity, new Handler(), downloadObserverCallback);
downloadObserver.onResume();
}
if(queue == null || queue.size() == 0) {
recyclerView.setVisibility(View.GONE);
@ -486,16 +489,6 @@ public class QueueFragment extends Fragment {
infoBar.setText(info);
}
private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
@Override
public void onContentChanged(List<Downloader> downloaderList) {
QueueFragment.this.downloaderList = downloaderList;
if (recyclerAdapter != null && !blockDownloadObserverUpdate) {
recyclerAdapter.notifyDataSetChanged();
}
}
};
private QueueRecyclerAdapter.ItemAccess itemAccess = new QueueRecyclerAdapter.ItemAccess() {
@Override
public int getCount() {
@ -504,7 +497,10 @@ public class QueueFragment extends Fragment {
@Override
public FeedItem getItem(int position) {
return queue != null ? queue.get(position) : null;
if(queue != null && position < queue.size()) {
return queue.get(position);
}
return null;
}
@Override
@ -557,6 +553,7 @@ public class QueueFragment extends Fragment {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((arg & EVENTS) != 0) {
Log.d(TAG, "arg: " + arg);
loadItems();
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
getActivity().supportInvalidateOptionsMenu();
@ -566,6 +563,7 @@ public class QueueFragment extends Fragment {
};
private void loadItems() {
Log.d(TAG, "loadItems()");
if(subscription != null) {
subscription.unsubscribe();
}
@ -574,7 +572,7 @@ public class QueueFragment extends Fragment {
txtvEmpty.setVisibility(View.GONE);
progLoading.setVisibility(View.VISIBLE);
}
subscription = Observable.defer(() -> Observable.just(DBReader.getQueue()))
subscription = Observable.fromCallable(() -> DBReader.getQueue())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(items -> {

View File

@ -1,7 +1,6 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.View;
@ -12,7 +11,8 @@ import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.DownloadlistAdapter;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadRequest;
@ -20,25 +20,18 @@ import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.greenrobot.event.EventBus;
/**
* Displays all running downloads and provides actions to cancel them
*/
public class RunningDownloadsFragment extends ListFragment {
private static final String TAG = "RunningDownloadsFrag";
private DownloadObserver downloadObserver;
private DownloadlistAdapter adapter;
private List<Downloader> downloaderList;
@Override
public void onDetach() {
super.onDetach();
if (downloadObserver != null) {
downloadObserver.onPause();
}
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@ -49,20 +42,39 @@ public class RunningDownloadsFragment extends ListFragment {
final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
lv.setPadding(0, vertPadding, 0, vertPadding);
final DownloadlistAdapter downloadlistAdapter = new DownloadlistAdapter(getActivity(), itemAccess);
setListAdapter(downloadlistAdapter);
downloadObserver = new DownloadObserver(getActivity(), new Handler(), new DownloadObserver.Callback() {
@Override
public void onContentChanged(List<Downloader> downloaderList) {
Log.d(TAG, "onContentChanged: downloaderList.size() == " + downloaderList.size());
RunningDownloadsFragment.this.downloaderList = downloaderList;
downloadlistAdapter.notifyDataSetChanged();
}
});
downloadObserver.onResume();
adapter = new DownloadlistAdapter(getActivity(), itemAccess);
setListAdapter(adapter);
}
@Override
public void onResume() {
super.onResume();
EventBus.getDefault().registerSticky(this);
}
@Override
public void onPause() {
super.onPause();
EventBus.getDefault().unregister(this);
}
@Override
public void onDestroy() {
super.onDestroy();
setListAdapter(null);
adapter = null;
}
public void onEvent(DownloadEvent event) {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
private DownloadlistAdapter.ItemAccess itemAccess = new DownloadlistAdapter.ItemAccess() {
@Override
public int getCount() {

View File

@ -204,7 +204,7 @@ public class SearchFragment extends ListFragment {
if (viewCreated && !itemsLoaded) {
setListShown(false);
}
subscription = Observable.defer(() -> Observable.just(performSearch()))
subscription = Observable.fromCallable(() -> performSearch())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {

View File

@ -20,7 +20,7 @@
tools:text="[Icon]"
android:gravity="center" />
<Button
<com.joanzapata.iconify.widget.IconButton
android:id="@+id/btnRetry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -28,6 +28,7 @@
android:layout_alignLeft="@id/txtvIcon"
android:layout_alignRight="@id/txtvIcon"
android:layout_marginTop="8dp"
android:text="{fa-repeat}"
tools:text="↻" />
<TextView

View File

@ -49,6 +49,7 @@ project.ext {
glideVersion = "3.6.1"
jsoupVersion = "1.7.3"
rxAndroidVersion = "1.0.1"
rxJavaVersion = "1.0.16"
okhttpVersion = "2.5.0"
okioVersion = "1.6.0"
}

View File

@ -1,191 +0,0 @@
package de.danoeh.antennapod.core.asynctask;
import android.app.Activity;
import android.content.*;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import org.apache.commons.lang3.Validate;
import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.download.Downloader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Provides access to the DownloadService's list of items that are currently being downloaded.
* The DownloadObserver object should be created in the activity's onCreate() method. resume() and pause()
* should be called in the activity's onResume() and onPause() methods
*/
public class DownloadObserver {
private static final String TAG = "DownloadObserver";
/**
* Time period between update notifications.
*/
public static final int WAITING_INTERVAL_MS = 3000;
private volatile Activity activity;
private final Handler handler;
private final Callback callback;
private DownloadService downloadService = null;
private AtomicBoolean mIsBound = new AtomicBoolean(false);
private Thread refresherThread;
private AtomicBoolean refresherThreadRunning = new AtomicBoolean(false);
private AtomicInteger users = new AtomicInteger(0);
/**
* Creates a new download observer.
*
* @param activity Used for registering receivers
* @param handler All callback methods are executed on this handler. The handler MUST run on the GUI thread.
* @param callback Callback methods for posting content updates
* @throws java.lang.IllegalArgumentException if one of the arguments is null.
*/
public DownloadObserver(Activity activity, Handler handler, Callback callback) {
Validate.notNull(activity);
Validate.notNull(handler);
Validate.notNull(callback);
this.activity = activity;
this.handler = handler;
this.callback = callback;
}
public void onResume() {
Log.d(TAG, "DownloadObserver resumed");
if(users.getAndIncrement() == 0) {
activity.registerReceiver(contentChangedReceiver, new IntentFilter(DownloadService.ACTION_DOWNLOADS_CONTENT_CHANGED));
connectToDownloadService();
}
}
public void onPause() {
Log.d(TAG, "DownloadObserver paused");
if(users.decrementAndGet() > 0) {
return;
}
try {
activity.unregisterReceiver(contentChangedReceiver);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
try {
activity.unbindService(mConnection);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
stopRefresher();
}
private BroadcastReceiver contentChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// reconnect to DownloadService if connection has been closed
if (downloadService == null) {
connectToDownloadService();
}
if (downloadService != null) {
callback.onContentChanged(downloadService.getDownloads());
} else {
// the service is gone, there are no more downloads.
callback.onContentChanged(new ArrayList<Downloader>());
}
startRefresher();
}
};
public interface Callback {
void onContentChanged(List<Downloader> downloaderList);
}
private void connectToDownloadService() {
activity.bindService(new Intent(activity, DownloadService.class), mConnection, 0);
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName className) {
downloadService = null;
mIsBound.set(false);
stopRefresher();
Log.i(TAG, "Closed connection with DownloadService.");
}
public void onServiceConnected(ComponentName name, IBinder service) {
downloadService = ((DownloadService.LocalBinder) service)
.getService();
mIsBound.set(true);
if (BuildConfig.DEBUG)
Log.d(TAG, "Connection to service established");
List<Downloader> downloaderList = downloadService.getDownloads();
if (downloaderList != null && !downloaderList.isEmpty()) {
callback.onContentChanged(downloaderList);
startRefresher();
}
}
};
private void stopRefresher() {
if (refresherThread != null) {
refresherThread.interrupt();
}
}
private void startRefresher() {
if (refresherThread == null || refresherThread.isInterrupted()) {
refresherThread = new Thread(new RefresherThread());
refresherThread.start();
}
}
private class RefresherThread implements Runnable {
public void run() {
refresherThreadRunning.set(true);
while (!Thread.interrupted()) {
try {
Thread.sleep(WAITING_INTERVAL_MS);
} catch (InterruptedException e) {
Log.d(TAG, "Refresher thread was interrupted");
}
if (mIsBound.get()) {
postUpdate();
}
}
refresherThreadRunning.set(false);
}
private void postUpdate() {
handler.post(new Runnable() {
@Override
public void run() {
if (downloadService != null) {
List<Downloader> downloaderList = downloadService.getDownloads();
callback.onContentChanged(downloaderList);
if (downloaderList == null || downloaderList.isEmpty()) {
Thread.currentThread().interrupt();
}
} else {
callback.onContentChanged(new ArrayList<Downloader>());
}
}
});
}
}
public void setActivity(Activity activity) {
Validate.notNull(activity);
this.activity = activity;
}
}

View File

@ -0,0 +1,28 @@
package de.danoeh.antennapod.core.event;
import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.core.service.download.Downloader;
public class DownloadEvent {
public final DownloaderUpdate update;
private DownloadEvent(DownloaderUpdate downloader) {
this.update = downloader;
}
public static DownloadEvent refresh(List<Downloader> list) {
list = new ArrayList<>(list);
DownloaderUpdate update = new DownloaderUpdate(list);
return new DownloadEvent(update);
}
@Override
public String toString() {
return "DownloadEvent{" +
"update=" + update +
'}';
}
}

View File

@ -0,0 +1,53 @@
package de.danoeh.antennapod.core.event;
import java.util.Arrays;
import java.util.List;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.util.LongList;
public class DownloaderUpdate {
/* Downloaders that are currently running */
public final List<Downloader> downloaders;
/**
* IDs of feeds that are currently being downloaded
* Often used to show some progress wheel in the action bar
*/
public final long[] feedIds;
/**
* IDs of feed media that are currently being downloaded
* Can be used to show and update download progress bars
*/
public final long[] mediaIds;
public DownloaderUpdate(List<Downloader> downloaders) {
this.downloaders = downloaders;
LongList feedIds1 = new LongList(), mediaIds1 = new LongList();
for(Downloader d1 : downloaders) {
int type = d1.getDownloadRequest().getFeedfileType();
long id = d1.getDownloadRequest().getFeedfileId();
if(type == Feed.FEEDFILETYPE_FEED) {
feedIds1.add(id);
} else if(type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
mediaIds1.add(id);
}
}
this.feedIds = feedIds1.toArray();
this.mediaIds = mediaIds1.toArray();
}
@Override
public String toString() {
return "DownloaderUpdate{" +
"downloaders=" + downloaders +
", feedIds=" + Arrays.toString(feedIds) +
", mediaIds=" + Arrays.toString(mediaIds) +
'}';
}
}

View File

@ -6,6 +6,7 @@ import android.support.annotation.NonNull;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.Arrays;
import java.util.List;
import de.danoeh.antennapod.core.feed.FeedItem;
@ -32,6 +33,10 @@ public class FeedItemEvent {
return new FeedItemEvent(Action.UPDATE, items);
}
public static FeedItemEvent updated(FeedItem... items) {
return new FeedItemEvent(Action.UPDATE, Arrays.asList(items));
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)

View File

@ -26,7 +26,6 @@ public class EventDistributor extends Observable {
public static final int UNREAD_ITEMS_UPDATE = 2;
public static final int DOWNLOADLOG_UPDATE = 8;
public static final int PLAYBACK_HISTORY_UPDATE = 16;
public static final int DOWNLOAD_QUEUED = 32;
public static final int DOWNLOAD_HANDLED = 64;
public static final int PLAYER_STATUS_UPDATE = 128;
@ -88,10 +87,6 @@ public class EventDistributor extends Observable {
Validate.isInstanceOf(EventListener.class, observer);
}
public void sendDownloadQueuedBroadcast() {
addEvent(DOWNLOAD_QUEUED);
}
public void sendUnreadItemsUpdateBroadcast() {
addEvent(UNREAD_ITEMS_UPDATE);
}
@ -108,10 +103,6 @@ public class EventDistributor extends Observable {
addEvent(DOWNLOADLOG_UPDATE);
}
public void sendDownloadHandledBroadcast() {
addEvent(DOWNLOAD_HANDLED);
}
public void sendPlayerStatusUpdateBroadcast() { addEvent(PLAYER_STATUS_UPDATE); }
public static abstract class EventListener implements Observer {

View File

@ -53,7 +53,8 @@ import javax.xml.parsers.ParserConfigurationException;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedImage;
import de.danoeh.antennapod.core.feed.FeedItem;
@ -74,6 +75,7 @@ import de.danoeh.antennapod.core.syndication.handler.UnsupportedFeedtypeExceptio
import de.danoeh.antennapod.core.util.ChapterUtils;
import de.danoeh.antennapod.core.util.DownloadError;
import de.danoeh.antennapod.core.util.InvalidFeedException;
import de.greenrobot.event.EventBus;
/**
* Manages the download of feedfiles in the app. Downloads can be enqueued viathe startService intent.
@ -101,12 +103,6 @@ public class DownloadService extends Service {
*/
public static final String EXTRA_DOWNLOAD_URL = "downloadUrl";
/**
* Sent by the DownloadService when the content of the downloads list
* changes.
*/
public static final String ACTION_DOWNLOADS_CONTENT_CHANGED = "action.de.danoeh.antennapod.core.service.downloadsContentChanged";
/**
* Extra for ACTION_ENQUEUE_DOWNLOAD intent.
*/
@ -155,6 +151,8 @@ public class DownloadService extends Service {
private static final int SCHED_EX_POOL_SIZE = 1;
private ScheduledThreadPoolExecutor schedExecutor;
private Handler postHandler = new Handler();
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
@ -180,10 +178,7 @@ public class DownloadService extends Service {
final int type = status.getFeedfileType();
if (successful) {
if (type == Feed.FEEDFILETYPE_FEED) {
handleCompletedFeedDownload(downloader
.getDownloadRequest());
} else if (type == FeedImage.FEEDFILETYPE_FEEDIMAGE) {
handleCompletedImageDownload(status, downloader.getDownloadRequest());
handleCompletedFeedDownload(downloader.getDownloadRequest());
} else if (type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
handleCompletedFeedMediaDownload(status, downloader.getDownloadRequest());
}
@ -202,9 +197,22 @@ public class DownloadService extends Service {
Log.e(TAG, "Download failed");
saveDownloadStatus(status);
handleFailedDownload(status, downloader.getDownloadRequest());
// to make lists reload the failed item, we fake an item update
if(type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
long id = status.getFeedfileId();
FeedMedia media = DBReader.getFeedMedia(id);
EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
}
}
} else {
// if FeedMedia download has been canceled, fake FeedItem update
// so that lists reload that it
if(status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
FeedMedia media = DBReader.getFeedMedia(status.getFeedfileId());
EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
}
}
sendDownloadHandledIntent();
queryDownloadsAsync();
}
} catch (InterruptedException e) {
@ -306,6 +314,9 @@ public class DownloadService extends Service {
updateReport();
}
postHandler.removeCallbacks(postDownloaderTask);
EventBus.getDefault().postSticky(DownloadEvent.refresh(Collections.emptyList()));
stopForeground(true);
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.cancel(NOTIFICATION_ID);
@ -407,15 +418,14 @@ public class DownloadService extends Service {
} else {
Log.e(TAG, "Could not cancel download with url " + url);
}
sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
postDownloaders();
} else if (StringUtils.equals(intent.getAction(), ACTION_CANCEL_ALL_DOWNLOADS)) {
for (Downloader d : downloads) {
d.cancel();
Log.d(TAG, "Cancelled all downloads");
}
sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
postDownloaders();
}
queryDownloads();
}
@ -434,13 +444,14 @@ public class DownloadService extends Service {
if (downloader != null) {
numberOfDownloads.incrementAndGet();
// smaller rss feeds before bigger media files
if(request.getFeedfileId() == Feed.FEEDFILETYPE_FEED) {
if(request.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
downloads.add(0, downloader);
} else {
downloads.add(downloader);
}
downloadExecutor.submit(downloader);
sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
postDownloaders();
}
queryDownloads();
@ -471,7 +482,7 @@ public class DownloadService extends Service {
boolean rc = downloads.remove(d);
Log.d(TAG, "Result of downloads.remove: " + rc);
DownloadRequester.getInstance().removeDownload(d.getDownloadRequest());
sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
postDownloaders();
}
});
}
@ -487,10 +498,6 @@ public class DownloadService extends Service {
DBWriter.addDownloadStatus(status);
}
private void sendDownloadHandledIntent() {
EventDistributor.getInstance().sendDownloadHandledBroadcast();
}
/**
* Creates a notification at the end of the service lifecycle to notify the
* user about the number of completed downloads. A report will only be
@ -606,14 +613,6 @@ public class DownloadService extends Service {
}
/**
* Is called whenever a Feed-Image is downloaded
*/
private void handleCompletedImageDownload(DownloadStatus status, DownloadRequest request) {
Log.d(TAG, "Handling completed Image Download");
syncExecutor.execute(new ImageHandlerThread(status, request));
}
/**
* Is called whenever a FeedMedia is downloaded.
*/
@ -767,8 +766,6 @@ public class DownloadService extends Service {
numberOfDownloads.decrementAndGet();
}
sendDownloadHandledIntent();
queryDownloadsAsync();
}
});
@ -1012,40 +1009,6 @@ public class DownloadService extends Service {
}
}
/**
* Handles a completed image download.
*/
class ImageHandlerThread implements Runnable {
private DownloadRequest request;
private DownloadStatus status;
public ImageHandlerThread(DownloadStatus status, DownloadRequest request) {
Validate.notNull(status);
Validate.notNull(request);
this.status = status;
this.request = request;
}
@Override
public void run() {
FeedImage image = DBReader.getFeedImage(request.getFeedfileId());
if (image == null) {
throw new IllegalStateException("Could not find downloaded image in database");
}
image.setFile_url(request.getDestination());
image.setDownloaded(true);
saveDownloadStatus(status);
sendDownloadHandledIntent();
DBWriter.setFeedImage(image);
numberOfDownloads.decrementAndGet();
queryDownloadsAsync();
}
}
/**
* Handles a completed media download.
*/
@ -1064,8 +1027,7 @@ public class DownloadService extends Service {
@Override
public void run() {
FeedMedia media = DBReader.getFeedMedia(
request.getFeedfileId());
FeedMedia media = DBReader.getFeedMedia(request.getFeedfileId());
if (media == null) {
throw new IllegalStateException(
"Could not find downloaded media object in database");
@ -1121,7 +1083,6 @@ public class DownloadService extends Service {
}
saveDownloadStatus(status);
sendDownloadHandledIntent();
if(GpodnetPreferences.loggedIn()) {
FeedItem item = media.getItem();
@ -1174,16 +1135,24 @@ public class DownloadService extends Service {
}
}
public List<Downloader> getDownloads() {
if (downloads == null) {
// this is unusual, but it should be OK, we'll return
// an empty list to make it easy for people
return new ArrayList<Downloader>();
}
// return a copy of downloads, but the copy doesn't need to be synchronized.
synchronized (downloads) {
return new ArrayList<Downloader>(downloads);
private long lastPost = 0;
final Runnable postDownloaderTask = new Runnable() {
@Override
public void run() {
List<Downloader> list = Collections.unmodifiableList(downloads);
EventBus.getDefault().postSticky(DownloadEvent.refresh(list));
postHandler.postDelayed(postDownloaderTask, 1500);
}
};
private void postDownloaders() {
long now = System.currentTimeMillis();
if(now - lastPost >= 250) {
postHandler.removeCallbacks(postDownloaderTask);
postDownloaderTask.run();
lastPost = now;
}
}

View File

@ -3,13 +3,13 @@ package de.danoeh.antennapod.core.storage;
import android.database.Cursor;
import android.util.Log;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.Feed;
@ -160,7 +160,7 @@ public final class DBReader {
* The method does NOT change the items-attribute of the feed.
*/
public static List<FeedItem> getFeedItemList(final Feed feed) {
Log.d(TAG, "Extracting Feeditems of feed " + feed.getTitle());
Log.d(TAG, "getFeedItemList() called with: " + "feed = [" + feed + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -169,11 +169,10 @@ public final class DBReader {
List<FeedItem> items = extractItemlistFromCursor(adapter,
itemlistCursor);
itemlistCursor.close();
adapter.close();
Collections.sort(items, new FeedItemPubdateComparator());
adapter.close();
for (FeedItem item : items) {
item.setFeed(feed);
}
@ -182,6 +181,7 @@ public final class DBReader {
}
public static List<FeedItem> extractItemlistFromCursor(Cursor itemlistCursor) {
Log.d(TAG, "extractItemlistFromCursor() called with: " + "itemlistCursor = [" + itemlistCursor + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
List<FeedItem> result = extractItemlistFromCursor(adapter, itemlistCursor);
@ -189,53 +189,61 @@ public final class DBReader {
return result;
}
private static List<FeedItem> extractItemlistFromCursor(
PodDBAdapter adapter, Cursor itemlistCursor) {
ArrayList<String> itemIds = new ArrayList<>();
List<FeedItem> items = new ArrayList<>(itemlistCursor.getCount());
private static List<FeedItem> extractItemlistFromCursor(PodDBAdapter adapter,
Cursor cursor) {
List<FeedItem> result = new ArrayList<>(cursor.getCount());
if (itemlistCursor.moveToFirst()) {
do {
int indexImage = itemlistCursor.getColumnIndex(PodDBAdapter.KEY_IMAGE);
long imageId = itemlistCursor.getLong(indexImage);
FeedImage image = null;
if (imageId != 0) {
image = getFeedImage(adapter, imageId);
}
FeedItem item = FeedItem.fromCursor(itemlistCursor);
item.setImage(image);
itemIds.add(String.valueOf(item.getId()));
items.add(item);
} while (itemlistCursor.moveToNext());
}
extractMediafromItemlist(adapter, items, itemIds);
return items;
}
private static void extractMediafromItemlist(PodDBAdapter adapter,
List<FeedItem> items, ArrayList<String> itemIds) {
List<FeedItem> itemsCopy = new ArrayList<>(items);
Cursor cursor = adapter.getFeedMediaCursorByItemID(itemIds
.toArray(new String[itemIds.size()]));
LongList imageIds = new LongList(cursor.getCount());
LongList itemIds = new LongList(cursor.getCount());
if (cursor.moveToFirst()) {
do {
int index = cursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM);
long itemId = cursor.getLong(index);
// find matching feed item
FeedItem item = getMatchingItemForMedia(itemId, itemsCopy);
if (item != null) {
FeedMedia media = FeedMedia.fromCursor(cursor);
item.setMedia(media);
item.getMedia().setItem(item);
}
int indexImage = cursor.getColumnIndex(PodDBAdapter.KEY_IMAGE);
long imageId = cursor.getLong(indexImage);
imageIds.add(imageId);
FeedItem item = FeedItem.fromCursor(cursor);
result.add(item);
itemIds.add(item.getId());
} while (cursor.moveToNext());
Map<Long,FeedImage> images = getFeedImages(adapter, imageIds.toArray());
Map<Long,FeedMedia> medias = getFeedMedia(adapter, itemIds.toArray());
for(int i=0; i < result.size(); i++) {
FeedItem item = result.get(i);
long imageId = imageIds.get(i);
FeedImage image = images.get(imageId);
item.setImage(image);
FeedMedia media = medias.get(item.getId());
item.setMedia(media);
if(media != null) {
media.setItem(item);
}
}
}
cursor.close();
return result;
}
private static Map<Long,FeedMedia> getFeedMedia(PodDBAdapter adapter,
long... itemIds) {
ArrayList<String> ids = new ArrayList<>(itemIds.length);
for(long itemId : itemIds) {
ids.add(String.valueOf(itemId));
}
Map<Long,FeedMedia> result = new HashMap<>(itemIds.length);
Cursor cursor = adapter.getFeedMediaCursor(ids.toArray(new String[0]));
try {
if (cursor.moveToFirst()) {
do {
int index = cursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM);
long itemId = cursor.getLong(index);
FeedMedia media = FeedMedia.fromCursor(cursor);
result.put(itemId, media);
} while (cursor.moveToNext());
}
} finally {
cursor.close();
}
return result;
}
private static Feed extractFeedFromCursorRow(PodDBAdapter adapter,
@ -261,16 +269,6 @@ public final class DBReader {
return feed;
}
private static FeedItem getMatchingItemForMedia(long itemId,
List<FeedItem> items) {
for (FeedItem item : items) {
if (item.getId() == itemId) {
return item;
}
}
return null;
}
static List<FeedItem> getQueue(PodDBAdapter adapter) {
Log.d(TAG, "getQueue()");
Cursor itemlistCursor = adapter.getQueueCursor();
@ -288,6 +286,7 @@ public final class DBReader {
* list in a {@link de.danoeh.antennapod.core.util.QueueAccess} object for easier access to the queue's properties.
*/
public static LongList getQueueIDList() {
Log.d(TAG, "getQueueIDList() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
LongList result = getQueueIDList(adapter);
@ -296,7 +295,6 @@ public final class DBReader {
}
static LongList getQueueIDList(PodDBAdapter adapter) {
adapter.open();
Cursor queueCursor = adapter.getQueueIDCursor();
LongList queueIds = new LongList(queueCursor.getCount());
@ -317,7 +315,7 @@ public final class DBReader {
* list in a {@link de.danoeh.antennapod.core.util.QueueAccess} object for easier access to the queue's properties.
*/
public static List<FeedItem> getQueue() {
Log.d(TAG, "getQueue()");
Log.d(TAG, "getQueue() called with: " + "");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -332,7 +330,7 @@ public final class DBReader {
* @return A list of FeedItems whose episdoe has been downloaded.
*/
public static List<FeedItem> getDownloadedItems() {
Log.d(TAG, "Extracting downloaded items");
Log.d(TAG, "getDownloadedItems() called with: " + "");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -342,9 +340,10 @@ public final class DBReader {
itemlistCursor);
itemlistCursor.close();
loadAdditionalFeedItemListData(items);
adapter.close();
Collections.sort(items, new FeedItemPubdateComparator());
adapter.close();
return items;
}
@ -355,7 +354,7 @@ public final class DBReader {
* @return A list of FeedItems whose 'read'-attribute it set to false.
*/
public static List<FeedItem> getUnreadItemsList() {
Log.d(TAG, "Extracting unread items list");
Log.d(TAG, "getUnreadItemsList() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -376,7 +375,7 @@ public final class DBReader {
* @return A list of FeedItems that are considered new.
*/
public static List<FeedItem> getNewItemsList() {
Log.d(TAG, "getNewItemsList()");
Log.d(TAG, "getNewItemsList() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -393,7 +392,7 @@ public final class DBReader {
}
public static List<FeedItem> getFavoriteItemsList() {
Log.d(TAG, "getFavoriteItemsList()");
Log.d(TAG, "getFavoriteItemsList() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -410,7 +409,9 @@ public final class DBReader {
}
static LongList getFavoriteIDList() {
PodDBAdapter adapter = PodDBAdapter.getInstance().open();
Log.d(TAG, "getFavoriteIDList() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor favoritesCursor = adapter.getFavoritesCursor();
LongList favoriteIDs = new LongList(favoritesCursor.getCount());
@ -420,6 +421,7 @@ public final class DBReader {
} while (favoritesCursor.moveToNext());
}
favoritesCursor.close();
adapter.close();
return favoriteIDs;
}
@ -429,7 +431,7 @@ public final class DBReader {
* @param limit The maximum number of episodes that should be loaded.
*/
public static List<FeedItem> getRecentlyPublishedEpisodes(int limit) {
Log.d(TAG, "Extracting recently published items list");
Log.d(TAG, "getRecentlyPublishedEpisodes() called with: " + "limit = [" + limit + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -453,7 +455,7 @@ public final class DBReader {
* The size of the returned list is limited by {@link #PLAYBACK_HISTORY_SIZE}.
*/
public static List<FeedItem> getPlaybackHistory() {
Log.d(TAG, "Loading playback history");
Log.d(TAG, "getPlaybackHistory() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -482,7 +484,7 @@ public final class DBReader {
* The size of the returned list is limited by {@link #DOWNLOAD_LOG_SIZE}.
*/
public static List<DownloadStatus> getDownloadLog() {
Log.d(TAG, "Extracting DownloadLog");
Log.d(TAG, "getDownloadLog() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -496,6 +498,7 @@ public final class DBReader {
} while (logCursor.moveToNext());
}
logCursor.close();
adapter.close();
Collections.sort(downloadLog, new DownloadStatusComparator());
return downloadLog;
}
@ -508,7 +511,7 @@ public final class DBReader {
* newest events first.
*/
public static List<DownloadStatus> getFeedDownloadLog(Feed feed) {
Log.d(TAG, "getFeedDownloadLog(" + feed.toString() + ")");
Log.d(TAG, "getFeedDownloadLog() called with: " + "feed = [" + feed + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -522,6 +525,7 @@ public final class DBReader {
} while (cursor.moveToNext());
}
cursor.close();
adapter.close();
Collections.sort(downloadLog, new DownloadStatusComparator());
return downloadLog;
}
@ -534,6 +538,7 @@ public final class DBReader {
* @return A list of FeedItemStatistics objects sorted alphabetically by their Feed's title.
*/
public static List<FeedItemStatistics> getFeedStatisticsList() {
Log.d(TAG, "getFeedStatisticsList() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
List<FeedItemStatistics> result = new ArrayList<>();
@ -558,6 +563,7 @@ public final class DBReader {
* database and the items-attribute will be set correctly.
*/
public static Feed getFeed(final long feedId) {
Log.d(TAG, "getFeed() called with: " + "feedId = [" + feedId + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
Feed result = getFeed(feedId, adapter);
@ -566,7 +572,6 @@ public final class DBReader {
}
static Feed getFeed(final long feedId, PodDBAdapter adapter) {
Log.d(TAG, "Loading feed with id " + feedId);
Feed feed = null;
Cursor feedCursor = adapter.getFeedCursor(feedId);
@ -635,7 +640,7 @@ public final class DBReader {
* as well as chapter marks of the FeedItem will also be loaded from the database.
*/
public static FeedItem getFeedItem(final long itemId) {
Log.d(TAG, "Loading feeditem with id " + itemId);
Log.d(TAG, "getFeedItem() called with: " + "itemId = [" + itemId + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -671,8 +676,7 @@ public final class DBReader {
* as well as chapter marks of the FeedItems will also be loaded from the database.
*/
public static List<FeedItem> getFeedItems(final long... itemIds) {
Log.d(TAG, "Loading feeditem with ids: " + StringUtils.join(itemIds, ","));
Log.d(TAG, "getFeedItems() called with: " + "itemIds = [" + itemIds + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
List<FeedItem> items = getFeedItems(adapter, itemIds);
@ -688,7 +692,7 @@ public final class DBReader {
* @return Credentials in format "<Username>:<Password>", empty String if no authorization given
*/
public static String getImageAuthentication(final String imageUrl) {
Log.d(TAG, "Loading credentials for image with URL " + imageUrl);
Log.d(TAG, "getImageAuthentication() called with: " + "imageUrl = [" + imageUrl + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -728,7 +732,7 @@ public final class DBReader {
* as well as chapter marks of the FeedItem will also be loaded from the database.
*/
public static FeedItem getFeedItem(final String podcastUrl, final String episodeUrl) {
Log.d(TAG, "Loading feeditem with podcast url " + podcastUrl + " and episode url " + episodeUrl);
Log.d(TAG, "getFeedItem() called with: " + "podcastUrl = [" + podcastUrl + "], episodeUrl = [" + episodeUrl + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@ -743,6 +747,7 @@ public final class DBReader {
* @param item The FeedItem
*/
public static void loadExtraInformationOfFeedItem(final FeedItem item) {
Log.d(TAG, "loadExtraInformationOfFeedItem() called with: " + "item = [" + item + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor extraCursor = adapter.getExtraInformationOfItem(item);
@ -766,6 +771,7 @@ public final class DBReader {
* @param item The FeedItem
*/
public static void loadChaptersOfFeedItem(final FeedItem item) {
Log.d(TAG, "loadChaptersOfFeedItem() called with: " + "item = [" + item + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
loadChaptersOfFeedItem(adapter, item);
@ -820,6 +826,7 @@ public final class DBReader {
* @return The number of downloaded episodes.
*/
public static int getNumberOfDownloadedEpisodes() {
Log.d(TAG, "getNumberOfDownloadedEpisodes() called with: " + "");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
final int result = adapter.getNumberOfDownloadedEpisodes();
@ -834,6 +841,7 @@ public final class DBReader {
* @return The found object
*/
public static FeedImage getFeedImage(final long imageId) {
Log.d(TAG, "getFeedImage() called with: " + "imageId = [" + imageId + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
FeedImage result = getFeedImage(adapter, imageId);
@ -844,21 +852,34 @@ public final class DBReader {
/**
* Searches the DB for a FeedImage of the given id.
*
* @param id The id of the object
* @param imageId The id of the object
* @return The found object
*/
static FeedImage getFeedImage(PodDBAdapter adapter, final long id) {
Cursor cursor = adapter.getImageCursor(id);
private static FeedImage getFeedImage(PodDBAdapter adapter, final long imageId) {
return getFeedImages(adapter, imageId).get(imageId);
}
/**
* Searches the DB for a FeedImage of the given id.
*
* @param ids The id of the object
* @return The found object
*/
private static Map<Long,FeedImage> getFeedImages(PodDBAdapter adapter, final long... ids) {
Cursor cursor = adapter.getImageCursor(ids);
Map<Long, FeedImage> result = new HashMap<>(cursor.getCount());
try {
if ((cursor.getCount() == 0) || !cursor.moveToFirst()) {
return null;
return Collections.emptyMap();
}
FeedImage image = FeedImage.fromCursor(cursor);
image.setId(id);
return image;
do {
FeedImage image = FeedImage.fromCursor(cursor);
result.put(image.getId(), image);
} while(cursor.moveToNext());
} finally {
cursor.close();
}
return result;
}
/**
@ -897,6 +918,7 @@ public final class DBReader {
* @return The flattr queue as a List.
*/
public static List<FlattrThing> getFlattrQueue() {
Log.d(TAG, "getFlattrQueue() called with: " + "");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
List<FlattrThing> result = new ArrayList<>();
@ -927,6 +949,7 @@ public final class DBReader {
*
*/
public static NavDrawerData getNavDrawerData() {
Log.d(TAG, "getNavDrawerData() called with: " + "");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
List<Feed> feeds = getFeedList(adapter);

View File

@ -766,6 +766,7 @@ public class DBWriter {
adapter.open();
adapter.setSingleFeedItem(item);
adapter.close();
EventBus.getDefault().post(FeedItemEvent.updated(item));
});
}

View File

@ -15,7 +15,6 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedFile;
import de.danoeh.antennapod.core.feed.FeedMedia;
@ -85,7 +84,7 @@ public class DownloadRequester {
Intent launchIntent = new Intent(context, DownloadService.class);
launchIntent.putExtra(DownloadService.EXTRA_REQUEST, request);
context.startService(launchIntent);
EventDistributor.getInstance().sendDownloadQueuedBroadcast();
return true;
}

View File

@ -10,14 +10,15 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.media.MediaMetadataRetriever;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.event.ProgressEvent;
@ -188,6 +189,15 @@ public class PodDBAdapter {
+ TABLE_NAME_FEED_ITEMS + "_" + KEY_IMAGE + " ON " + TABLE_NAME_FEED_ITEMS + " ("
+ KEY_IMAGE + ")";
public static final String CREATE_INDEX_FEEDITEMS_PUBDATE = "CREATE INDEX IF NOT EXISTS "
+ TABLE_NAME_FEED_ITEMS + "_" + KEY_PUBDATE + " ON " + TABLE_NAME_FEED_ITEMS + " ("
+ KEY_PUBDATE + ")";
public static final String CREATE_INDEX_FEEDITEMS_READ = "CREATE INDEX IF NOT EXISTS "
+ TABLE_NAME_FEED_ITEMS + "_" + KEY_READ + " ON " + TABLE_NAME_FEED_ITEMS + " ("
+ KEY_READ + ")";
public static final String CREATE_INDEX_QUEUE_FEEDITEM = "CREATE INDEX "
+ TABLE_NAME_QUEUE + "_" + KEY_FEEDITEM + " ON " + TABLE_NAME_QUEUE + " ("
+ KEY_FEEDITEM + ")";
@ -270,10 +280,10 @@ public class PodDBAdapter {
KEY_CONTENT_ENCODED, KEY_FEED};
private SQLiteDatabase db;
private static SQLiteDatabase db;
private static Context context;
private static PodDBHelper dbHelper;
private static AtomicInteger counter = new AtomicInteger(0);
private static int counter = 0;
public static void init(Context context) {
PodDBAdapter.context = context.getApplicationContext();
@ -288,12 +298,15 @@ public class PodDBAdapter {
private PodDBAdapter() {}
public PodDBAdapter open() {
counter.incrementAndGet();
public synchronized PodDBAdapter open() {
counter++;
if (db == null || !db.isOpen() || db.isReadOnly()) {
Log.v(TAG, "Opening DB");
try {
db = dbHelper.getWritableDatabase();
if(Build.VERSION.SDK_INT >= 11) {
db.enableWriteAheadLogging();
}
} catch (SQLException ex) {
Log.e(TAG, Log.getStackTraceString(ex));
db = dbHelper.getReadableDatabase();
@ -302,12 +315,13 @@ public class PodDBAdapter {
return this;
}
public void close() {
if(counter.decrementAndGet() == 0) {
public synchronized void close() {
counter--;
if(counter == 0) {
Log.v(TAG, "Closing DB");
db.close();
db = null;
}
db = null;
}
public static boolean deleteDatabase() {
@ -990,14 +1004,16 @@ public class PodDBAdapter {
}
/**
* Returns a cursor for a DB query in the FeedImages table for a given ID.
* Returns a cursor for a DB query in the FeedImages table for given IDs.
*
* @param id ID of the FeedImage
* @param ids IDs of the FeedImages
* @return The cursor of the query
*/
public final Cursor getImageCursor(final long id) {
Cursor c = db.query(TABLE_NAME_FEED_IMAGES, null, KEY_ID + "=?",
new String[]{String.valueOf(id)}, null, null, null);
public final Cursor getImageCursor(long... ids) {
String sql = "SELECT * FROM " + TABLE_NAME_FEED_IMAGES +
" WHERE " + KEY_ID + " IN (" + StringUtils.join(ids, ',') + ")";
Cursor c = db.rawQuery(sql, null);
return c;
}
@ -1138,26 +1154,26 @@ public class PodDBAdapter {
return db.query(TABLE_NAME_FEED_MEDIA, null, KEY_ID + "=?", new String[]{String.valueOf(id)}, null, null, null);
}
public final Cursor getFeedMediaCursorByItemID(String... mediaIds) {
int length = mediaIds.length;
public final Cursor getFeedMediaCursor(String... itemIds) {
int length = itemIds.length;
if (length > IN_OPERATOR_MAXIMUM) {
Log.w(TAG, "Length of id array is larger than "
+ IN_OPERATOR_MAXIMUM + ". Creating multiple cursors");
int numCursors = (int) (((double) length) / (IN_OPERATOR_MAXIMUM)) + 1;
Cursor[] cursors = new Cursor[numCursors];
for (int i = 0; i < numCursors; i++) {
int neededLength = 0;
String[] parts = null;
int neededLength;
String[] parts;
final int elementsLeft = length - i * IN_OPERATOR_MAXIMUM;
if (elementsLeft >= IN_OPERATOR_MAXIMUM) {
neededLength = IN_OPERATOR_MAXIMUM;
parts = Arrays.copyOfRange(mediaIds, i
parts = Arrays.copyOfRange(itemIds, i
* IN_OPERATOR_MAXIMUM, (i + 1)
* IN_OPERATOR_MAXIMUM);
} else {
neededLength = elementsLeft;
parts = Arrays.copyOfRange(mediaIds, i
parts = Arrays.copyOfRange(itemIds, i
* IN_OPERATOR_MAXIMUM, (i * IN_OPERATOR_MAXIMUM)
+ neededLength);
}
@ -1169,7 +1185,7 @@ public class PodDBAdapter {
return new MergeCursor(cursors);
} else {
return db.query(TABLE_NAME_FEED_MEDIA, null, KEY_FEEDITEM + " IN "
+ buildInOperator(length), mediaIds, null, null, null);
+ buildInOperator(length), itemIds, null, null, null);
}
}
@ -1442,7 +1458,7 @@ public class PodDBAdapter {
*/
private static class PodDBHelper extends SQLiteOpenHelper {
private final static int VERSION = 1040002;
private final static int VERSION = 1040013;
private Context context;
@ -1472,6 +1488,8 @@ public class PodDBAdapter {
db.execSQL(CREATE_INDEX_FEEDITEMS_FEED);
db.execSQL(CREATE_INDEX_FEEDITEMS_IMAGE);
db.execSQL(CREATE_INDEX_FEEDITEMS_PUBDATE);
db.execSQL(CREATE_INDEX_FEEDITEMS_READ);
db.execSQL(CREATE_INDEX_FEEDMEDIA_FEEDITEM);
db.execSQL(CREATE_INDEX_QUEUE_FEEDITEM);
db.execSQL(CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM);
@ -1680,6 +1698,11 @@ public class PodDBAdapter {
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
+ " ADD COLUMN " + PodDBAdapter.KEY_LAST_PLAYED_TIME + " INTEGER DEFAULT 0");
}
if(oldVersion < 1040013) {
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_PUBDATE);
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_READ);
}
EventBus.getDefault().post(ProgressEvent.end());
}
}

View File

@ -176,6 +176,28 @@ public final class LongList {
return false;
}
/**
* Removes values from this list.
*
* @param values values to remove
*/
public void removeAll(long[] values) {
for(long value : values) {
remove(value);
}
}
/**
* Removes values from this list.
*
* @param list List with values to remove
*/
public void removeAll(LongList list) {
for(long value : list.values) {
remove(value);
}
}
/**
* Removes an element at a given index, shifting elements at greater
* indicies down one.