Android 使用Volley 解析JSON
在本教程中,我们将在Android中使用Volley 解析JSON。
之前,我们看到了Android JSON解析教程非常简单。
在本教程中,我们将使用外部库volle权来发送HTTP请求。
我们可以将其视为以前的教程中ASYNCTASK的替代品。
为什么要使用Volley而不是AsyncTask
- 不太复杂
- 高效的网络管理。
- 轻松定制
例子 :
我已经实现了Restful WebServices JSON示例。
我将使用相同的例子来实现RESTful Web服务。
如果我们要部署以上Web服务,请使用以下URL来获取JSON数据
<span style="color: green; font-weight: bold;">http://192.168.2.22:8080/JAXRSJsonExample/rest/countries
192.168.2.22是我机器的IP地址。
在计算机上实现此Web服务后,我们应该用IP地址替换它。
如果我们不想自己实现REST Web服务并希望低于JSON响应。
我们可以使用以下链接。
https://cdn.rawgit.com/arpitmandliya/androidrestjsonexample/master/countries.json我们将从上面的URL上获得以下JSON响应:
[
{
"id":1,
"countryName":"San Franceco"
},
{
"id":4,
"countryName":"China"
},
{
"id":3,
"countryName":"Nepal"
},
{
"id":2,
"countryName":"Bhutan"
}
]
我们从REST Web服务中获得了JSONARRAY。
如果我们不熟悉JSON,则可以通过JSON教程进行。
我们将渲染以上JSON响应Android自定义列表查看:
第1步:创建项目
创建一个Android应用程序ProjectNamed"JSONPASINGUSINGVOLLEY"。
第2步:添加凌空地面依赖性
对于使用volley库,我们需要添加volley依赖关系"compile'com.mc.mcxiacoke.volley:1.0.19'"在build.gradle中(模块:应用程序)
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "com.theitroad.jsonparsingusingvolley"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.0.0'
compile 'com.mcxiaoke.volley:library:1.0.19'
testCompile 'junit:junit:4.12'
}
第3步:创建布局
更改RES - >布局 - > Activity_main.xml如下所示:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="10dp" tools:context="com.theitroad.androidrestjsonexample.MainActivity"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Fetching countries data" android:id="@+id/btnSubmit" <ListView android:id="@+id/android:list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/btnSubmit" </RelativeLayout>
我们有一个按钮和ListView。
单击按钮时,我们将通过调用RESTful Web服务并在ListView上渲染它来填充ListView中的数据。
第4步:为行创建布局
正如我们在Activity_main.xml中声明listview小部件。
现在我们需要为单个行提供布局。
- 转到res - >布局
- 右键单击布局
- 单击"新建 - >文件"。
- 创建名为"row_item.xml"的文件,并在row_item.xml中粘贴以下代码。
<?xml version="1.0" encoding="utf-8"?> <GridLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_columnWeight="1" android:layout_marginLeft="10dp" android:textSize="30dp" android:textColor="#1E90FF" android:id="@+id/textViewId" android:layout_row="0" android:layout_column="1" <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_columnWeight="1" android:layout_marginLeft="10dp" android:textSize="20dp" android:textColor="#4B0082" android:id="@+id/textViewCountry" android:layout_row="1" android:layout_column="1" </GridLayout>
第5步:创建模型对象国家/地区:
如果我们注意到,我们从RESTful Web服务中获取JSON数组,其中有4项。
每个项目都有两个属性ID和CountryName。
我们将为每个项目创建国家对象。
package com.theitroad.androidrestjsonexample;
public class Country{
int id;
String countryName;
public Country(int i, String countryName) {
super();
this.id = i;
this.countryName = countryName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
}
步骤6:为ListView创建BaseAdapter
在创建捕获期之前,我们需要为自定义ListView行创建CustomCountrylist类。
package com.theitroad.androidrestjsonexample;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.theitroad.androidrestjsonexample.Country;
import com.theitroad.androidrestjsonexample.R;
import java.util.ArrayList;
public class CustomCountryList extends BaseAdapter {
private Activity context;
ArrayList countries;
public CustomCountryList(Activity context, ArrayList countries) {
// super(context, R.layout.row_item, countries);
this.context = context;
this.countries=countries;
}
public static class ViewHolder
{
TextView textViewId;
TextView textViewCountry;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row=convertView;
LayoutInflater inflater = context.getLayoutInflater();
ViewHolder vh;
if(convertView==null) {
vh=new ViewHolder();
row = inflater.inflate(R.layout.row_item, null, true);
vh.textViewId = (TextView) row.findViewById(R.id.textViewId);
vh.textViewCountry = (TextView) row.findViewById(R.id.textViewCountry);
//store the holder with the view.
row.setTag(vh);
}
else {
vh = (ViewHolder) convertView.getTag();
}
vh.textViewCountry.setText(countries.get(position).getCountryName());
vh.textViewId.setText(""+countries.get(position).getId());
return row;
}
public long getItemId(int position) {
return position;
}
public Object getItem(int position) {
return position;
}
public int getCount() {
if(countries.size()<=0)
return 1;
return countries.size();
}
}
此类用于填充ListView的数据。
GetView方法被调用以绘制每一行。
第7步:创建MainActivity
我们将使用jsonArrayrequest类的凌空库 。
JsonArrayRequest req = new JsonArrayRequest(jsonURl,
new Response.Listener() {
@Override
public void onResponse(JSONArray response) {... , new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {...)
它有三个参数。
- 返回jsonArray响应的REST Web服务URL。
- 传递具有呼叫响应的方法的侦听器在获取REST URL的响应时会被调用。
- 通过errorListener,当我们在执行REST Web服务URL时出现任何错误时,将在发生任何错误时调用orerrorresponse。
我们还可以使用volley类使用jsonObjectRequest或者stringRequest取决于需求。
更改src/main/packageName/mainActivity.java如下:
package com.theitroad.jsonparsingusingvolley;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.URL;
import java.util.ArrayList;
import static android.content.ContentValues.TAG;
public class MainActivity extends AppCompatActivity {
private Button btnSubmit;
String responseText;
Activity activity;
ArrayList countries=new ArrayList();
private ProgressDialog progressDialog;
ListView listView;
//In case if you deploy rest web service, then use below link and replace below ip address with yours
//http://192.168.2.22:8080/JAXRSJsonExample/rest/countries
//Direct Web services URL
private String path = "https://cdn.rawgit.com/arpitmandliya/AndroidRestJSONExample/master/countries.json";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity = this;
btnSubmit = (Button) findViewById(R.id.btnSubmit);
listView = (ListView) findViewById(android.R.id.list);
btnSubmit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
countries.clear();
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Fetching conntry data");
progressDialog.setCancelable(false);
progressDialog.show();
//Call WebService
getWebServiceResponseData();
}
});
}
protected Void getWebServiceResponseData() {
JsonArrayRequest req = new JsonArrayRequest(jsonURl,
new Response.Listener() {
@Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
if (progressDialog.isShowing())
progressDialog.dismiss();
//Parsing json response and iterate over each JSON object
Log.d(TAG, "data:" + responseText);
try {
for (int i = 0; i < response.length(); i++) {
JSONObject jsonobject = response.getJSONObject(i);
int id = jsonobject.getInt("id");
String country = jsonobject.getString("countryName");
Log.d(TAG, "id:" + id);
Log.d(TAG, "country:" + country);
Country countryObj = new Country(id, country);
countries.add(countryObj);
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
CustomCountryList customCountryList = new CustomCountryList(activity, countries);
listView.setAdapter(customCountryList);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
Toast.makeText(getApplicationContext(),"You Selected "+countries.get(position).getCountryName()+ " as Country",Toast.LENGTH_SHORT).show(); }
});
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this,error.getMessage(),Toast.LENGTH_LONG).show();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(req);
return null;
}
}
第8步:在androidmanifest.xml中添加Internet权限
复制以下代码:
<uses-permission android:name="android.permission.INTERNET"
把它放在androidmanifest.xml中
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.theitroad.jsonparsingusingvolley"> <uses-permission android:name="android.permission.INTERNET" <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" <category android:name="android.intent.category.LAUNCHER" </intent-filter> </activity> </application> </manifest>
完成了,我们为Androidmanifest.xml添加了Internet权限。

