/** * Copyright 2012 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.facebook; import android.annotation.TargetApi; import android.os.AsyncTask; import android.os.Handler; import android.util.Log; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.util.Collection; import java.util.List; import java.util.concurrent.Executor; /** * Defines an AsyncTask suitable for executing a Request in the background. May be subclassed * by applications having unique threading model needs. */ @TargetApi(3) public class RequestAsyncTask extends AsyncTask<Void, Void, List<Response>> { private static final String TAG = RequestAsyncTask.class.getCanonicalName(); private static Method executeOnExecutorMethod; private final HttpURLConnection connection; private final RequestBatch requests; private Exception exception; static { for (Method method : AsyncTask.class.getMethods()) { if ("executeOnExecutor".equals(method.getName())) { Class<?>[] parameters = method.getParameterTypes(); if ((parameters.length == 2) && (parameters[0] == Executor.class) && parameters[1].isArray()) { executeOnExecutorMethod = method; break; } } } } /** * Constructor. Serialization of the requests will be done in the background, so any serialization- * related errors will be returned via the Response.getException() method. * * @param requests the requests to execute */ public RequestAsyncTask(Request... requests) { this(null, new RequestBatch(requests)); } /** * Constructor. Serialization of the requests will be done in the background, so any serialization- * related errors will be returned via the Response.getException() method. * * @param requests the requests to execute */ public RequestAsyncTask(Collection<Request> requests) { this(null, new RequestBatch(requests)); } /** * Constructor. Serialization of the requests will be done in the background, so any serialization- * related errors will be returned via the Response.getException() method. * * @param requests the requests to execute */ public RequestAsyncTask(RequestBatch requests) { this(null, requests); } /** * Constructor that allows specification of an HTTP connection to use for executing * the requests. No validation is done that the contents of the connection actually * reflect the serialized requests, so it is the caller's responsibility to ensure * that it will correctly generate the desired responses. * * @param connection the HTTP connection to use to execute the requests * @param requests the requests to execute */ public RequestAsyncTask(HttpURLConnection connection, Request... requests) { this(connection, new RequestBatch(requests)); } /** * Constructor that allows specification of an HTTP connection to use for executing * the requests. No validation is done that the contents of the connection actually * reflect the serialized requests, so it is the caller's responsibility to ensure * that it will correctly generate the desired responses. * * @param connection the HTTP connection to use to execute the requests * @param requests the requests to execute */ public RequestAsyncTask(HttpURLConnection connection, Collection<Request> requests) { this(connection, new RequestBatch(requests)); } /** * Constructor that allows specification of an HTTP connection to use for executing * the requests. No validation is done that the contents of the connection actually * reflect the serialized requests, so it is the caller's responsibility to ensure * that it will correctly generate the desired responses. * * @param connection the HTTP connection to use to execute the requests * @param requests the requests to execute */ public RequestAsyncTask(HttpURLConnection connection, RequestBatch requests) { this.requests = requests; this.connection = connection; } protected final Exception getException() { return exception; } protected final RequestBatch getRequests() { return requests; } @Override public String toString() { return new StringBuilder().append("{RequestAsyncTask: ").append(" connection: ").append(connection) .append(", requests: ").append(requests).append("}").toString(); } @Override protected void onPreExecute() { super.onPreExecute(); if (requests.getCallbackHandler() == null) { // We want any callbacks to go to a handler on this thread unless a handler has already been specified. requests.setCallbackHandler(new Handler()); } } @Override protected void onPostExecute(List<Response> result) { super.onPostExecute(result); if (exception != null) { Log.d(TAG, String.format("onPostExecute: exception encountered during request: %s", exception.getMessage())); } } @Override protected List<Response> doInBackground(Void... params) { try { if (connection == null) { return requests.executeAndWait(); } else { return Request.executeConnectionAndWait(connection, requests); } } catch (Exception e) { exception = e; return null; } } RequestAsyncTask executeOnSettingsExecutor() { try { if (executeOnExecutorMethod != null) { executeOnExecutorMethod.invoke(this, Settings.getExecutor(), null); return this; } } catch (InvocationTargetException e) { // fall-through } catch (IllegalAccessException e) { // fall-through } this.execute(); return this; } }