在Android应用开发中,我们不可避免的需要网络操作,尤其是在与服务器频繁的交互过程中,更是需要大量的重复编码:HttpURLConnection,Thread, AsyncTask, Service等,十分复杂又容易出错。在2013年Google I/O大会上推出了网络通信框架——Volley。它可以极大简化HTTP通信,加载网络图片的操作,并且在小数据量的频繁网络交互中性能表现良好。不过,它不适合进行大文件的上传下载。
基于上述原因,在最近的项目中我学习使用了Volley网络库,然而Volley在使用中也存在一些问题:
比如,Volley自带的JsonRequest只支持JSONObject,而如果想要使用Gson,还需要自己定制Request。
另外,默认情况下,Volley在Froyo使用Apache Http stack作为其传输层,而在Gingerbread及之后的版本上使用HttpURLConnection stack作为传输层。很自然我们想到,能不能将口碑十分好的OkHttp替换为Volley的传输层呢。
最后,很多时候我们需要一些小文件的上传操作(如用户头像),能不能使用Volley完成这个任务呢。
所以,本文描述一种结合使用Volley+OkHttp+Gson进行快速网络开发的方法,并给出一些网络接口封装的例子。
首先,要将OkHttp替换为Volley的传输层,需要实现一个OkHttpStack类,然后在实例化Volley的RequestQueue时将之替换即可:
OkHttpStack类的代码如下(来自GitHub,详见文后参考资料部分,这里为了方便网络不佳的读者贴出来):
为了方便调用,封装Response接口如下:
至此,对Volley+OkHttp+Gson的封装就完成了。在使用时,我们可以在自定义Application中初始化Queue,再封装一个专门的NetworkManager类来提供所有的网络访问操作,比如,在我最近的项目中是这样用的:
OkHttpStack.java -- from GitHub
Android Networking I: OkHttp, Volley and Gson
Android Volley完全解析(三),定制自己的Request
Android volley 解析(三)之文件上传篇
Android OkHttp完全解析 是时候来了解OkHttp了
基于上述原因,在最近的项目中我学习使用了Volley网络库,然而Volley在使用中也存在一些问题:
比如,Volley自带的JsonRequest只支持JSONObject,而如果想要使用Gson,还需要自己定制Request。
另外,默认情况下,Volley在Froyo使用Apache Http stack作为其传输层,而在Gingerbread及之后的版本上使用HttpURLConnection stack作为传输层。很自然我们想到,能不能将口碑十分好的OkHttp替换为Volley的传输层呢。
最后,很多时候我们需要一些小文件的上传操作(如用户头像),能不能使用Volley完成这个任务呢。
所以,本文描述一种结合使用Volley+OkHttp+Gson进行快速网络开发的方法,并给出一些网络接口封装的例子。
首先,要将OkHttp替换为Volley的传输层,需要实现一个OkHttpStack类,然后在实例化Volley的RequestQueue时将之替换即可:
RequestQueue mQueue = Volley.newRequestQueue(this, new OkHttpStack(new OkHttpClient()));
OkHttpStack类的代码如下(来自GitHub,详见文后参考资料部分,这里为了方便网络不佳的读者贴出来):
/**
* The MIT License (MIT)
*
* Copyright (c) 2015 Circle Internet Financial
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.toolbox.HttpStack;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Protocol;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicStatusLine;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* OkHttp backed {@link com.android.volley.toolbox.HttpStack HttpStack} that does not
* use okhttp-urlconnection
*/
public class OkHttpStack implements HttpStack {
private final OkHttpClient mClient;
public OkHttpStack(OkHttpClient client) {
this.mClient = client;
}
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
OkHttpClient client = mClient.clone();
int timeoutMs = request.getTimeoutMs();
client.setConnectTimeout(timeoutMs, TimeUnit.MILLISECONDS);
client.setReadTimeout(timeoutMs, TimeUnit.MILLISECONDS);
client.setWriteTimeout(timeoutMs, TimeUnit.MILLISECONDS);
com.squareup.okhttp.Request.Builder okHttpRequestBuilder = new com.squareup.okhttp.Request.Builder();
okHttpRequestBuilder.url(request.getUrl());
Map<String, String> headers = request.getHeaders();
for (final String name : headers.keySet()) {
okHttpRequestBuilder.addHeader(name, headers.get(name));
}
for (final String name : additionalHeaders.keySet()) {
okHttpRequestBuilder.addHeader(name, additionalHeaders.get(name));
}
setConnectionParametersForRequest(okHttpRequestBuilder, request);
com.squareup.okhttp.Request okHttpRequest = okHttpRequestBuilder.build();
Call okHttpCall = client.newCall(okHttpRequest);
Response okHttpResponse = okHttpCall.execute();
StatusLine responseStatus = new BasicStatusLine(parseProtocol(okHttpResponse.protocol()), okHttpResponse.code(), okHttpResponse.message());
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
response.setEntity(entityFromOkHttpResponse(okHttpResponse));
Headers responseHeaders = okHttpResponse.headers();
for (int i = 0, len = responseHeaders.size(); i < len; i++) {
final String name = responseHeaders.name(i), value = responseHeaders.value(i);
if (name != null) {
response.addHeader(new BasicHeader(name, value));
}
}
return response;
}
private static HttpEntity entityFromOkHttpResponse(Response r) throws IOException {
BasicHttpEntity entity = new BasicHttpEntity();
ResponseBody body = r.body();
entity.setContent(body.byteStream());
entity.setContentLength(body.contentLength());
entity.setContentEncoding(r.header("Content-Encoding"));
if (body.contentType() != null) {
entity.setContentType(body.contentType().type());
}
return entity;
}
@SuppressWarnings("deprecation")
private static void setConnectionParametersForRequest(com.squareup.okhttp.Request.Builder builder, Request<?> request)
throws IOException, AuthFailureError {
switch (request.getMethod()) {
case Request.Method.DEPRECATED_GET_OR_POST:
// Ensure backwards compatibility. Volley assumes a request with a null body is a GET.
byte[] postBody = request.getPostBody();
if (postBody != null) {
builder.post(RequestBody.create(MediaType.parse(request.getPostBodyContentType()), postBody));
}
break;
case Request.Method.GET:
builder.get();
break;
case Request.Method.DELETE:
builder.delete();
break;
case Request.Method.POST:
builder.post(createRequestBody(request));
break;
case Request.Method.PUT:
builder.put(createRequestBody(request));
break;
case Request.Method.HEAD:
builder.head();
break;
case Request.Method.OPTIONS:
builder.method("OPTIONS", null);
break;
case Request.Method.TRACE:
builder.method("TRACE", null);
break;
case Request.Method.PATCH:
builder.patch(createRequestBody(request));
break;
default:
throw new IllegalStateException("Unknown method type.");
}
}
private static ProtocolVersion parseProtocol(final Protocol p) {
switch (p) {
case HTTP_1_0:
return new ProtocolVersion("HTTP", 1, 0);
case HTTP_1_1:
return new ProtocolVersion("HTTP", 1, 1);
case SPDY_3:
return new ProtocolVersion("SPDY", 3, 1);
case HTTP_2:
return new ProtocolVersion("HTTP", 2, 0);
}
throw new IllegalAccessError("Unkwown protocol");
}
private static RequestBody createRequestBody(Request r) throws AuthFailureError {
final byte[] body = r.getBody();
if (body == null) return null;
return RequestBody.create(MediaType.parse(r.getBodyContentType()), body);
}
}
然后,我们需要实现使用Gson的Request类:
import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.util.Map;
import me.zq.youjoin.utils.LogUtils;
import me.zq.youjoin.utils.StringUtils;
public class PostObjectRequest<T> extends Request<T> {
private ResponseListener listener;
private Gson gson;
private Type clazz;
private Map<String, String> params;
public PostObjectRequest(String url, Map<String, String> params, Type type,
ResponseListener listener){
super(Method.POST, url, listener);
this.listener = listener;
this.clazz = type;
this.params = params;
this.gson = new Gson();
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response){
try{
T result;
String jsonString =
new String(response.data, HttpHeaderParser.parseCharset(response.headers));
LogUtils.d("hehe", jsonString);
result = gson.fromJson(StringUtils.FixJsonString(jsonString), clazz);
return Response.success(result,
HttpHeaderParser.parseCacheHeaders(response));
}catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(T response){
listener.onResponse(response);
}
@Override
protected Map<String, String> getParams() throws AuthFailureError{
return params;
}
}
最后,我们来实现图片上传部分。由于我们希望在上传图片的时候添加一些参数,例如用户id等,导致这部分的实现比较复杂。虽然我们可以将这些信息存储在图片文件名中实现传递,但这总归是取巧的办法。比较正规一点的方法还是研究网页表单提交时的Post请求的格式,然后自己构造一个合法的Post请求。我们可以使用Chorme的开发者工具来抓取Post请求,研究其格式,下图为我抓取的一个带图片和参数的表单Post请求:
从图中可以看出,我们只需要重写getBody()方法,逐行仿照Post格式写入我们自己的图片和参数,就可实现参数+图片的上传。多张图片的上传原理相同。另外,图片要注意在上传之前进行压缩处理。另外,为了方便服务器解析多张图片,将图片参数设置为uploadedfile[index]格式。代码如下:
import android.util.Log;
import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import me.zq.youjoin.model.ImageInfo;
import me.zq.youjoin.utils.StringUtils;
public class PostUploadRequest<T> extends Request<T> {
/**
* 正确数据的时候回掉用
*/
private ResponseListener mListener ;
/*请求 数据通过参数的形式传入*/
private List<ImageInfo> mListItem ;
private static final String BOUNDARY = "--------------520-13-14"; //数据分隔线
private static final String MULTIPART_FORM_DATA = "multipart/form-data";//使用表单数据方法提交
private static final String TAG = "hehe_upload_request";
private static final String PARAM = "uploadedfile";//图片的参数,<span style="font-family: Arial, Helvetica, sans-serif;">为了上传多张图片,在下面的封装中使用uploadedfile[index]格式作为图片参数</span>
private Map<String, String> params;
private Gson gson;
private Type clazz;
public PostUploadRequest(String url, List<ImageInfo> listItem,
Map<String, String> params,
Type type, ResponseListener listener) {
super(Method.POST, url, listener);
this.mListener = listener ;
this.params = params;
this.gson = new Gson();
this.clazz = type;
setShouldCache(false);
mListItem = listItem ;
//设置请求的响应事件,因为文件上传需要较长的时间,所以在这里加大了,设为5秒
setRetryPolicy(new DefaultRetryPolicy(5000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
}
/**
* 这里开始解析数据
* @param response Response from the network
* @return
*/
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String mString =
new String(response.data, HttpHeaderParser.parseCharset(response.headers));
Log.v(TAG, "mString = " + mString);
T result = gson.fromJson(StringUtils.FixJsonString(mString), clazz);
return Response.success(result,
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
/**
* 回调正确的数据
* @param response The parsed response returned by
*/
@Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
//重写getBody()方法,封装Post包
@Override
public byte[] getBody() throws AuthFailureError {
if (mListItem == null||mListItem.size() == 0){
return super.getBody() ;
}
ByteArrayOutputStream bos = new ByteArrayOutputStream() ;
if(!params.isEmpty()) {
StringBuilder sbParams = new StringBuilder();
for (Map.Entry<String, String> o : params.entrySet()) {
Map.Entry entry = (Map.Entry) o;
/*第一行*/
//`"--" + BOUNDARY + "\r\n"`
sbParams.append("--" + BOUNDARY);
sbParams.append("\r\n");
/*第二行*/
//Content-Disposition: form-data; name="参数的名称"; + 参数 + "\r\n"
sbParams.append("Content-Disposition: form-data;");
sbParams.append(" name=\"");
sbParams.append((String) entry.getKey());
sbParams.append("\"");
sbParams.append("\r\n");
sbParams.append("\r\n");
sbParams.append((String) entry.getValue());
sbParams.append("\r\n");
}
try {
bos.write(sbParams.toString().getBytes("utf-8"));
// bos.write("\r\n".getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
int N = mListItem.size() ;
ImageInfo imageInfo ;
for (int i = 0; i < N ;i++){
imageInfo = mListItem.get(i) ;
StringBuilder sb= new StringBuilder() ;
/*第一行*/
//`"--" + BOUNDARY + "\r\n"`
sb.append("--"+BOUNDARY);
sb.append("\r\n") ;
/*第二行*/
//Content-Disposition: form-data; name="参数的名称"; filename="上传的文件名" + "\r\n"
sb.append("Content-Disposition: form-data;");
sb.append(" name=\"");
sb.append(PARAM + "[" + Integer.toString(i) + "]"); //为了上传多张图片,使用uploadedfile[index]格式作为图片参数
sb.append("\"") ;
sb.append("; filename=\"") ;
sb.append(imageInfo.getFileName()) ;
sb.append("\"");
sb.append("\r\n") ;
/*第三行*/
//Content-Type: 文件的 mime 类型 + "\r\n"
sb.append("Content-Type: ");
sb.append(imageInfo.getMime()) ;
sb.append("\r\n") ;
/*第四行*/
//"\r\n"
sb.append("\r\n") ;
try {
bos.write(sb.toString().getBytes("utf-8"));
/*第五行*/
//文件的二进制数据 + "\r\n"
bos.write(imageInfo.getValue());
bos.write("\r\n".getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
/*结尾行*/
//`"--" + BOUNDARY + "--" + "\r\n"`
String endLine = "--" + BOUNDARY + "--" + "\r\n" ;
try {
bos.write(endLine.getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
// Log.v(TAG,"imageInfo =\n"+bos.toString()) ;
return bos.toByteArray();
}
//Content-Type: multipart/form-data; boundary=----------8888888888888
@Override
public String getBodyContentType() {
return MULTIPART_FORM_DATA+"; boundary="+BOUNDARY;
}
// @Override //注意一旦重写getBody()方法,则使用此方法添加参数无效。
// protected Map<String, String> getParams() throws AuthFailureError{
// return params;
// }
}
为了方便调用,封装Response接口如下:
import com.android.volley.Response;
public interface ResponseListener<T> extends Response.ErrorListener,Response.Listener<T> {
}
至此,对Volley+OkHttp+Gson的封装就完成了。在使用时,我们可以在自定义Application中初始化Queue,再封装一个专门的NetworkManager类来提供所有的网络访问操作,比如,在我最近的项目中是这样用的:
/**
* 网络管理类,封装网络操作接口
*/
public class NetworkManager {
/**
* 网络接口相关常量
*/
public static final String USER_USERNAME = "user_name";
public static final String USER_PASSWORD = "user_password";
public static final String USER_EMAIL = "user_email";
public static final String USER_ID = "user_id";
public static final String USER_WORK = "user_work";
public static final String USER_BIRTH = "user_birth";
public static final String USER_SIGN = "user_sign";
public static final String USER_LOCATION = "user_location";
public static final String USER_SEX = "user_sex";
public static final String TWEETS_CONTNET = "tweets_content";
public static final String FRIEND_ID = "friend_id";
public static final String SEND_USERID = "send_userid";
public static final String RECEIVE_USERID = "receive_userid";
public static final String MESSAGE_CONTENT = "message_content";
/**
* 服务器接口URL
*/
public static final String BASE_API_URL = "http://192.168.0.103:8088/youjoin-server/controllers/";
public static final String API_SIGN_IN = BASE_API_URL + "signin.php";
public static final String API_SIGN_UP = BASE_API_URL + "signup.php";
public static final String API_UPDATE_USERINFO = BASE_API_URL + "update_userinfo.php";
public static final String API_SEND_TWEET = BASE_API_URL + "send_tweet.php";
public static final String API_REQUEST_USERINFO = BASE_API_URL + "request_userinfo.php";
public static final String API_ADD_FRIEND = BASE_API_URL + "add_friend.php";
public static final String API_SEND_MESSAGE = BASE_API_URL + "send_message.php";
public static final String API_RECEIVE_MESSAGE = BASE_API_URL + "receive_message.php";
public static final String API_COMMENT_TWEET = BASE_API_URL + "comment_tweet.php";
public static final String API_UPVOTE_TWEET = BASE_API_URL + "upvote_tweet.php";
private static RequestQueue mRequestQueue ;
/**
* 发送动态接口
* @param listener ResponseListener
*/
public static void postSendTweet(String content, List<ImageInfo> images,
ResponseListener listener){
Map<String, String> params = new HashMap<>();
params.put(USER_ID, YouJoinApplication.getCurrUser().getId());
params.put(TWEETS_CONTNET, content);
Request request = new PostUploadRequest(API_SEND_TWEET, images, params,
new TypeToken<UpdateUserInfoResult>(){}.getType(), listener);
NetworkManager.getRequestQueue().add(request);
}
/**
* 发送私信接口
* @param receiveUserId 接收方用户id
* @param content 私信内容
* @param listener ResponseListener
*/
public static void postSendMessage(String receiveUserId, String content,
ResponseListener listener){
Map<String, String> params = new HashMap<>();
params.put(SEND_USERID, YouJoinApplication.getCurrUser().getId());
params.put(RECEIVE_USERID, receiveUserId);
params.put(MESSAGE_CONTENT, content);
Request request = new PostObjectRequest(
API_SEND_MESSAGE,
params, new TypeToken<ResultInfo>(){}.getType(),
listener);
NetworkManager.getRequestQueue().add(request);
}
/**
* 添加好友接口
* @param friendUserId 要添加的好友id
* @param listener ResponseListener
*/
public static void postAddFriend(String friendUserId,
ResponseListener listener){
Map<String, String> params = new HashMap<>();
params.put(USER_ID, YouJoinApplication.getCurrUser().getId());
params.put(FRIEND_ID, friendUserId);
Request request = new PostObjectRequest(
API_ADD_FRIEND,
params, new TypeToken<ResultInfo>(){}.getType(),
listener);
NetworkManager.getRequestQueue().add(request);
}
/**
* 个人资料请求(下载)接口
* @param userId 要获取的用户id
* @param listener ResponseListener
*/
public static void postRequestUserInfo(String userId, ResponseListener listener){
Map<String, String> params = new HashMap<>();
params.put(USER_ID, userId);
Request request = new PostObjectRequest(
API_REQUEST_USERINFO,
params,new TypeToken<UserInfo>(){}.getType(),
listener);
NetworkManager.getRequestQueue().add(request);
}
/**
* 个人资料更新(上传)接口
* @param userInfo 用户实体类
* @param picPath 头像的本地路径
* @param listener ResponseListener
*/
public static void postUpdateUserInfo(UserInfo userInfo, String picPath, ResponseListener listener){
if(userInfo.getId() == null) return;
List<ImageInfo> imageList = new ArrayList<>();
imageList.add(new ImageInfo(picPath));
Map<String, String> params = new HashMap<>();
params.put(USER_ID, userInfo.getId());
params.put(USER_WORK, userInfo.getWork());
params.put(USER_LOCATION, userInfo.getLocation());
params.put(USER_SEX, userInfo.getSex());
params.put(USER_BIRTH, userInfo.getBirth());
params.put(USER_SIGN, userInfo.getUsersign());
Request request = new PostUploadRequest(API_UPDATE_USERINFO, imageList, params,
new TypeToken<UpdateUserInfoResult>(){}.getType(), listener);
NetworkManager.getRequestQueue().add(request);
}
/**
* 登陆接口
* @param username 登录用户名
* @param password 登陆密码
* @param listener ResponseListener
*/
public static void postSignIn(String username, String password,
ResponseListener listener){
Map<String, String> param = new HashMap<>();
param.put(USER_USERNAME, username);
param.put(USER_PASSWORD, Md5Utils.getMd5(password));
Request request = new PostObjectRequest(
API_SIGN_IN,
param,
new TypeToken<UserInfo>(){}.getType(),
listener);
NetworkManager.getRequestQueue().add(request);
}
/**
* 注册接口
* @param username 注册用户名
* @param password 注册密码
* @param email 注册邮箱
* @param listener ResponseListener
*/
public static void postSignUp(String username, String password, String email,
ResponseListener listener){
Map<String, String> param = new HashMap<>();
param.put(USER_USERNAME, username);
param.put(USER_PASSWORD, Md5Utils.getMd5(password));
param.put(USER_EMAIL, email);
Request request = new PostObjectRequest(
API_SIGN_UP,
param,
new TypeToken<UserInfo>(){}.getType(),
listener);
NetworkManager.getRequestQueue().add(request);
}
/**初始化Volley 使用OkHttpStack
* @param context 用作初始化Volley RequestQueue
*/
public static synchronized void initialize(Context context){
if (mRequestQueue == null){
synchronized (NetworkManager.class){
if (mRequestQueue == null){
mRequestQueue =
Volley.newRequestQueue(context, new OkHttpStack(new OkHttpClient()));
}
}
}
mRequestQueue.start();
}
/**获取RequestQueue实例
* @return 返回RequestQueue实例
*/
public static RequestQueue getRequestQueue(){
if (mRequestQueue == null)
throw new RuntimeException("请先初始化mRequestQueue") ;
return mRequestQueue ;
}
}
import android.app.Application;
import android.content.Context;
import me.zq.youjoin.model.UserInfo;
import me.zq.youjoin.network.NetworkManager;
public class YouJoinApplication extends Application {
public static float sScale;
public static int sHeightPix;
private static Context context;
private static UserInfo currUser;
@Override
public void onCreate(){
super.onCreate();
context = getApplicationContext();
NetworkManager.initialize(context);
sScale = getResources().getDisplayMetrics().density;
sHeightPix = getResources().getDisplayMetrics().heightPixels;
}
public static Context getAppContext(){
return context;
}
public static UserInfo getCurrUser() {
return currUser;
}
public static void setCurrUser(UserInfo currUser) {
YouJoinApplication.currUser = currUser;
}
}
参考资料:
OkHttpStack.java -- from GitHub
Android Networking I: OkHttp, Volley and Gson
Android Volley完全解析(三),定制自己的Request
Android volley 解析(三)之文件上传篇
Android OkHttp完全解析 是时候来了解OkHttp了