Java : a WebService asking embeded in a AsyncTask

2019-01-20 18:30发布

问题:

. Hi, as a young android developer i was looking at a way to get a JSON response from a server. I started looking at AsyncTask but i not feeling comfortable to code an AsyncTask for each time i needed to ask a WebService.

Then i started to code a class (extends AsyncTask) that query an URL (POST or GET) and provide a callback containing the response from the server. I wanted to have some feedback, is it really useful, and not an useless overlay of an AsyncTask cause i missed understand something at the beginning. The more i code it, the more i doubt.

Thanks in advance for your feedback.

Here's the code i use to query a server with my class :

HashMap<String, String> parameters = new HashMap<String, String>();
parameters.put("address", "sidney");
parameters.put("sensor", "false");

WebServiceAsyncTask asyncWS = new WebServiceAsyncTask(MainActivity.this);
asyncWS.setParameters(parameters);
asyncWS.execute(
        "http://maps.googleapis.com/maps/api/geocode/json",
        WebServiceAsyncTask.GET,
        new WebServiceAsyncTaskCallback() {
            @Override
            void callbackMethod(String result) {
                Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
            }
        }
);

Here's the code of my WebServiceAsyncTask :

import android.app.ProgressDialog;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Anthony Raymond
 */
public class WebServiceAsyncTask extends AsyncTask<Object, String, String> {
    public static final String GET = "GET";
    public static final String POST = "POST";

    private static final String PROGRESS_TEXT_PREPARING = "Preparing request";
    private static final String PROGRESS_PERCENT_PREPARING = "25";
    private static final String PROGRESS_TEXT_CONNECTION_SERVER = "Connecting to the server";
    private static final String PROGRESS_PERCENT_CONNECTION_SERVER = "50";
    private static final String PROGRESS_TEXT_PARSING = "Parsing received data";
    private static final String PROGRESS_PERCENT_PARSING = "75";
    private static final String PROGRESS_TEXT_END = "Process ended";
    private static final String PROGRESS_PERCENT_END = "100";


    private Context context;
    private HashMap<String, String> mData = new HashMap<String, String>();
    private ProgressDialog progressDialog;


    private WebServiceAsyncTaskCallback callbackClass;

    /**
     * If a Context is passed, a ProgressDialog will be displayed
     * NEED TO PASS Context LIKE THIS :
     * MyActivity.this
     * DO NOT USE getApplicationContext()
     * @param applicationContext
     */
    public WebServiceAsyncTask(Context applicationContext)
    {
        this.context = applicationContext;
    }

    /**
     * Create a WebServiceAsyncTask.
     * Usage : add request parameter by passing an HashMap<String, String> with the setParameter Method, then call
     * .execute(String url, WebServiceAsyncTask constant (GET or SET), WebServiceAsyncTaskCallback callback)
     * exemple :
     * HashMap<String, String> parameters = new HashMap<String, String>();
     * parameters.put("address", "Sidney");
     * parameters.put("sensor", "false");
     * WebServiceAsyncTask asyncWS = new WebServiceAsyncTask(MainActivity.this);
     * asyncWS.setParameters(parameters);
     * asyncWS.execute(
     *      "http://maps.googleapis.com/maps/api/geocode/json",
     *      WebServiceAsyncTask.GET,
     *      new WebServiceAsyncTaskCallback() {
     *          @Override
     *          void callbackMethod(String result) {
     *              Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
     *          }
     *      }
     * );
     */
    public WebServiceAsyncTask()
    {
        this.context = null;
    }

    private void prepareProgressDialog()
    {
        if (this.context != null)
        {
            this.progressDialog = new ProgressDialog(this.context);
            this.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            this.progressDialog.setCancelable(true);
            this.progressDialog.setTitle("Please Wait...");
            this.progressDialog.setMessage(PROGRESS_TEXT_PREPARING);
            this.progressDialog.setProgress(Integer.parseInt(PROGRESS_PERCENT_PREPARING));
        }
    }
    private String getPostResponse(String url)
    {
        byte[] result;
        String str = "";
        HttpClient client = new DefaultHttpClient();

        HttpPost http = new HttpPost(url);
        // set up post data
        List<NameValuePair> nameValuePair = new ArrayList<NameValuePair>();
        for (String key : this.mData.keySet()) {
            nameValuePair.add(new BasicNameValuePair(key, this.mData.get(key)));
        }

        UrlEncodedFormEntity urlEncodedFormEntity;
        try
        {

            urlEncodedFormEntity = new UrlEncodedFormEntity(nameValuePair);
            http.setEntity(urlEncodedFormEntity);
            this.publishProgress(PROGRESS_TEXT_CONNECTION_SERVER, PROGRESS_PERCENT_CONNECTION_SERVER);
            HttpResponse response = client.execute(http);
            StatusLine statusLine = response.getStatusLine();

            if(statusLine.getStatusCode() == HttpURLConnection.HTTP_OK)
            {
                this.publishProgress(PROGRESS_TEXT_PARSING, PROGRESS_PERCENT_PARSING);
                result  = EntityUtils.toByteArray(response.getEntity());
                str     = new String(result, HTTP.UTF_8);
            }
        }
        catch (UnsupportedEncodingException e)
        {
            e.printStackTrace();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return str;
    }
    private String getGetResponse(String url)
    {
        byte[] result;
        String str = "";
        HttpClient client = new DefaultHttpClient();

        try
        {
            // set up get data and URL
            Uri.Builder uri = Uri.parse(url).buildUpon();

            for (String key : this.mData.keySet()) {
                uri.appendQueryParameter(key, this.mData.get(key));
            }

            HttpGet http = new HttpGet(String.valueOf(uri));
            this.publishProgress(PROGRESS_TEXT_CONNECTION_SERVER, PROGRESS_PERCENT_CONNECTION_SERVER);
            HttpResponse response = client.execute(http);
            StatusLine statusLine = response.getStatusLine();

            if(statusLine.getStatusCode() == HttpURLConnection.HTTP_OK)
            {
                this.publishProgress(PROGRESS_TEXT_PARSING, PROGRESS_PERCENT_PARSING);
                result  = EntityUtils.toByteArray(response.getEntity());
                str     = new String(result, HTTP.UTF_8);
            }
        }
        catch (UnsupportedEncodingException e)
        {
            e.printStackTrace();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return str;
    }
    public void setParameters(HashMap<String, String> httpRequestParameters)
    {
        this.mData = httpRequestParameters;
    }



    @Override
    protected String doInBackground(Object... params)
    {
        // Ensure that we got, URL, http method and Callback
        if (params.length != 3)
        {
            this.cancel(true);
        }
        else
        {
            if ((params[2] instanceof WebServiceAsyncTaskCallback))
            {
                this.callbackClass = ((WebServiceAsyncTaskCallback)params[2]);
            }
            else
            {
                this.cancel(true);
            }
            try {
                URL url = new URL((String)params[0]);
            } catch (MalformedURLException e) {
                this.callbackClass.onError("First param must be a valid URL. (" + params[0] + " given)");
                this.cancel(true);
            }
            if (!((String)params[1]).equals(POST) && !((String)params[1]).equals(GET))
            {
                this.callbackClass.onError("Second parameters must be " + this.getClass().getName() + " POST or GET constant");
                this.cancel(true);
            }
        }

        String str          = "";

        //IS OUR REQUEST A POST
        if (params.length > 1)
        {
            if (((String)params[1]).toUpperCase().equals(WebServiceAsyncTask.POST))
            {
                str = getPostResponse(((String)params[0]));
            }
            else if(((String)params[1]).toUpperCase().equals(WebServiceAsyncTask.GET)) //THEN GET
            {
                str = getGetResponse(((String)params[0]));
            }
        }

        return str;
    }

    @Override
    protected void onPostExecute(String result)
    {
        this.mData = null;

        if (this.context != null)
        {
            this.publishProgress(PROGRESS_TEXT_END, PROGRESS_PERCENT_END);
            this.progressDialog.dismiss();
        }
        if (this.callbackClass != null)
        {
            this.callbackClass.callbackMethod(result);
        }
    }

    @Override
    protected void onPreExecute()
    {
        if (this.context != null)
        {
            this.prepareProgressDialog();
            this.progressDialog.show();
        }
    }

    @Override
    protected void onProgressUpdate(String... values) {
        if (this.context != null)
        {
            this.progressDialog.setMessage(values[0]);
            this.progressDialog.setProgress(Integer.parseInt(values[1]));
        }
    }


}

/**
 * Allow to easily get the server response
 */
abstract class WebServiceAsyncTaskCallback{
    /**
     * Return the server response as String
     * @param result server response as a String
     */
    abstract void callbackMethod(String result);

    /**
     * This method is design to report simple errors for development phase.
     * @param errMessage contains error message
     */
    protected void onError(String errMessage){};

    ;
}

回答1:

Your use of AsyncTask appears appropriate. As you may be aware.. for network communications you must use AsyncTask or your own thread (extend HandlerThread.)

If your app is frequently calling AsyncTask or is executing simultaneous AsyncTask then creating your own thread will be more efficient (all AsyncTask requests use a single thread in API 13 and up.)

I'm unfamiliar with your app and how it functions.. do your users require the dialogs and status feedback for thses background network transmissions?



回答2:

Can I just point out that, because you are not doing this in a Service, your remote query stands every chance of being killed, as soon your Activity is hidden. You have, essentially, rewritten IntentService... except that your version will get killed and the version the framework provides, free, will not

IntentService, FTW