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权限。