Google I/O 2013上,Volley发布。它是Android平台上的网络通信库,能使网络通信更快,更简单,更健壮。
提供功能:
- JSON,图像等的异步下载;
- 网络请求的排序(scheduling)
- 网络请求的优先级处理
- 缓存
- 多级别取消请求
- 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求)
volley适合:数据量不大,通信频繁的网络操作,对大数据量(下载上传文件),会很糟糕。
在实习期间由于要求使用volley,所以第一次开始接触volley,从一开始的迷茫陌生,到疯狂的查找各种资料,通过在项目中用到的实际问题,我想做一些总结,所以写了这篇文章。下面我将介绍我理解的用户登录的一套详细流程,涉及到volley请求以及json数据的解析。
登录流程的总结:首先通过EditText获取到用户名和密码,然后再执行登录请求 LoginToServer()里面发送用户名和密码,服务器返回给我json数据(如果用到Oauth 认证这里返回的json数据就应该是Token的一套东西,如果只是简单的登录,可以和服务器约定返回的内容,提取出对应的内容,包装起来做判断反馈给用户登录是否成功),我需要把这些json数据解析出来,然后再反馈给用户“登录成功”或者“登录失败”。
LoginActivity.class这里是在登录界面调用到 LoginToServer()这个方法,这里我把 User_Local.class 里面写了基本的set,get方法,然后是里面是全局(public static)的方法。
public void onClick(View v) {
switch (v.getId()) {
case R.id.login_button:
if (checkEdit()) {
//这里记得一定要先get获得数据
User_Local.setUsername(username.getText().toString());
User_Local.setPassword(password.getText().toString());
// LoginToServer();
new LoginSupport(LoginActivity.this).LoginToServer();
}
break;
这里是User_Local.class ,首先这里为什么要写成public static,写成这种是说这是全局变量。全局的引用方法就是类名直接引用,不用再new 一个对象。比如这里就是引用直接就是上述的 User_Local.setUsername(username.getText().toString());。什么时候用全局的,什么时候不用,这个大家可以百度一下。比如在接受服务器传过来的json数据我要再建一套类去匹配解析,这个时候就不要用全局的。
public class User_Local {
public static String username = " " ;//用户名
public static String password =" ";//密码
public static String getUsername() {
return username;
}
public static void setUsername(String username) {
User_Local.username = username;
}
public static String getPassword() {
return password;
}
public static void setPassword(String password) {
User_Local.password = password;
}
LoginSupport.class 这个类里面我写了volley的登录请求,还有服务器返回的json数据解析(这里使用的是Gson来解析json数据),还有反馈给用户登录成功失败与否
volley请求简单说就三步:1.添加url地址。2.new 一个请求(请求里面有成功和失败的接口)3.添加请求到请求队列里面去
这里我只用了volley 里面的StringRequest这个请求,这个请求向服务器发送的应该是字符串吧,我理解的是这样的。然后至于volley的其他请求大家可以参考其他的博客和专业资料。
public void LoginToServer( ) {
String url = "http://XXXXX";//1.这里就是你要向服务器发送请求的地址
StringRequest loginRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {//2.new 一个请求
@Override
public void onResponse(String s) {//这里是返回正确反馈的接口(只要请求成功反馈的数据都这这里)
//数据处理反馈(可以这这里处理服务器返回的数据)
DealResponseFromServer(s);//json数据的解析和用户反馈
Log.i("TAG",s);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
//volley 有专门处理error的库,下面就是调用了其中的一些,可以方便调试的时候查找到错误
Log.d(TAG, "Volley returned error________________:" + volleyError);
Class klass = volleyError.getClass();
if(klass == com.android.volley.AuthFailureError.class) {
Log.d(TAG,"AuthFailureError");
Toast.makeText(context,"未授权,请重新登录",Toast.LENGTH_LONG).show();
} else if(klass == com.android.volley.NetworkError.class) {
Log.d(TAG,"NetworkError");
Toast.makeText(context,"网络连接错误,请重新登录",Toast.LENGTH_LONG).show();
} else if(klass == com.android.volley.NoConnectionError.class) {
Log.d(TAG,"NoConnectionError");
} else if(klass == com.android.volley.ServerError.class) {
Log.d(TAG,"ServerError");
Toast.makeText(context,"服务器未知错误,请重新登录",Toast.LENGTH_LONG).show();
} else if(klass == com.android.volley.TimeoutError.class) {
Log.d(TAG,"TimeoutError");
Toast.makeText(context,"连接超时,请重新登录",Toast.LENGTH_LONG).show();
} else if(klass == com.android.volley.ParseError.class) {
Log.d(TAG,"ParseError");
} else if(klass == com.android.volley.VolleyError.class) {
Log.d(TAG,"General error");
}
Toast.makeText(context,"登录失败",Toast.LENGTH_LONG).show();
}
})
{
//这里是添加请求头的地方重写了getHeaders() 方法(发送设么请求头要根据自己实际开发需要设定)
@Override
public Map<String, String> getHeaders() {
HashMap<String, String> header = new HashMap<String, String>();
header.put("Accept","application/json");
header.put("Content-Type","application/x-www-form-urlencoded");
return header;
}
//这里是发送参数的地方,重写了 getParams() 方法(传什么参数给服务器也是实际你自己修改)
@Override
protected Map<String, String> getParams() {
HashMap<String, String> map = new HashMap<String, String>();
//如果出现空指针异常或者是登录失败,先检查这里有木有传进来你要发送的用户名和密码。
//所以在执行get数据方法之前一定要先存数据(set方法)
map.put("username", User_Local.getUsername());
map.put("password", User_Local.getPassword());
return map;
}
};
//设置超时重新请求
loginRequest.setRetryPolicy(new DefaultRetryPolicy(5000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
//设置标签,方便在stop(){}里面取消对应的volley 请求
loginRequest.setTag("POST");
//3.把请求添加到全局请求队列里面
MyApplication.getHttpQueue().add(loginRequest);
}
//建立一个全局请求队列
public class MyApplication extends Application {
public static RequestQueue requestQueue;//
@Override
public void onCreate() {
super.onCreate();
requestQueue = Volley.newRequestQueue(getApplicationContext());
}
public static RequestQueue getHttpQueue(){
return requestQueue;
}
}
Gson解析json数据的精华就是:
gson.fromJson(就是把json数据解析成普通数据)和gson.toJson(把普通数据转化成json类型的数据格式)
要注意的是,这里解析到服务器的数据必须有一套模型和服务器里面的各种数据类型匹配,也就是你需要根据传过来的json数据建一个类来把解析的数据保存起来。
//解析服务器返回的json字符串反馈给用户
public void DealResponseFromServer(String s) {
Gson gson = new Gson();//第一步,实例化
User_Service user_service = gson.fromJson(s, User_Service.class);//第二步,解析数据
if (s!=null) {//这里的s就是上面成功回调接口里面的参数
//这里我保存了从服务器返回的token的信息,至于token就涉及到oauth2.0的内容了,不懂得可以百度,
//当然这里可以保持你需要保存的服务器返回的数据
PreferenceUtils.setPrefString(context,User_Service.userKey, "access_token", user_service.getAccess_token());//保存令牌(这里我用的是自己写的一套SharedPreferences的工具类来保存token)
PreferenceUtils.setPrefString(context,User_Service.userKey, "refresh_token", user_service.getRefresh_token());//保存刷新令牌
Toast.makeText(context, "登录成功", Toast.LENGTH_SHORT).show();//反馈给用户登录成功
}
}
这个就是用于接收服务器返回的json数据类型所建立的类,专门用于解析json数据的。这里的变量就不用设置成全局的变量。
这里面的关系我捋一下,1.从服务器解析的json数据保存到本地数据库里面2.然后本地需要调用数据的时候,再去数据库里面去取。
//用于接收解析服务器返回数据所给的数据
public class User_Service {
public static final String userKey = "user_service";//用于保存服务器端传回的数据文件
private String access_token;//令牌
private String refresh_token;//刷新令牌
public String getAccess_token() {
return access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public void setRefresh_token(String refresh_token) {
this.refresh_token = refresh_token;
}
public String getRefresh_token() {
return refresh_token;
}