Java tutorial
/** * Copyright 2012 Scott Weeden-Moody * * 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.lillicoder.newsblurry.net; import java.io.IOException; import junit.framework.Assert; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.CookieStore; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.protocol.ClientContext; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.net.http.AndroidHttpClient; import android.os.AsyncTask; import android.util.Log; import com.lillicoder.newsblurry.R; import com.lillicoder.newsblurry.exception.ApiRequestException; /** * Base {@link AsyncTask} implementation that supports {@link OnTaskCompletedListener} callbacks. * When using the class, do not override {@link #onPreExecute()} or {@link #onPostExecute(Object)} * since this are overridden to enable listener callbacks. * @author lillicoder * * @param <Params> Type of the parameters sent to the task upon execution. * @param <Progress> Type of the progress units published during the background computation. * @param <Result> Type of the result of the background computation. */ public abstract class BaseTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> { private static final String TAG = BaseTask.class.getSimpleName(); private static final String EXCEPTION_CONNECTION_ERROR = "Unable to get connection, request unsuccessful."; private static final String EXCEPTION_HTTP_ERROR = "HTTP error, request unsuccessful."; private static final String EXCEPTION_INVALID_CONTEXT_PARAM = "The given Context must not be null."; private static final String EXCEPTION_INVALID_LISTENER_PARAM = "The given OnTaskCompletedListener must not be null."; private static final String WARNING_FAILED_TO_GET_PACKAGE_INFO = "Failed to get package info for package name %s."; protected static final String EXCEPTION_API_REQUEST_FAILED = "Failed to connect and fetch data from NewsBlur."; protected static final String EXCEPTION_FAILED_TO_PARAMS = "Failed to get params for this task, will not execute."; protected static final String EXCEPTION_FAILED_TO_PARSE_RESPONSE = "Failed to parse the HTTP response."; protected static final String EXCEPTION_UNABLE_TO_CREATE_JSON_FROM_RESPONSE = "Unable to create JSON instance from server response, is the received JSON data valid?"; private Context _context; private Exception _exception; private OnTaskCompletedListener<Result> _listener; /** * Instantiates this instance with the given context and task completion listener. * @param context {@link Context} for this task. * @param listener {@link OnTaskCompletedListener} for this task. This is used for task callback events (e.g. success, failure). */ protected BaseTask(Context context, OnTaskCompletedListener<Result> listener) { if (context == null) throw new IllegalArgumentException(EXCEPTION_INVALID_CONTEXT_PARAM); if (listener == null) throw new IllegalArgumentException(EXCEPTION_INVALID_LISTENER_PARAM); this._context = context; this._listener = listener; } /** * Executes the given {@link HttpGet} using pre-configured * defaults. Cookies storage and HTTP context will be provided * via {@link #getRequestContext()}. Override this method * to provide custom execution control for a request. * @param get {@link HttpGet} request to execute. * @return {@link HttpResponse} from the executed request. * @throws ApiRequestException Thrown in case of an HTTP or connection error, * or if the request was aborted. */ protected HttpResponse executeWebRequest(HttpGet get) throws ApiRequestException { try { HttpClient client = AndroidHttpClient.newInstance(this.getUserAgent()); return client.execute(get, this.getRequestContext()); } catch (ClientProtocolException e) { throw new ApiRequestException(EXCEPTION_HTTP_ERROR, e); } catch (IOException e) { throw new ApiRequestException(EXCEPTION_CONNECTION_ERROR, e); } } /** * Executes the given {@link HttpPost} using pre-configured * defaults. Cookies storage and HTTP context will be provided * via {@link #getRequestContext()}. Override this method * to provide custom execution control for a request. * @param get {@link HttpPost} request to execute. * @return {@link HttpResponse} from the executed request. * @throws ApiRequestException Thrown in case of an HTTP or connection error, * or if the request was aborted. */ protected HttpResponse executeWebRequest(HttpPost post) throws ApiRequestException { try { HttpClient client = AndroidHttpClient.newInstance(this.getUserAgent()); return client.execute(post, this.getRequestContext()); } catch (ClientProtocolException e) { throw new ApiRequestException(EXCEPTION_HTTP_ERROR, e); } catch (IOException e) { throw new ApiRequestException(EXCEPTION_CONNECTION_ERROR, e); } } /** * Gets the context associated with this task. * @return {@link Contxt} associated with this task. */ protected Context getContext() { return this._context; } /** * Gets the exception generated by this task when execution fails. * When this task succeeds or still still running, this value may be <code>null</code>. * @return {@link Exception} generated by this task as a result of failure. */ protected Exception getException() { return this._exception; } /** * Gets an {@link HttpContext} instance configured for making * web requests. The returned context will have a cookie store * attached for persisting cookies created during the request. * @return {@link HttpContext} for use with web requests. */ protected HttpContext getRequestContext() { HttpContext context = new BasicHttpContext(); CookieStore cookieStore = new PreferenceCookieStore(this.getContext()); context.setAttribute(ClientContext.COOKIE_STORE, cookieStore); return context; } /** * Gets the user agent string for use with tasks that make web requests. * By default this returns the application name and version code. * @return User agent string for use with web requests. */ protected String getUserAgent() { Context context = this.getContext(); Assert.assertTrue(context != null); String versionName = context.getString(R.string.default_versionName); try { PackageManager manager = context.getPackageManager(); PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0); versionName = info.versionName; } catch (NameNotFoundException e) { Log.w(TAG, String.format(WARNING_FAILED_TO_GET_PACKAGE_INFO, context.getPackageName())); } String userAgentFormat = context.getString(R.string.format_userAgent); String appName = context.getString(R.string.app_name); return String.format(userAgentFormat, appName, versionName); } /** * Gets the task completion listener associated with this task. * @return {@link OnTaskCompletedListener} associated with this task. */ protected OnTaskCompletedListener<Result> getListener() { return this._listener; } @Override protected void onPreExecute() { OnTaskCompletedListener<Result> listener = this.getListener(); Assert.assertTrue(listener != null); listener.onPreExecute(); } @Override protected void onPostExecute(Result result) { OnTaskCompletedListener<Result> listener = this.getListener(); Assert.assertTrue(listener != null); Exception exception = this.getException(); if (exception != null) // Exception was set, we task has failed execution. listener.onFailure(exception); else // No exception, task has succeeded. listener.onSuccess(result); } /** * Gets the {@link JSONObject} data contained in the given {@link HttpResponse}. * @param response {@link HttpResponse} to get JSON data from. * @return {@link JSONObject} data contained in the given response. * @throws JSONException Thrown when the JSON containing the response data could not be created. * @throws IOException Thrown when there is an error parsing the given response. */ protected JSONObject getJsonFromResponse(HttpResponse response) throws JSONException, IOException { Assert.assertTrue(response != null); HttpEntity responseEntity = response.getEntity(); String responseText = EntityUtils.toString(responseEntity, "UTF-8"); return new JSONObject(responseText); } /** * Sets this task's {@link Exception}. When {@link #doInBackground(Object...)} * completes, this exception will be reported to this task's * {@link OnTaskCompletedListener#onFailure(Exception)} method. * @param exception {@link Exception} to set. */ protected void setException(Exception exception) { this._exception = exception; } }