在 Android 上调用返回 JSON 响应的 HTTP Web API 调用的最有效方法是什么?

我是完美主义者类型,我已经有Web API调用与Google Places API一起工作(只是作为一个例子),但我觉得它有时很慢,或者也许我做得不对。一些博客说我应该使用AndroidHttpClient,但我不是,我应该吗?

我正在使用的Web API调用返回json,我不在UI线程上运行它们,因此使用AsyncTask(AsyncTask是在后台线程上运行的最有效方式还是我应该使用其他东西?

请看我的代码,并告诉我它怎么能更有效率

public static class NearbySearchRequest extends AsyncTask<String, Void, JSONObject>
{
    Exception mException = null;

    @Override
    protected void onPreExecute()
    {
        super.onPreExecute();
        this.mException = null;
    }

    @Override
    protected JSONObject doInBackground(String... params)
    {
        StringBuilder urlString = new StringBuilder();
        urlString.append("https://maps.googleapis.com/maps/api/place/nearbysearch/json?");
        urlString.append("key=").append(Constants.GOOGLE_SIMPLE_API_KEY);
        urlString.append("&location=").append(params[0]);
        urlString.append("&sensor=").append("true");
        urlString.append("&language=").append("en-GB");
        urlString.append("&name=").append(params[1]);
        urlString.append("&rankby=").append("distance");

        LogHelper.Log(urlString.toString());

        HttpURLConnection urlConnection = null;
        URL url = null;
        JSONObject object = null;

        try
        {
            url = new URL(urlString.toString());
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.connect();
            InputStream inStream = null;
            inStream = urlConnection.getInputStream();
            BufferedReader bReader = new BufferedReader(new InputStreamReader(inStream));
            String temp, response = "";
            while ((temp = bReader.readLine()) != null)
                response += temp;
            bReader.close();
            inStream.close();
            urlConnection.disconnect();
            object = (JSONObject) new JSONTokener(response).nextValue();
        }
        catch (Exception e)
        {
            this.mException = e;
        }

        return (object);
    }

    @Override
    protected void onPostExecute(JSONObject result)
    {
        super.onPostExecute(result);

        if (this.mException != null)
            ErrorHelper.report(this.mException, "Error # NearbySearchRequest");
    }
}

答案 1

您使用的Http引擎似乎是最佳选择。实际上,任何其他第三方引擎都基于Apache,或者基于HttpUrlConnection。我更喜欢使用Spring for Android,因为该API提供了对Http引擎的抽象,并且您实际上不需要关心如何根据API级别使用哪种API。或者你可以使用Volley - 一个非常时尚的图书馆。

但是,我会触摸您的一些代码:

  1. 如果在读取流时出现异常,该怎么办?然后,流保持打开状态,并且连接也保持打开状态。因此,我建议最终阻止流和连接关闭,无论您是否遇到异常:

    HttpURLConnection urlConnection = null;
    URL url = null;
    JSONObject object = null;
    InputStream inStream = null;
    try {
        url = new URL(urlString.toString());
        urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("GET");
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);
        urlConnection.connect();
        inStream = urlConnection.getInputStream();
        BufferedReader bReader = new BufferedReader(new InputStreamReader(inStream));
        String temp, response = "";
        while ((temp = bReader.readLine()) != null) {
            response += temp;
        }
        object = (JSONObject) new JSONTokener(response).nextValue();
    } catch (Exception e) {
        this.mException = e;
    } finally {
        if (inStream != null) {
            try {
                // this will close the bReader as well
                inStream.close();
            } catch (IOException ignored) {
            }
        }
        if (urlConnection != null) {
            urlConnection.disconnect();
        }
    }
    
  2. JSON解析:您正在使用Android标准方式解析JSON,但这不是最快,最容易使用的方法。GSONJackson最好使用。为了在JSON解析器方面进行比较,我会选择Jackson。这是关于此比较的另一个SO主题

  3. 不要像那样连接字符串,因为每次创建另一个字符串时,都会创建连接字符串。请改用 StringBuilder

  4. 异常处理(无论如何,这是所有编程论坛中长期争论的主题)。首先,您必须记录它(不使用日志类)。然后,您需要通知用户:要么祝酒消息,要么显示标签或通知。该决定取决于用户案例以及您正在拨打的电话的相关性。System.out.printXXX

这些是我在您的代码中看到的主题。

编辑我意识到我没有回答这个问题:is AsyncTask the most efficient way to run on background thread or should I use something else?

我想给出的简短答案是:如果你应该执行一个短暂的请求,那么它是完美的。但是,如果您需要获取一些数据并显示它 - 但是您不想担心如果屏幕旋转等是否再次下载,我强烈建议使用AsyncTaskLoaderLoadersAsyncTask

如果您需要下载一些大数据,则可以使用 IntentService,或者对于重度操作,请使用 DownloadManager

享受编码!


答案 2

------为项目创建服务处理程序类--------

public class ServiceHandler {

static String response = null;
public final static int GET = 1;
public final static int POST = 2;

public ServiceHandler() {
}

/*
 * Making service call
 * @url - url to make request
 * @method - http request method
 * */
public String makeServiceCall(String url, int method) {
    return this.makeServiceCall(url, method, null);
}

/*
 * Making service call
 * @url - url to make request
 * @method - http request method
 * @params - http request params
 * */
public String makeServiceCall(String url, int method,
        List<NameValuePair> params) {
    try {
        // http client
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpEntity httpEntity = null;
        HttpResponse httpResponse = null;

        // Checking http request method type
        if (method == POST) {
            Log.e("in POST","in POST");
            HttpPost httpPost = new HttpPost(url);
            // adding post params
            if (params != null) {
                Log.e("in POST params","in POST params");
                httpPost.setEntity(new UrlEncodedFormEntity(params));
            }
            Log.e("url in post service",url);
            httpResponse = httpClient.execute(httpPost);

        } else if (method == GET) {
            // appending params to url
            Log.e("in GET","in GET");
            if (params != null) {
                Log.e("in GET params","in GET params");
                String paramString = URLEncodedUtils
                        .format(params, "utf-8");
                url += "?" + paramString;
            }
            Log.e("url in get service",url);
            HttpGet httpGet = new HttpGet(url);

            httpResponse = httpClient.execute(httpGet);

        }
        httpEntity = httpResponse.getEntity();
        response = EntityUtils.toString(httpEntity);

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return response;

}
public String makeServiceCallIMAGE(String url, int method,
        List<NameValuePair> params) {
    try {
        // http client
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpEntity httpEntity = null;
        HttpResponse httpResponse = null;

        // Checking http request method type
        if (method == POST) {
            HttpPost httpPost = new HttpPost(url);
            // adding post params
            if (params != null) {
                httpPost.setEntity(new UrlEncodedFormEntity(params));

            }

            httpResponse = httpClient.execute(httpPost);

        } else if (method == GET) {
            // appending params to url
            if (params != null) {
                String paramString = URLEncodedUtils
                        .format(params, "utf-8");
                url += "?" + paramString;
            }
            HttpGet httpGet = new HttpGet(url);

            httpResponse = httpClient.execute(httpGet);

        }
        httpEntity = httpResponse.getEntity();
        response = EntityUtils.toString(httpEntity);

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return response;
}
}

--------------用于登录的异步任务------------------

public class Login_Activity extends ActionBarActivity {

//Internet Service
NetworkConnection nw;
ProgressDialog prgDialog;
Boolean netConnection = false;
//

//Login API
String loginURL ="url";
//

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);

    nw = new NetworkConnection(getApplicationContext());
    prgDialog = new ProgressDialog(this);
    // Set Cancelable as False
    prgDialog.setCancelable(false);

    new LoginOperation().execute();
}

private class LoginOperation  extends AsyncTask<String, Void, Void> {

    String status, message;
    @Override
    protected void onPreExecute() {
        // Set Progress Dialog Text
        prgDialog.setMessage("Logging...");
        prgDialog.show();
    }

    @Override
    protected Void doInBackground(String... urls) {

        if(nw.isConnectingToInternet() == true)
        {
            try
            {
                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
                nameValuePairs.add(new BasicNameValuePair("method", "ClientesLogin"));
                nameValuePairs.add(new BasicNameValuePair("Email", str_Email));
                nameValuePairs.add(new BasicNameValuePair("Senha", str_Password));
                ServiceHandler sh  = new ServiceHandler();
                String response = sh.makeServiceCall(loginURL, ServiceHandler.GET,
                        nameValuePairs);

                Log.e("response", response);

                JSONObject js = new JSONObject(response);
                status = js.getString("status");
                Log.e("status",status);

                if(status.contains("Fail"))
                {
                    message = js.getString("message");
                }
                /*else
                {
                    JSONObject jslogin=js.getJSONObject("user_list");
                    for (int i = 0; i < jslogin.length(); i++) {
                    }
                }*/

            }catch(Exception ex){

            }
            netConnection = true;
        }else
        {
            netConnection = false;
        }

        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        prgDialog.dismiss();

        if(netConnection == false)
        {
            Toast toast = Toast.makeText(getApplicationContext(),"Internet is not available. Please turn on and try again.", Toast.LENGTH_LONG);
            toast.setGravity(Gravity.CENTER, 0, 0);
            toast.show();
        }
        else
        {
            if(status.contains("Success"))
            {
                Toast toast = Toast.makeText(getApplicationContext(), "Login Successful", Toast.LENGTH_SHORT);
                toast.setGravity(Gravity.CENTER, 0, 0);
                toast.show();

                Intent i=new Intent(Login_Activity.this,home_page_activity.class);
                startActivity(i);
            }
            else{
                Toast toast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT);
                toast.setGravity(Gravity.CENTER, 0, 0);
                toast.show();
            }
        }
        super.onPostExecute(result);
    }
}
}

---------------网络连接类---------------------

public class NetworkConnection {

Context context;

public NetworkConnection(Context context){
    this.context = context;
}

public boolean isConnectingToInternet(){
    ConnectivityManager connectivity = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
      if (connectivity != null) 
      {
          NetworkInfo[] info = connectivity.getAllNetworkInfo();
          if (info != null) 
              for (int i = 0; i < info.length; i++) 
                  if (info[i].getState() == NetworkInfo.State.CONNECTED)
                  {
                      return true;
                  }
      }
      return false;
}
}

JSONArray main1 = js.getJSONArray("Test 1");

  for (int i = 0; i < main1.length(); i++) {

    JSONObject jsonObject = main1.getJSONObject(i);

推荐