Moved communication with DownloadService into DownloadObserver

This commit is contained in:
daniel oeh 2014-02-15 14:35:11 +01:00
parent 7d44c471f2
commit a2f841c43e
2 changed files with 170 additions and 92 deletions

View File

@ -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<Void, Void, Void> 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<Void, Void, Void>() {
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<Downloader> downloaderList) {
dla = new DownloadlistAdapter(DownloadActivity.this, 0,
downloaderList);
listview.setAdapter(dla);
dla.notifyDataSetChanged();
}
};
}

View File

@ -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<Downloader> 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<Downloader> 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<Downloader> downloaderList = downloadService.getDownloads();
if (downloaderList == null || downloaderList.isEmpty()) {
Thread.currentThread().interrupt();
}
}
});
}
}
}