From 641c1d2af4f9bf7a1fb60d0e054373af0bb23926 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 4 Mar 2019 15:55:09 +0000 Subject: [PATCH] Properly release DownloadHelper and TrackSelectionDialog. The release needs to post to the MediaSource thread and also needs to post back to the DownloadHelper thread to prevent sending updates after release has been called. The point where we release the downloadHelper also needs to dismiss the dialog in case the creation has already been queued before the release. PiperOrigin-RevId: 236652309 --- .../exoplayer2/demo/DownloadTracker.java | 6 +- .../exoplayer2/offline/DownloadHelper.java | 57 +++++++++++++++---- 2 files changed, 51 insertions(+), 12 deletions(-) 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 {