From a2f841c43e95c8b3743788e7bbc505c90045e73b Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sat, 15 Feb 2014 14:35:11 +0100 Subject: Moved communication with DownloadService into DownloadObserver --- .../antennapod/activity/DownloadActivity.java | 112 +++------------ .../antennapod/asynctask/DownloadObserver.java | 150 +++++++++++++++++++++ 2 files changed, 170 insertions(+), 92 deletions(-) create mode 100644 src/de/danoeh/antennapod/asynctask/DownloadObserver.java (limited to 'src/de') diff --git a/src/de/danoeh/antennapod/activity/DownloadActivity.java b/src/de/danoeh/antennapod/activity/DownloadActivity.java index ee5bb502c..f5986baf5 100644 --- a/src/de/danoeh/antennapod/activity/DownloadActivity.java +++ b/src/de/danoeh/antennapod/activity/DownloadActivity.java @@ -1,18 +1,9 @@ package de.danoeh.antennapod.activity; -import android.annotation.SuppressLint; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; import android.content.res.TypedArray; -import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; -import android.os.IBinder; -import android.support.v4.app.NavUtils; +import android.os.Handler; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.ActionBarActivity; import android.support.v7.view.ActionMode; @@ -22,17 +13,18 @@ import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemLongClickListener; - import android.widget.ListView; - import de.danoeh.antennapod.AppConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.DownloadlistAdapter; +import de.danoeh.antennapod.asynctask.DownloadObserver; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.service.download.DownloadRequest; -import de.danoeh.antennapod.service.download.DownloadService; +import de.danoeh.antennapod.service.download.Downloader; import de.danoeh.antennapod.storage.DownloadRequester; +import java.util.List; + /** * Shows all running downloads in a list. The list objects are DownloadStatus * objects created by a DownloadObserver. @@ -49,13 +41,10 @@ public class DownloadActivity extends ActionBarActivity implements private ActionMode mActionMode; private DownloadRequest selectedDownload; - private DownloadService downloadService = null; - boolean mIsBound; - - private AsyncTask contentRefresher; - private ListView listview; + private DownloadObserver downloadObserver; + @Override protected void onCreate(Bundle savedInstanceState) { setTheme(UserPreferences.getTheme()); @@ -68,22 +57,19 @@ public class DownloadActivity extends ActionBarActivity implements Log.d(TAG, "Creating Activity"); requester = DownloadRequester.getInstance(); getSupportActionBar().setDisplayHomeAsUpEnabled(true); + downloadObserver = new DownloadObserver(this, new Handler(), observerCallback); } @Override protected void onPause() { super.onPause(); - unbindService(mConnection); - unregisterReceiver(contentChanged); + downloadObserver.onPause(); } @Override protected void onResume() { super.onResume(); - registerReceiver(contentChanged, new IntentFilter( - DownloadService.ACTION_DOWNLOADS_CONTENT_CHANGED)); - bindService(new Intent(this, DownloadService.class), mConnection, 0); - startContentRefresher(); + downloadObserver.onResume(); if (dla != null) { dla.notifyDataSetChanged(); } @@ -94,72 +80,8 @@ public class DownloadActivity extends ActionBarActivity implements super.onStop(); if (AppConfig.DEBUG) Log.d(TAG, "Stopping Activity"); - stopContentRefresher(); - } - - private ServiceConnection mConnection = new ServiceConnection() { - public void onServiceDisconnected(ComponentName className) { - downloadService = null; - mIsBound = false; - Log.i(TAG, "Closed connection with DownloadService."); - } - - public void onServiceConnected(ComponentName name, IBinder service) { - downloadService = ((DownloadService.LocalBinder) service) - .getService(); - mIsBound = true; - if (AppConfig.DEBUG) - Log.d(TAG, "Connection to service established"); - dla = new DownloadlistAdapter(DownloadActivity.this, 0, - downloadService.getDownloads()); - listview.setAdapter(dla); - dla.notifyDataSetChanged(); - } - }; - - @SuppressLint("NewApi") - private void startContentRefresher() { - if (contentRefresher != null) { - contentRefresher.cancel(true); - } - contentRefresher = new AsyncTask() { - private static final int WAITING_INTERVAL = 1000; - - @Override - protected void onProgressUpdate(Void... values) { - super.onProgressUpdate(values); - if (dla != null) { - if (AppConfig.DEBUG) - Log.d(TAG, "Refreshing content automatically"); - dla.notifyDataSetChanged(); - } - } - - @Override - protected Void doInBackground(Void... params) { - while (!isCancelled()) { - try { - Thread.sleep(WAITING_INTERVAL); - publishProgress(); - } catch (InterruptedException e) { - return null; - } - } - return null; - } - }; - if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { - contentRefresher.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } else { - contentRefresher.execute(); - } } - private void stopContentRefresher() { - if (contentRefresher != null) { - contentRefresher.cancel(true); - } - } @Override protected void onPostCreate(Bundle savedInstanceState) { @@ -247,16 +169,22 @@ public class DownloadActivity extends ActionBarActivity implements dla.setSelectedItemIndex(DownloadlistAdapter.SELECTION_NONE); } - private BroadcastReceiver contentChanged = new BroadcastReceiver() { + private DownloadObserver.Callback observerCallback = new DownloadObserver.Callback() { @Override - public void onReceive(Context context, Intent intent) { + public void onContentChanged() { if (dla != null) { - if (AppConfig.DEBUG) - Log.d(TAG, "Refreshing content"); dla.notifyDataSetChanged(); } } + + @Override + public void onDownloadDataAvailable(List downloaderList) { + dla = new DownloadlistAdapter(DownloadActivity.this, 0, + downloaderList); + listview.setAdapter(dla); + dla.notifyDataSetChanged(); + } }; } diff --git a/src/de/danoeh/antennapod/asynctask/DownloadObserver.java b/src/de/danoeh/antennapod/asynctask/DownloadObserver.java new file mode 100644 index 000000000..26e405615 --- /dev/null +++ b/src/de/danoeh/antennapod/asynctask/DownloadObserver.java @@ -0,0 +1,150 @@ +package de.danoeh.antennapod.asynctask; + +import android.app.Activity; +import android.content.*; +import android.os.Handler; +import android.os.IBinder; +import android.util.Log; +import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.service.download.DownloadService; +import de.danoeh.antennapod.service.download.Downloader; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * 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 = 1000; + + private final 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); + + + /** + * 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) { + if (activity == null) throw new IllegalArgumentException("activity = null"); + if (handler == null) throw new IllegalArgumentException("handler = null"); + if (callback == null) throw new IllegalArgumentException("callback = null"); + + this.activity = activity; + this.handler = handler; + this.callback = callback; + } + + public void onResume() { + if (AppConfig.DEBUG) Log.d(TAG, "DownloadObserver resumed"); + activity.registerReceiver(contentChangedReceiver, new IntentFilter(DownloadService.ACTION_DOWNLOADS_CONTENT_CHANGED)); + activity.bindService(new Intent(activity, DownloadService.class), mConnection, 0); + } + + public void onPause() { + if (AppConfig.DEBUG) Log.d(TAG, "DownloadObserver paused"); + activity.unregisterReceiver(contentChangedReceiver); + activity.unbindService(mConnection); + stopRefresher(); + } + + private BroadcastReceiver contentChangedReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + callback.onContentChanged(); + startRefresher(); + } + }; + + public interface Callback { + void onContentChanged(); + + void onDownloadDataAvailable(List downloaderList); + } + + 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 (AppConfig.DEBUG) + Log.d(TAG, "Connection to service established"); + List downloaderList = downloadService.getDownloads(); + if (downloaderList != null && !downloaderList.isEmpty()) { + callback.onDownloadDataAvailable(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() { + callback.onContentChanged(); + List downloaderList = downloadService.getDownloads(); + if (downloaderList == null || downloaderList.isEmpty()) { + Thread.currentThread().interrupt(); + } + } + }); + } + } + +} -- cgit v1.2.3