標簽(空格分隔): Volley Session小結(jié)
Volley創(chuàng)建過程
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
Network network = new BasicNetwork(stack);
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
}
Volley默認給出了兩種創(chuàng)建方式颅围,其中HurlStack對應(yīng)HttpURLConnection秸弛,而HttpClientStack對應(yīng)于HttpClient.默認情況下坯墨,Volley是不支持Cookies和Session的禁舷。這兩種情況下添加session支持的方式如下违霞。
兩種方式對Session支持:
1.HttpURLConnection方式
CookieManager cookieManager = new CookieManager( );
CookieHandler.setDefault( cookieManager );
RequestQueue mRequestQueue = Volley.newRequestQueue( context )
添加一個CookieManager即可讓HttpURLConnection支持session,在HttpURLConnectionImpl實現(xiàn)類中OkHttpClient會引用這個cookiemanager對象佳镜。均為java.net包下提供。這種方式目前沒有并發(fā)問題姊氓,下面來看看另外一種丐怯。
2.HttpClient方式
//自定義一個PreferencesCookieStore對象,把cookie值本地化存起來
HttpClient defaultHttpClient = new DefaultHttpClient();
CookieStore cookieStore = new PreferencesCookieStore( context );
defaultHttpClient.setCookieStore( cookieStore );
HttpStack httpStack = new HttpClientStack( defaultHttpClient );
RequestQueue mRequestQueue = Volley.newRequestQueue( context, httpStack );
但是有一個嚴重問題使用這種方式之后,網(wǎng)絡(luò)請求由httpClient執(zhí)行翔横,我們會失去Volley一個很重要的并發(fā)功能读跷,因為我們使用的是HttpClient的一個單例,我們必須遵守它的規(guī)則禾唁,同一個實例下一個請求必須在上一個請求已經(jīng)結(jié)束情況下才行效览。很顯然无切,這樣使用Volley并發(fā)的問題在實際開發(fā)中完全不能滿足我們的需要。下面是一種改良法丐枉,經(jīng)我測試哆键,只不過是加上的等待機制,對于真正并發(fā)來說效率低了許多瘦锹。
如下:
DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
ClientConnectionManager mClientConnectionManager = defaultHttpClient.getConnectionManager();
HttpParams mHttpParams = defaultHttpClient.getParams();
ThreadSafeClientConnManager mThreadSafeClientConnManager = new ThreadSafeClientConnManager( mHttpParams,
mClientConnectionManager.getSchemeRegistry() );
defaultHttpClient = new DefaultHttpClient( mThreadSafeClientConnManager, mHttpParams );
CookieStore cookieStore = new PreferencesCookieStore( context );
defaultHttpClient.setCookieStore( cookieStore );
HttpStack httpStack = new HttpClientStack( defaultHttpClient );
mRequestQueue = Volley.newRequestQueue( context, httpStack );
關(guān)于HttpClient的Cookie機制簡要說明责鳍,假設(shè)cookie保存在本地昼蛀,當去請求一個網(wǎng)址的時候违寞,request會獲取本地的cookie對象(CookieStore.getCookies())纵潦,即是我們代碼中setCookieStore設(shè)置的,第一次,本地cookie是空听绳,這個時候服務(wù)器給回response的時候颂碘,會根據(jù)規(guī)則判斷是否要往本地寫cookie (CookieStore.addCookie(Cookie)),第一次顯然會將當前這次連接的cookie信息保存下來椅挣。以后再由請求的時候头岔,即能從本地中獲取cookie去請求了,當然整個過程復雜度是比較高的
eg:自定義PreferencesCookieStore如下
PreferencesCookieStore.java
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import org.apache.http.client.CookieStore;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.cookie.BasicClientCookie;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* 保存到 Preferences 的cookie
*
*/
public class PreferencesCookieStore implements CookieStore {
private static final String COOKIE_PREFS = "CookiePrefsFile";
private static final String COOKIE_NAME_STORE = "names";
private static final String COOKIE_NAME_PREFIX = "cookie_";
private final ConcurrentHashMap<String, Cookie> cookies;
private final SharedPreferences cookiePrefs;
/**
* Construct a persistent cookie store.
*/
public PreferencesCookieStore(Context context) {
cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0);
cookies = new ConcurrentHashMap<String, Cookie>();
// Load any previously stored cookies into the store
String storedCookieNames = cookiePrefs.getString(COOKIE_NAME_STORE, null);
if(storedCookieNames != null) {
String[] cookieNames = TextUtils.split(storedCookieNames, ",");
for(String name : cookieNames) {
String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null);
if(encodedCookie != null) {
Cookie decodedCookie = decodeCookie(encodedCookie);
if(decodedCookie != null) {
cookies.put(name, decodedCookie);
}
}
}
// Clear out expired cookies
clearExpired(new Date());
}
}
@Override
public void addCookie(Cookie cookie) {
String name = cookie.getName();
// Save cookie into local store, or remove if expired
if(!cookie.isExpired(new Date())) {
cookies.put(name, cookie);
} else {
cookies.remove(name);
}
// Save cookie into persistent store
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet()));
prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie( new SerializableCookie( cookie ) ));
prefsWriter.commit();
}
@Override
public void clear() {
// Clear cookies from local store
cookies.clear();
// Clear cookies from persistent store
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
for(String name : cookies.keySet()) {
prefsWriter.remove(COOKIE_NAME_PREFIX + name);
}
prefsWriter.remove(COOKIE_NAME_STORE);
prefsWriter.commit();
}
@Override
public boolean clearExpired(Date date) {
boolean clearedAny = false;
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
for(ConcurrentHashMap.Entry<String, Cookie> entry : cookies.entrySet()) {
String name = entry.getKey();
Cookie cookie = entry.getValue();
if(cookie.isExpired(date)) {
// 清除cookies
cookies.remove(name);
// Clear cookies from persistent store
prefsWriter.remove(COOKIE_NAME_PREFIX + name);
// We've cleared at least one
clearedAny = true;
}
}
// Update names in persistent store
if(clearedAny) {
prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet()));
}
prefsWriter.commit();
return clearedAny;
}
@Override
public List<Cookie> getCookies() {
return new ArrayList<Cookie>(cookies.values());
}
protected String encodeCookie(SerializableCookie cookie) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
ObjectOutputStream outputStream = new ObjectOutputStream(os);
outputStream.writeObject(cookie);
} catch (Exception e) {
return null;
}
return byteArrayToHexString(os.toByteArray());
}
protected Cookie decodeCookie(String cookieStr) {
byte[] bytes = hexStringToByteArray(cookieStr);
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
Cookie cookie = null;
try {
ObjectInputStream ois = new ObjectInputStream(is);
cookie = ((SerializableCookie)ois.readObject()).getCookie();
} catch (Exception e) {
e.printStackTrace();
}
return cookie;
}
// Using some super basic byte array <-> hex conversions so we don't have
// to rely on any large Base64 libraries. Can be overridden if you like!
protected String byteArrayToHexString(byte[] b) {
StringBuffer sb = new StringBuffer(b.length * 2);
for (byte element : b) {
int v = element & 0xff;
if(v < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(v));
}
return sb.toString().toUpperCase();
}
protected byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for(int i=0; i<len; i+=2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
}
return data;
}
public class SerializableCookie implements Serializable {
private static final long serialVersionUID = 6374381828722046732L;
private transient final Cookie cookie;
private transient BasicClientCookie clientCookie;
public SerializableCookie(Cookie cookie) {
this.cookie = cookie;
}
public Cookie getCookie() {
Cookie bestCookie = cookie;
if(clientCookie != null) {
bestCookie = clientCookie;
}
return bestCookie;
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeObject(cookie.getName());
out.writeObject(cookie.getValue());
out.writeObject(cookie.getComment());
out.writeObject(cookie.getDomain());
out.writeObject(cookie.getExpiryDate());
out.writeObject(cookie.getPath());
out.writeInt(cookie.getVersion());
out.writeBoolean(cookie.isSecure());
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
String name = (String)in.readObject();
String value = (String)in.readObject();
clientCookie = new BasicClientCookie(name, value);
clientCookie.setComment((String)in.readObject());
clientCookie.setDomain((String)in.readObject());
clientCookie.setExpiryDate((Date)in.readObject());
clientCookie.setPath((String)in.readObject());
clientCookie.setVersion(in.readInt());
clientCookie.setSecure(in.readBoolean());
}
}
}