|
23 | 23 |
|
24 | 24 | package com.algolia.search.saas;
|
25 | 25 |
|
26 |
| -import android.os.AsyncTask; |
27 | 26 | import android.os.Build;
|
28 | 27 | import android.os.Handler;
|
29 | 28 | import android.os.Looper;
|
30 | 29 | import android.support.annotation.NonNull;
|
31 | 30 | import android.support.annotation.Nullable;
|
32 | 31 |
|
| 32 | +import com.algolia.search.saas.helpers.HandlerExecutor; |
| 33 | + |
33 | 34 | import org.json.JSONException;
|
34 | 35 | import org.json.JSONObject;
|
35 | 36 | import org.json.JSONTokener;
|
|
49 | 50 | import java.util.HashMap;
|
50 | 51 | import java.util.List;
|
51 | 52 | import java.util.Map;
|
| 53 | +import java.util.concurrent.Executor; |
52 | 54 | import java.util.concurrent.ExecutorService;
|
53 | 55 | import java.util.concurrent.Executors;
|
54 | 56 | import java.util.zip.GZIPInputStream;
|
@@ -141,12 +143,12 @@ private static class HostStatus {
|
141 | 143 | */
|
142 | 144 | private HashMap<String, String> headers = new HashMap<String, String>();
|
143 | 145 |
|
144 |
| - /** Handler used to execute operations on the main thread. */ |
145 |
| - protected Handler mainHandler = new Handler(Looper.getMainLooper()); |
146 |
| - |
147 | 146 | /** Thread pool used to run asynchronous requests. */
|
148 | 147 | protected ExecutorService searchExecutorService = Executors.newFixedThreadPool(4);
|
149 | 148 |
|
| 149 | + /** Executor used to run completion handlers. By default, runs on the main thread. */ |
| 150 | + protected @NonNull Executor completionExecutor = new HandlerExecutor(new Handler(Looper.getMainLooper())); |
| 151 | + |
150 | 152 | protected Map<String, WeakReference<Object>> indices = new HashMap<>();
|
151 | 153 |
|
152 | 154 | // ----------------------------------------------------------------------
|
@@ -372,6 +374,16 @@ private List<String> getWriteHostsThatAreUp() {
|
372 | 374 | return hostsThatAreUp(writeHosts);
|
373 | 375 | }
|
374 | 376 |
|
| 377 | + /** |
| 378 | + * Change the executor on which completion handlers are executed. |
| 379 | + * By default, completion handlers are executed on the main thread. |
| 380 | + * |
| 381 | + * @param completionExecutor The new completion executor to use. |
| 382 | + */ |
| 383 | + public void setCompletionExecutor(@NonNull Executor completionExecutor) { |
| 384 | + this.completionExecutor = completionExecutor; |
| 385 | + } |
| 386 | + |
375 | 387 | // ----------------------------------------------------------------------
|
376 | 388 | // Utilities
|
377 | 389 | // ----------------------------------------------------------------------
|
@@ -670,127 +682,28 @@ boolean isUpOrCouldBeRetried(String host) {
|
670 | 682 | // ----------------------------------------------------------------------
|
671 | 683 |
|
672 | 684 | /**
|
673 |
| - * Abstract {@link Request} implementation using an `AsyncTask`. |
674 |
| - * Derived classes just have to implement the {@link #run()} method. |
| 685 | + * Abstract convenience implementation of {@link FutureRequest} using the client's default executors. |
675 | 686 | */
|
676 |
| - abstract protected class AsyncTaskRequest implements Request { |
677 |
| - /** The completion handler notified of the result. May be null if the caller omitted it. */ |
678 |
| - private CompletionHandler completionHandler; |
679 |
| - |
680 |
| - /** The executor used to execute the request. */ |
681 |
| - private ExecutorService executorService; |
682 |
| - |
683 |
| - private boolean finished = false; |
684 |
| - |
685 |
| - /** |
686 |
| - * The underlying asynchronous task. |
687 |
| - */ |
688 |
| - private AsyncTask<Void, Void, APIResult> task = new AsyncTask<Void, Void, APIResult>() { |
689 |
| - @Override |
690 |
| - protected APIResult doInBackground(Void... params) { |
691 |
| - try { |
692 |
| - return new APIResult(run()); |
693 |
| - } catch (AlgoliaException e) { |
694 |
| - return new APIResult(e); |
695 |
| - } |
696 |
| - } |
697 |
| - |
698 |
| - @Override |
699 |
| - protected void onPostExecute(APIResult result) { |
700 |
| - finished = true; |
701 |
| - if (completionHandler != null) { |
702 |
| - completionHandler.requestCompleted(result.content, result.error); |
703 |
| - } |
704 |
| - } |
705 |
| - |
706 |
| - @Override |
707 |
| - protected void onCancelled(APIResult apiResult) { |
708 |
| - finished = true; |
709 |
| - } |
710 |
| - }; |
711 |
| - |
| 687 | + abstract protected class AsyncTaskRequest extends FutureRequest { |
712 | 688 | /**
|
713 |
| - * Construct a new request with the specified completion handler, executing on the client's default executor. |
| 689 | + * Construct a new request with the specified completion handler, executing on the client's search executor, |
| 690 | + * and calling the completion handler on the client's completion executor. |
714 | 691 | *
|
715 |
| - * @param completionHandler The completion handler to be notified of results. May be null if the caller omitted it. |
| 692 | + * @param completionHandler The completion handler to be notified of results. May be null if the caller omitted it. |
716 | 693 | */
|
717 | 694 | protected AsyncTaskRequest(@Nullable CompletionHandler completionHandler) {
|
718 | 695 | this(completionHandler, searchExecutorService);
|
719 | 696 | }
|
720 | 697 |
|
721 | 698 | /**
|
722 |
| - * Construct a new request with the specified completion handler, executing on the specified executor. |
723 |
| - * |
724 |
| - * @param completionHandler The completion handler to be notified of results. May be null if the caller omitted it. |
725 |
| - * @param executorService Executor service on which to execute the request. |
726 |
| - */ |
727 |
| - protected AsyncTaskRequest(@Nullable CompletionHandler completionHandler, @NonNull ExecutorService executorService) { |
728 |
| - this.completionHandler = completionHandler; |
729 |
| - this.executorService = executorService; |
730 |
| - } |
731 |
| - |
732 |
| - /** |
733 |
| - * Run this request synchronously. To be implemented by derived classes. |
734 |
| - * <p> |
735 |
| - * <strong>Do not call this method directly.</strong> Will be run in a background thread when calling |
736 |
| - * {@link #start()}. |
737 |
| - * </p> |
738 |
| - * |
739 |
| - * @return The request's result. |
740 |
| - * @throws AlgoliaException If an error was encountered. |
741 |
| - */ |
742 |
| - @NonNull |
743 |
| - abstract protected JSONObject run() throws AlgoliaException; |
744 |
| - |
745 |
| - /** |
746 |
| - * Run this request asynchronously. |
747 |
| - * |
748 |
| - * @return This instance. |
749 |
| - */ |
750 |
| - public AsyncTaskRequest start() { |
751 |
| - // WARNING: Starting with Honeycomb (3.0), `AsyncTask` execution is serial, so we must force parallel |
752 |
| - // execution. See <http://developer.android.com/reference/android/os/AsyncTask.html>. |
753 |
| - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { |
754 |
| - task.executeOnExecutor(executorService); |
755 |
| - } else { |
756 |
| - task.execute(); |
757 |
| - } |
758 |
| - return this; |
759 |
| - } |
760 |
| - |
761 |
| - /** |
762 |
| - * Cancel this request. |
763 |
| - * The listener will not be called after a request has been cancelled. |
764 |
| - * <p> |
765 |
| - * WARNING: Cancelling a request may or may not cancel the underlying network call, depending how late the |
766 |
| - * cancellation happens. In other words, a cancelled request may have already been executed by the server. In any |
767 |
| - * case, cancelling never carries "undo" semantics. |
768 |
| - * </p> |
769 |
| - */ |
770 |
| - @Override |
771 |
| - public void cancel() { |
772 |
| - // NOTE: We interrupt the task's thread to better cope with timeouts. |
773 |
| - task.cancel(true /* mayInterruptIfRunning */); |
774 |
| - } |
775 |
| - |
776 |
| - /** |
777 |
| - * Test if this request is still running. |
778 |
| - * |
779 |
| - * @return true if completed or cancelled, false if still running. |
780 |
| - */ |
781 |
| - @Override |
782 |
| - public boolean isFinished() { |
783 |
| - return finished; |
784 |
| - } |
785 |
| - |
786 |
| - /** |
787 |
| - * Test if this request has been cancelled. |
| 699 | + * Construct a new request with the specified completion handler, executing on the specified executor, and |
| 700 | + * calling the completion handler on the client's completion executor. |
788 | 701 | *
|
789 |
| - * @return true if cancelled, false otherwise. |
| 702 | + * @param completionHandler The completion handler to be notified of results. May be null if the caller omitted it. |
| 703 | + * @param requestExecutor Executor on which to execute the request. |
790 | 704 | */
|
791 |
| - @Override |
792 |
| - public boolean isCancelled() { |
793 |
| - return task.isCancelled(); |
| 705 | + protected AsyncTaskRequest(@Nullable CompletionHandler completionHandler, @NonNull Executor requestExecutor) { |
| 706 | + super(completionHandler, requestExecutor, completionExecutor); |
794 | 707 | }
|
795 | 708 | }
|
796 | 709 | }
|
0 commit comments