Enhance Loader API.
This commit is contained in:
parent
ce5eea72d2
commit
c4e1c3543c
@ -24,6 +24,7 @@ import com.google.android.exoplayer.SampleSource;
|
|||||||
import com.google.android.exoplayer.TrackInfo;
|
import com.google.android.exoplayer.TrackInfo;
|
||||||
import com.google.android.exoplayer.TrackRenderer;
|
import com.google.android.exoplayer.TrackRenderer;
|
||||||
import com.google.android.exoplayer.upstream.Loader;
|
import com.google.android.exoplayer.upstream.Loader;
|
||||||
|
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
||||||
import com.google.android.exoplayer.util.Assertions;
|
import com.google.android.exoplayer.util.Assertions;
|
||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@ -39,7 +40,7 @@ import java.util.List;
|
|||||||
* A {@link SampleSource} that loads media in {@link Chunk}s, which are themselves obtained from a
|
* A {@link SampleSource} that loads media in {@link Chunk}s, which are themselves obtained from a
|
||||||
* {@link ChunkSource}.
|
* {@link ChunkSource}.
|
||||||
*/
|
*/
|
||||||
public class ChunkSampleSource implements SampleSource, Loader.Listener {
|
public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface definition for a callback to be notified of {@link ChunkSampleSource} events.
|
* Interface definition for a callback to be notified of {@link ChunkSampleSource} events.
|
||||||
@ -199,7 +200,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Listener {
|
|||||||
@Override
|
@Override
|
||||||
public boolean prepare() {
|
public boolean prepare() {
|
||||||
Assertions.checkState(state == STATE_UNPREPARED);
|
Assertions.checkState(state == STATE_UNPREPARED);
|
||||||
loader = new Loader("Loader:" + chunkSource.getTrackInfo().mimeType, this);
|
loader = new Loader("Loader:" + chunkSource.getTrackInfo().mimeType);
|
||||||
state = STATE_PREPARED;
|
state = STATE_PREPARED;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -413,7 +414,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoaded() {
|
public void onLoadCompleted(Loadable loadable) {
|
||||||
Chunk currentLoadable = currentLoadableHolder.chunk;
|
Chunk currentLoadable = currentLoadableHolder.chunk;
|
||||||
notifyLoadCompleted(currentLoadable.bytesLoaded());
|
notifyLoadCompleted(currentLoadable.bytesLoaded());
|
||||||
try {
|
try {
|
||||||
@ -436,7 +437,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCanceled() {
|
public void onLoadCanceled(Loadable loadable) {
|
||||||
Chunk currentLoadable = currentLoadableHolder.chunk;
|
Chunk currentLoadable = currentLoadableHolder.chunk;
|
||||||
notifyLoadCanceled(currentLoadable.bytesLoaded());
|
notifyLoadCanceled(currentLoadable.bytesLoaded());
|
||||||
if (!isMediaChunk(currentLoadable)) {
|
if (!isMediaChunk(currentLoadable)) {
|
||||||
@ -452,7 +453,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(IOException e) {
|
public void onLoadError(Loadable loadable, IOException e) {
|
||||||
currentLoadableException = e;
|
currentLoadableException = e;
|
||||||
currentLoadableExceptionCount++;
|
currentLoadableExceptionCount++;
|
||||||
currentLoadableExceptionTimestamp = SystemClock.elapsedRealtime();
|
currentLoadableExceptionTimestamp = SystemClock.elapsedRealtime();
|
||||||
@ -553,7 +554,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Listener {
|
|||||||
discardUpstreamMediaChunks(currentLoadableHolder.queueSize);
|
discardUpstreamMediaChunks(currentLoadableHolder.queueSize);
|
||||||
if (currentLoadableHolder.chunk == backedOffChunk) {
|
if (currentLoadableHolder.chunk == backedOffChunk) {
|
||||||
// Chunk was unchanged. Resume loading.
|
// Chunk was unchanged. Resume loading.
|
||||||
loader.startLoading(backedOffChunk);
|
loader.startLoading(backedOffChunk, this);
|
||||||
} else {
|
} else {
|
||||||
backedOffChunk.release();
|
backedOffChunk.release();
|
||||||
maybeStartLoading();
|
maybeStartLoading();
|
||||||
@ -564,7 +565,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Listener {
|
|||||||
if (backedOffChunk == mediaChunks.getFirst()) {
|
if (backedOffChunk == mediaChunks.getFirst()) {
|
||||||
// We're not able to clear the first media chunk, so we have no choice but to continue
|
// We're not able to clear the first media chunk, so we have no choice but to continue
|
||||||
// loading it.
|
// loading it.
|
||||||
loader.startLoading(backedOffChunk);
|
loader.startLoading(backedOffChunk, this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -579,7 +580,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Listener {
|
|||||||
|
|
||||||
if (currentLoadableHolder.chunk == backedOffChunk) {
|
if (currentLoadableHolder.chunk == backedOffChunk) {
|
||||||
// Chunk was unchanged. Resume loading.
|
// Chunk was unchanged. Resume loading.
|
||||||
loader.startLoading(backedOffChunk);
|
loader.startLoading(backedOffChunk, this);
|
||||||
} else {
|
} else {
|
||||||
// This call will remove and release at least one chunk from the end of mediaChunks. Since
|
// This call will remove and release at least one chunk from the end of mediaChunks. Since
|
||||||
// the current loadable is the last media chunk, it is guaranteed to be removed.
|
// the current loadable is the last media chunk, it is guaranteed to be removed.
|
||||||
@ -609,7 +610,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Listener {
|
|||||||
notifyLoadStarted(currentLoadable.format.id, currentLoadable.trigger, true, -1, -1,
|
notifyLoadStarted(currentLoadable.format.id, currentLoadable.trigger, true, -1, -1,
|
||||||
currentLoadable.getLength());
|
currentLoadable.getLength());
|
||||||
}
|
}
|
||||||
loader.startLoading(currentLoadable);
|
loader.startLoading(currentLoadable, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer.util.Util;
|
|||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@ -72,22 +73,28 @@ public final class Loader {
|
|||||||
/**
|
/**
|
||||||
* Interface definition for a callback to be notified of {@link Loader} events.
|
* Interface definition for a callback to be notified of {@link Loader} events.
|
||||||
*/
|
*/
|
||||||
public interface Listener {
|
public interface Callback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when loading has been canceled.
|
* Invoked when loading has been canceled.
|
||||||
|
*
|
||||||
|
* @param loadable The loadable whose load has been canceled.
|
||||||
*/
|
*/
|
||||||
void onCanceled();
|
void onLoadCanceled(Loadable loadable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when the data source has been fully loaded.
|
* Invoked when the data source has been fully loaded.
|
||||||
|
*
|
||||||
|
* @param loadable The loadable whose load has completed.
|
||||||
*/
|
*/
|
||||||
void onLoaded();
|
void onLoadCompleted(Loadable loadable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when the data source is stopped due to an error.
|
* Invoked when the data source is stopped due to an error.
|
||||||
|
*
|
||||||
|
* @param loadable The loadable whose load has failed.
|
||||||
*/
|
*/
|
||||||
void onError(IOException exception);
|
void onLoadError(Loadable loadable, IOException exception);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,18 +102,29 @@ public final class Loader {
|
|||||||
private static final int MSG_ERROR = 1;
|
private static final int MSG_ERROR = 1;
|
||||||
|
|
||||||
private final ExecutorService downloadExecutorService;
|
private final ExecutorService downloadExecutorService;
|
||||||
private final Listener listener;
|
|
||||||
|
|
||||||
private LoadTask currentTask;
|
private LoadTask currentTask;
|
||||||
private boolean loading;
|
private boolean loading;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param threadName A name for the loader's thread.
|
* @param threadName A name for the loader's thread.
|
||||||
* @param listener A listener to invoke when state changes occur.
|
|
||||||
*/
|
*/
|
||||||
public Loader(String threadName, Listener listener) {
|
public Loader(String threadName) {
|
||||||
this.downloadExecutorService = Util.newSingleThreadExecutor(threadName);
|
this.downloadExecutorService = Util.newSingleThreadExecutor(threadName);
|
||||||
this.listener = listener;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes {@link #startLoading(Looper, Loadable, Callback)}, using the {@link Looper}
|
||||||
|
* associated with the calling thread.
|
||||||
|
*
|
||||||
|
* @param loadable The {@link Loadable} to load.
|
||||||
|
* @param callback A callback to invoke when the load ends.
|
||||||
|
* @throws IllegalStateException If the calling thread does not have an associated {@link Looper}.
|
||||||
|
*/
|
||||||
|
public void startLoading(Loadable loadable, Callback callback) {
|
||||||
|
Looper myLooper = Looper.myLooper();
|
||||||
|
Assertions.checkState(myLooper != null);
|
||||||
|
startLoading(myLooper, loadable, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,12 +133,14 @@ public final class Loader {
|
|||||||
* A {@link Loader} instance can only load one {@link Loadable} at a time, and so this method
|
* A {@link Loader} instance can only load one {@link Loadable} at a time, and so this method
|
||||||
* must not be called when another load is in progress.
|
* must not be called when another load is in progress.
|
||||||
*
|
*
|
||||||
|
* @param looper The looper of the thread on which the callback should be invoked.
|
||||||
* @param loadable The {@link Loadable} to load.
|
* @param loadable The {@link Loadable} to load.
|
||||||
|
* @param callback A callback to invoke when the load ends.
|
||||||
*/
|
*/
|
||||||
public void startLoading(Loadable loadable) {
|
public void startLoading(Looper looper, Loadable loadable, Callback callback) {
|
||||||
Assertions.checkState(!loading);
|
Assertions.checkState(!loading);
|
||||||
loading = true;
|
loading = true;
|
||||||
currentTask = new LoadTask(loadable);
|
currentTask = new LoadTask(looper, loadable, callback);
|
||||||
downloadExecutorService.submit(currentTask);
|
downloadExecutorService.submit(currentTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,11 +181,14 @@ public final class Loader {
|
|||||||
private static final String TAG = "LoadTask";
|
private static final String TAG = "LoadTask";
|
||||||
|
|
||||||
private final Loadable loadable;
|
private final Loadable loadable;
|
||||||
|
private final Loader.Callback callback;
|
||||||
|
|
||||||
private volatile Thread executorThread;
|
private volatile Thread executorThread;
|
||||||
|
|
||||||
public LoadTask(Loadable loadable) {
|
public LoadTask(Looper looper, Loadable loadable, Loader.Callback callback) {
|
||||||
|
super(looper);
|
||||||
this.loadable = loadable;
|
this.loadable = loadable;
|
||||||
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void quit() {
|
public void quit() {
|
||||||
@ -200,15 +223,15 @@ public final class Loader {
|
|||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
onFinished();
|
onFinished();
|
||||||
if (loadable.isLoadCanceled()) {
|
if (loadable.isLoadCanceled()) {
|
||||||
listener.onCanceled();
|
callback.onLoadCanceled(loadable);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case MSG_END_OF_SOURCE:
|
case MSG_END_OF_SOURCE:
|
||||||
listener.onLoaded();
|
callback.onLoadCompleted(loadable);
|
||||||
break;
|
break;
|
||||||
case MSG_ERROR:
|
case MSG_ERROR:
|
||||||
listener.onError((IOException) msg.obj);
|
callback.onLoadError(loadable, (IOException) msg.obj);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user