詳解使用者登入流程——Volley 請求
volley(一)基本特點
Google I/O 2013上,Volley釋出。它是Android平臺上的網路通訊庫,能使網路通訊更快,更簡單,更健壯。
提供功能:
- JSON,影象等的非同步下載;
- 網路請求的排序(scheduling)
- 網路請求的優先順序處理
- 快取
- 多級別取消請求
- 和Activity和生命週期的聯動(Activity結束時同時取消所有網路請求)
volley適合:資料量不大,通訊頻繁的網路操作,對大資料量(下載上傳檔案),會很糟糕。
使用者登入流程詳解 +volley(StringRequest)
在實習期間由於要求使用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;
}