package net.callumtaylor.asynchttp.response; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.support.annotation.WorkerThread; import net.callumtaylor.asynchttp.obj.ClientTaskImpl; import net.callumtaylor.asynchttp.obj.ConnectionInfo; import net.callumtaylor.asynchttp.obj.Packet; import java.io.InputStream; import java.net.SocketTimeoutException; /** * This is the base class for response handlers in AsyncHttpClient. The method * flow is as follows: * * <pre> * onSend -> onByteChunkSent -> onByteChunkReceived -> beforeResponse -> onSuccess/onFailure -> beforeFinish -> onFinish * </pre> * * {@link ResponseHandler#onByteChunkReceived}, {@link ResponseHandler#onByteChunkSent}, * {@link ResponseHandler#beforeResponse}, {@link ResponseHandler#onSuccess}, and {@link ResponseHandler#onFailure} all run in * the background thread. All your processing should be handled in one of those * 4 methods and then either call to run on UI thread a new runnable, or handle * in {@link ResponseHandler#onFinish} which runs on the UI thread * * In order to get the content created from the response handler, you must * call {@link ResponseHandler#getContent} which can be accessed in {@link ResponseHandler#onSuccess} or * {@link ResponseHandler#onFailure} */ public abstract class ResponseHandler<E> { private final ConnectionInfo connectionInfo = new ConnectionInfo(); public ConnectionInfo getConnectionInfo() { return connectionInfo; } /** * Called when the connection is first made */ @WorkerThread public void onSend(){} /** * Called when processing the response from a stream. Use this to override * the processing of the InputStream to handle the response differently. * Default is to read the response as a byte-array which gets passed, chunk * by chunk, to {@link ResponseHandler#onByteChunkReceived} * * @param stream * The response InputStream * @param client * The client task. In order to call * {@link ResponseHandler#onByteChunkReceivedProcessed}, you must call * <code>client.postPublishProgress(new Packet(int readCount, int totalLength, boolean isDownload))</code> * This is required when displaying a progress indicator. * @param totalLength * The total length of the stream * @throws SocketTimeoutException * @throws Exception */ @WorkerThread public void onReceiveStream(InputStream stream, ClientTaskImpl client, long totalLength) throws SocketTimeoutException, Exception { byte[] buffer = new byte[8192]; int len = 0; int readCount = 0; while ((len = stream.read(buffer)) > -1 && !client.isCancelled()) { onByteChunkReceived(buffer, len, readCount, totalLength); client.transferProgress(new Packet(readCount, totalLength, true)); readCount += len; } if (!client.isCancelled()) { getConnectionInfo().responseLength = readCount; // we fake the content length, because it can be -1 onByteChunkReceived(null, readCount, readCount, readCount); client.transferProgress(new Packet(readCount, totalLength, true)); } stream.close(); } /** * Called when a chunk has been downloaded from the request. This will be * called once every chunk request, and once extra when all the content is * downloaded. * * @param chunk * The chunk of data. This will be the <b>null</b> after the total amount has been downloaded. * @param chunkLength * The length of the chunk * @param totalProcessed * The total amount of data processed from the request. * @param totalLength * The total size of the request. <b>note:</b> This <i>can</i> be * -1 during download. */ @WorkerThread public void onByteChunkReceived(@Nullable byte[] chunk, long chunkLength, long totalProcessed, long totalLength){} /** * Runs on the UI thread. Useful for updating progress bars. * * @param totalProcessed * The total processed sized of the request * @param totalLength * The total length of the request */ @UiThread public void onByteChunkReceivedProcessed(long totalProcessed, long totalLength){} /** * Called when a chunk has been uploaded to the request. This will be * called once every chunk request * * @param chunk * The chunk of data * @param chunkLength * The length of the chunk * @param totalProcessed * The total amount of data processed from the request. * @param totalLength * The total size of the request. */ @WorkerThread public void onByteChunkSent(@NonNull byte[] chunk, long chunkLength, long totalProcessed, long totalLength){} /** * Runs on the UI thread. Useful for updating progress bars. * * @param totalProcessed * The total processed sized of the request * @param totalLength * The total length of the request */ @UiThread public void onByteChunkSentProcessed(long totalProcessed, long totalLength){} /** * Called just before {@link ResponseHandler#onSuccess} */ @WorkerThread public void beforeResponse(){} /** * Override this method to efficiently generate your content from any buffers you have have * used. * * This is called directly after {@link ResponseHandler#onReceiveStream} has finished */ @WorkerThread public abstract void generateContent(); /** * Gets the content generated from the * response. * * You should only call this once * * @return The generated content object */ @Nullable public abstract E getContent(); /** * Processes the response from the stream. * This is <b>not</b> ran on the UI thread */ @WorkerThread public void onSuccess(){} /** * Called when a response was not 2xx. */ @WorkerThread public void onFailure(){} /** * Called before {@link ResponseHandler#onFinish} */ @WorkerThread public void beforeFinish(){} /** * Called when the streams have all finished, success or not. This is called on the UI Thread */ @UiThread public void onFinish(){} }