/** * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. * * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, * copy, modify, and distribute this software in source code or binary form for use * in connection with the web services and APIs provided by Facebook. * * As with any software that integrates with the Facebook platform, your use of * this software is subject to the Facebook Developer Principles and Policies * [http://developers.facebook.com/policy/]. This copyright notice shall be * included in all copies or substantial portions of the software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package com.facebook; 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. */ public class GraphRequestAsyncTask extends AsyncTask<Void, Void, List<GraphResponse>> { private static final String TAG = GraphRequestAsyncTask.class.getCanonicalName(); private static Method executeOnExecutorMethod; private final HttpURLConnection connection; private final GraphRequestBatch 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 GraphRequestAsyncTask(GraphRequest... requests) { this(null, new GraphRequestBatch(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 GraphRequestAsyncTask(Collection<GraphRequest> requests) { this(null, new GraphRequestBatch(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 GraphRequestAsyncTask(GraphRequestBatch 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 GraphRequestAsyncTask(HttpURLConnection connection, GraphRequest... requests) { this(connection, new GraphRequestBatch(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 GraphRequestAsyncTask(HttpURLConnection connection, Collection<GraphRequest> requests) { this(connection, new GraphRequestBatch(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 GraphRequestAsyncTask(HttpURLConnection connection, GraphRequestBatch requests) { this.requests = requests; this.connection = connection; } protected final Exception getException() { return exception; } protected final GraphRequestBatch 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<GraphResponse> result) { super.onPostExecute(result); if (exception != null) { Log.d(TAG, String.format( "onPostExecute: exception encountered during request: %s", exception.getMessage())); } } @Override protected List<GraphResponse> doInBackground(Void... params) { try { if (connection == null) { return requests.executeAndWait(); } else { return GraphRequest.executeConnectionAndWait(connection, requests); } } catch (Exception e) { exception = e; return null; } } GraphRequestAsyncTask executeOnSettingsExecutor() { if (executeOnExecutorMethod != null) { try { executeOnExecutorMethod.invoke(this, FacebookSdk.getExecutor(), null); } catch (InvocationTargetException e) { // fall-through } catch (IllegalAccessException e) { // fall-through } } else { this.execute(); } return this; } }