在 Android 上调用返回 JSON 响应的 HTTP Web API 调用的最有效方法是啥?
Posted
技术标签:
【中文标题】在 Android 上调用返回 JSON 响应的 HTTP Web API 调用的最有效方法是啥?【英文标题】:What is the most efficient way on Android to call HTTP Web API calls that return a JSON response?在 Android 上调用返回 JSON 响应的 HTTP Web API 调用的最有效方法是什么? 【发布时间】:2013-10-03 17:21:47 【问题描述】:我是完美主义者,我已经使用 Google Places API 进行了 Web 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");
【问题讨论】:
根据Android developer,您正在使用的 HttpURLConnection 似乎是 Gingerbread 及更高版本的最佳选择。 【参考方案1】:您使用的 Http 引擎似乎是最佳选择。实际上任何其他第 3 方引擎要么基于 Apache,要么基于 HttpUrlConnection。我更喜欢使用Spring for Android,因为该 API 提供了对 Http Engine 的抽象,并且您实际上不需要关心基于 API 级别使用什么 API。或者你可以使用Volley - 一个非常时尚的库。
我会触摸你的一些代码:
如果读取流时出现异常怎么办?然后流保持打开状态,连接也保持打开状态。所以我建议有一个 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();
JSON 解析:您使用的是 Android 标准解析 JSON 的方式,但这不是最快和最容易使用的。 GSON 和 Jackson 更好用。 To make a comparison 对于 JSON 解析器,我会选择 Jackson。这是another SO topic 的比较结果。
不要像这样连接字符串,因为每次连接字符串都会创建另一个字符串。请改用StringBuilder
。
异常处理(无论如何,这在所有编程论坛中都是一个长期争论的话题)。首先,您必须记录它(使用Log
类而不是System.out.printXXX
)。然后您需要通知用户:您可以发送消息,或者显示标签或通知。该决定取决于用户案例以及您拨打的电话的相关程度。
这些是我在你的代码中看到的主题。
编辑我意识到我没有回答这个问题:is AsyncTask the most efficient way to run on background thread or should I use something else?
我给出的简短答案是:如果您应该执行一个短期的请求,那么AsyncTask
是完美的。但是,如果您需要获取一些数据并显示它 - 但您不想担心如果屏幕旋转等是否再次下载,我强烈建议使用AsyncTaskLoader
和Loaders
一般.
如果您需要下载一些大数据,那么您可以使用IntentService
,或者对于重量级操作,使用DownloadManager
。
享受编码!
【讨论】:
非常感谢您的精彩回答!现在,我保存异常的原因是我可以在 onPostExecute 函数中处理它,因为我的错误处理涉及 Toasting e.getMessage(),而我不能在 doInBackground 中敬酒。创建包装对象和保存响应代码不会有同样的问题吗?还请详细介绍赛车异常点 我现在意识到异常保存在AsyncTask
对象中,很抱歉,我将其删除
我将编辑字符串连接,因为最后一句话毁了它:)
@gunar,Volley 对于并行短请求很有用,尤其是那些用数据填充视图的请求。它不应用于大数据传输。【参考方案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;
-------------AsyncTask For Login------
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);
【讨论】:
以上是关于在 Android 上调用返回 JSON 响应的 HTTP Web API 调用的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
Firebase 可调用函数在 Android SDK 中不返回 JSON 响应
有没有一种简单的方法可以在 Android 上展平 json:api 响应?