40

我是完美主义者,我已经让 Web API 调用在 Google Places API 上运行良好(仅作为示例),但我觉得它有时很慢,或者我做得不对。有些博客说我应该使用 AndroidHttpClient,但我不是,应该吗?

我正在使用返回 json 的 Web API 调用,我不在 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");
    }
}
4

2 回答 2

46

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

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

  1. 如果读取流时出现异常怎么办?然后流保持打开状态,连接也保持打开状态。所以我建议有一个 finally 块,无论您是否遇到异常,流和连接都会关闭:

    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 解析:您正在使用解析 JSON 的 Android 标准方式,但这不是最快和最容易使用的。GSONJackson更好用。为了比较JSON 解析器,我会选择 Jackson。这是有关此比较的另一个 SO 主题。

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

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

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

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

我会给出的简短回答是:如果你应该执行一个短暂的请求,那么AsyncTask就是完美的。但是,如果你需要获取一些数据并显示出来——但又不想担心屏幕旋转等情况下是否要重新下载,我强烈建议一般使用AsyncTaskLoaderand Loaders

如果您需要下载一些大数据,那么您可以使用IntentServiceor,对于重量级操作,DownloadManager.

享受编码!

于 2013-09-27T12:56:50.787 回答
6

------为您的项目创建一个服务处理程序类--------

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);
于 2015-08-01T07:06:59.213 回答