diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java index ef7cf5e25a..9afcc20d26 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java @@ -239,6 +239,9 @@ public class DownloadTracker implements DownloadManager.Listener { public void release() { downloadHelper.release(); + if (trackSelectionDialog != null) { + trackSelectionDialog.dismiss(); + } startDownloadDialogHelper = null; } @@ -318,7 +321,8 @@ public class DownloadTracker implements DownloadManager.Listener { @Override public void onDismiss(DialogInterface dialogInterface) { - release(); + trackSelectionDialog = null; + downloadHelper.release(); } } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java index e4e92c8cab..4cd6a891b1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java @@ -366,8 +366,7 @@ public final class DownloadHelper { public void prepare(Callback callback) { Assertions.checkState(this.callback == null); this.callback = callback; - Looper myLooper = Looper.myLooper(); - callbackHandler = new Handler(myLooper != null ? myLooper : Looper.getMainLooper()); + callbackHandler = new Handler(Util.getLooper()); if (mediaSource != null) { mediaPreparer = new MediaPreparer(mediaSource, /* downloadHelper= */ this); } else { @@ -745,23 +744,32 @@ public final class DownloadHelper { private static final int MESSAGE_PREPARE_SOURCE = 0; private static final int MESSAGE_CHECK_FOR_FAILURE = 1; private static final int MESSAGE_CONTINUE_LOADING = 2; + private static final int MESSAGE_RELEASE = 3; + + private static final int DOWNLOAD_HELPER_CALLBACK_MESSAGE_PREPARED = 0; + private static final int DOWNLOAD_HELPER_CALLBACK_MESSAGE_FAILED = 1; private final MediaSource mediaSource; private final DownloadHelper downloadHelper; private final Allocator allocator; private final HandlerThread mediaSourceThread; private final Handler mediaSourceHandler; + private final Handler downloadHelperHandler; + private final ArrayList pendingMediaPeriods; @Nullable public Object manifest; public @MonotonicNonNull Timeline timeline; public MediaPeriod @MonotonicNonNull [] mediaPeriods; - private final ArrayList pendingMediaPeriods; + private boolean released; public MediaPreparer(MediaSource mediaSource, DownloadHelper downloadHelper) { this.mediaSource = mediaSource; this.downloadHelper = downloadHelper; allocator = new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE); + @SuppressWarnings("methodref.receiver.bound.invalid") + Handler downloadThreadHandler = Util.createHandler(this::handleDownloadHelperCallbackMessage); + this.downloadHelperHandler = downloadThreadHandler; mediaSourceThread = new HandlerThread("DownloadHelper"); mediaSourceThread.start(); mediaSourceHandler = Util.createHandler(mediaSourceThread.getLooper(), /* callback= */ this); @@ -770,13 +778,11 @@ public final class DownloadHelper { } public void release() { - if (mediaPeriods != null) { - for (MediaPeriod mediaPeriod : mediaPeriods) { - mediaSource.releasePeriod(mediaPeriod); - } + if (released) { + return; } - mediaSource.releaseSource(this); - mediaSourceThread.quit(); + released = true; + mediaSourceHandler.sendEmptyMessage(MESSAGE_RELEASE); } // Handler.Callback @@ -800,7 +806,9 @@ public final class DownloadHelper { mediaSourceHandler.sendEmptyMessageDelayed( MESSAGE_CHECK_FOR_FAILURE, /* delayMillis= */ 100); } catch (IOException e) { - downloadHelper.onMediaPreparationFailed(e); + downloadHelperHandler + .obtainMessage(DOWNLOAD_HELPER_CALLBACK_MESSAGE_FAILED, /* obj= */ e) + .sendToTarget(); } return true; case MESSAGE_CONTINUE_LOADING: @@ -809,6 +817,16 @@ public final class DownloadHelper { mediaPeriod.continueLoading(/* positionUs= */ 0); } return true; + case MESSAGE_RELEASE: + if (mediaPeriods != null) { + for (MediaPeriod period : mediaPeriods) { + mediaSource.releasePeriod(period); + } + } + mediaSource.releaseSource(this); + mediaSourceHandler.removeCallbacksAndMessages(null); + mediaSourceThread.quit(); + return true; default: return false; } @@ -847,7 +865,7 @@ public final class DownloadHelper { pendingMediaPeriods.remove(mediaPeriod); if (pendingMediaPeriods.isEmpty()) { mediaSourceHandler.removeMessages(MESSAGE_CHECK_FOR_FAILURE); - downloadHelper.onMediaPrepared(); + downloadHelperHandler.sendEmptyMessage(DOWNLOAD_HELPER_CALLBACK_MESSAGE_PREPARED); } } @@ -857,6 +875,23 @@ public final class DownloadHelper { mediaSourceHandler.obtainMessage(MESSAGE_CONTINUE_LOADING, mediaPeriod).sendToTarget(); } } + + private boolean handleDownloadHelperCallbackMessage(Message msg) { + if (released) { + // Stale message. + return false; + } + switch (msg.what) { + case DOWNLOAD_HELPER_CALLBACK_MESSAGE_PREPARED: + downloadHelper.onMediaPrepared(); + return true; + case DOWNLOAD_HELPER_CALLBACK_MESSAGE_FAILED: + downloadHelper.onMediaPreparationFailed((IOException) Util.castNonNull(msg.obj)); + return true; + default: + return false; + } + } } private static final class DownloadTrackSelection extends BaseTrackSelection {