本篇文章主要参考自:http://developer.android.com/training/volley/index.html
按照谷歌官方的说法,Volley主要适用于那些数据量不大,但是通信频繁的场景。这篇文章主要讲些基本用法,关于Volley的具体实现原理,我暂时也没去研究。
Google推荐用一个单例类来管理Volley的所有网络请求,下面是我目前用到的单例类:
package com.android.etuan.whereru;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.LruCache;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;
public class MyVolleySingleton {
private static MyVolleySingleton mInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static Context mContext;
private MyVolleySingleton(Context context) {
mContext = context;
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue,
new ImageLoader.ImageCache() {
//谷歌官方推荐的缓存大小计算方式
int maxMemory = (int) Runtime.getRuntime().maxMemory() / 1024;
int cacheSize = maxMemory / 8;
private final LruCache<String, Bitmap>
cache = new LruCache<>(cacheSize);
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
}
public static synchronized MyVolleySingleton getInstance(Context context) {
if (mInstance == null) {
mInstance = new MyVolleySingleton(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
// getApplicationContext() is key, it keeps you from leaking the
// Activity or BroadcastReceiver if someone passes one in.
mRequestQueue = Volley.newRequestQueue(mContext.getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req) {
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
}
对于一般APP,get和post足以解决大部分问题了(不过Volley请求的时候好像连Get和Post都不需要指定),下面是我用来请求学校名称列表数据的部分代码(删减了部分相关度不高的代码):
//下拉列表的数据
mSchoolList = new ArrayList<>();
//请求学校名称数据
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(
InterfaceConstant.SCHOOL_NAME_LIST_URL,
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray jsonArray) {
mSchoolList = new ArrayList<>();
for (int i = 0;i < jsonArray.length();i++) {
try {
mSchoolList.add(jsonArray.getJSONObject(i).getString("name"));
} catch (JSONException e) {
System.out.println("JSON解析出错 SchoolList");
}
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
MyVolleySingleton.getInstance(this.getApplicationContext())
.addToRequestQueue(jsonArrayRequest);
就功能实现来说异常简单(当然因为这里要解析的JSON数据很简单,而且数据只在这里用一次,所以直接在这里解析掉了),我目前一般采用的方式如下:
package com.android.etuan.whereru.utils.jsonjavabean;
import org.json.JSONException;
import org.json.JSONObject;
public class Person {
private static Person sPerson;
private Person() {
}
public static synchronized Person getInstance() {
if (sPerson == null) {
sPerson = new Person();
}
return sPerson;
}
private final String EroMsg = "JSON解析出错 Person";
private String m_id;
private int mTtl;
private String mCreated;
private String mUserId;
private String mName;
private String mSchool;
private String mPhone;
private String mSign;
public String getM_id() {
return m_id;
}
public String getmCreated() {
return mCreated;
}
public int getmTtl() {
return mTtl;
}
public String getmUserId() {
return mUserId;
}
public String getmName() {
return mName;
}
public String getmSchool() {
return mSchool;
}
public String getmPhone() {
return mPhone;
}
public String getmSign() {
return mSign;
}
public void getInfoFromJson(JSONObject jsonObject) {
try {
m_id = jsonObject.getString("id");
} catch (JSONException e) {
System.out.println(EroMsg + "id");
}
try {
mTtl = jsonObject.getInt("ttl");
} catch (JSONException e) {
System.out.println(EroMsg + "ttl");
}
try {
mCreated = jsonObject.getString("created");
} catch (JSONException e) {
System.out.println(EroMsg + "created");
}
try {
mUserId = jsonObject.getString("userId");
} catch (JSONException e) {
System.out.println(EroMsg + "userId");
}
try {
JSONObject jsonUser = jsonObject.getJSONObject("user");
try {
mPhone = jsonUser.getString("phone");
} catch (JSONException e) {
System.out.println(EroMsg + "phone");
}
try {
mName = jsonUser.getString("name");
} catch (JSONException e) {
System.out.println(EroMsg + "name");
}
try {
mSchool = jsonUser.getString("school");
} catch (JSONException e) {
System.out.println(EroMsg + "school");
}
try {
mSign = jsonUser.getString("sign");
} catch (JSONException e) {
System.out.println(EroMsg + "sign");
}
} catch (Exception e) {
System.out.println("JSON解析出错 User");
e.printStackTrace();
}
}
}
比如上面这个用户信息,在APP的很多界面都会用到,没有必要每次用到都做一次网络请求,所以直接用一个单例类做存储,用到直接调用。
上面JSON解析的代码我也直接扔在单例类里,代码量不大,感觉没必要单独搞个类去做数据解析。上面我没用类似Gson这种框架去做解析,一是我们要解析的JSON数据量不太大,二嘛,好像后端给的JSON数据不是很合法啊,总是各种问题,折腾来折腾去,我发现如果自己手写早写好了,当然也可能我自己Gson用的不熟练导致的。。。
上面看了下获取JSONArray类型的,其实JSONObject也差不多:
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(
InterfaceConstant.SCHOOL_ACTIVITY_URL, null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
MyVolleySingleton.getInstance(this.getApplicationContext())
.addToRequestQueue(jsonObjectRequest);
下面再看下用Volley从服务器端获取图片的方法,下面是加载校园活动的ListView的Adapter的代码,其中用到了这部分知识:
package com.android.etuan.whereru.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.android.etuan.whereru.MyVolleySingleton;
import com.android.etuan.whereru.R;
import com.android.etuan.whereru.utils.jsonjavabean.mActivity;
import com.android.volley.toolbox.NetworkImageView;
import java.util.List;
public class CampusActivityListViewAdapter extends BaseAdapter {
private Context mContext;
private List<mActivity> mActivityDataList;
private LayoutInflater mLayoutInflater;
//把该做的工作放在构造函数里做掉去,以免在getView中反复操作
public CampusActivityListViewAdapter(Context context) {
mContext = context;
mLayoutInflater = LayoutInflater.from(mContext);
}
public void setmActivityDataList(List<mActivity> mActivityDataList) {
this.mActivityDataList = mActivityDataList;
}
@Override
public int getCount() {
return mActivityDataList.size();
}
@Override
public Object getItem(int position) {
return mActivityDataList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public static class ViewHolder {
public TextView activityTitleTextView;
public TextView activitySponsorTextView;
public TextView activityCreateTimeTextView;
public TextView activityKeywordTextView;
public NetworkImageView activityPosterImageView;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = mLayoutInflater
.inflate(R.layout.campus_activity_home_page_activity_listview_item_layout, null);
viewHolder = new ViewHolder();
viewHolder.activityTitleTextView = (TextView)
convertView.findViewById(R.id.activity_title);
viewHolder.activitySponsorTextView = (TextView)
convertView.findViewById(R.id.activity_sponsor);
viewHolder.activityCreateTimeTextView = (TextView)
convertView.findViewById(R.id.activity_create_time);
viewHolder.activityKeywordTextView = (TextView)
convertView.findViewById(R.id.activity_keyword);
viewHolder.activityPosterImageView = (NetworkImageView)
convertView.findViewById(R.id.activity_poster);
//设置加载过程中的默认图片
viewHolder.activityPosterImageView.setDefaultImageResId(R.drawable.loading_image);
//设置加载出错时的图片
viewHolder.activityPosterImageView.setErrorImageResId(R.drawable.loading_image_error);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.activityTitleTextView.setText(mActivityDataList.get(position).getTitle());
viewHolder.activitySponsorTextView.setText(mActivityDataList.get(position).getAuthorName());
viewHolder.activityCreateTimeTextView.setText(mActivityDataList.get(position).getCreated());
viewHolder.activityKeywordTextView.setText(mActivityDataList.get(position).getKeyword());
//这里使用Volley来进行图片的加载,图片放在NetworkImageView中
viewHolder.activityPosterImageView.setImageUrl(
mActivityDataList.get(position).getImgUrl(),
MyVolleySingleton.getInstance(mContext.getApplicationContext()).getImageLoader());
return convertView;
}
}
其实核心的就一句代码:
viewHolder.activityPosterImageView.setImageUrl(mActivityDataList.get(position).getImgUrl(),MyVolleySingleton.getInstance(mContext.getApplicationContext()).getImageLoader());
当然前提是你单例类已经写好了,JSON也解析好了,这里注意用NetworkImageView这个控件取代ImageView来放图片。
对了,最后给个post的例子,Google给的教程里好像没有post相关的例子。比如用户注册时就会用到post,代码如下(同样,删掉了部分相关度不高的代码):
Map<String, String> params = new HashMap<>();
params.put("name", userName);
params.put("password", password);
params.put("phone", phoneNumber);
params.put("sex", mSexChooseResult);
params.put("school", mSchoolName);
JSONObject jsonObject = new JSONObject(params);
JsonObjectRequest jsonRequest = new JsonObjectRequest(
InterfaceConstant.REGISTER_URL, jsonObject,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
MyVolleySingleton.getInstance(RegisterPageTwoActivity.this.getApplicationContext())
.addToRequestQueue(jsonRequest);