okhttp get/post基本用法
okhttp upload/download 上传和下载
对应的项目下载地址:NetFramework
全部单例模式创建方式:单例模式 例子中用到了静态内部类创建单例,对此不了解的可以参考这篇
前两篇文章实践了使用okhttp3.0进行简单的网络交互、获取网络资源等操作,但是可以预料代码会有冗余的情况,我们可以写的更加优雅一点,例子中只是个别的网络请求,实际上我们在做项目的时候会有大量的网络请求,因此我们需要更加简单的使用方式,因此必要的封装是一定的,下面将简单的就okhttp3.0的部分使用做一个简单的封装。网络上已经有了可供使用开源库,本着不重复造轮子的思想,我们其实可以直接使用,但是了解封装的简单思路,了解开源库的封装逻辑还是十分有必要的。
下面是截取前面章节使用的例子,在fragment中有两个按钮,分别进行get和post请求网络数据,获取到的是一串json格式的字符串,我们将这个获取的结果显示在ui空间text上,如此下图:
下面是demo代码:
1、封装前使用okhttp经行网络实践
public class NewOkHttpFragment extends Fragment implements View.OnClickListener {
private static final String TAG = "OkHttpFragment";
private TextView resultView;
private Button getView;
private Button postView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_okhttp, container, false);
getView = (Button) view.findViewById(R.id.id_http_get_button);
postView = (Button) view.findViewById(R.id.id_http_post_button);
resultView = (TextView) view.findViewById(R.id.id_result_okhttp_view);
initListener();
return view;
}
private void initListener() {
getView.setOnClickListener(this);
postView.setOnClickListener(this);
}
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
if (msg.obj == null) {
resultView.setText("null");
} else {
resultView.setText("error:" + msg.obj.toString());
}
break;
case 1:
if (msg.obj == null) {
resultView.setText("null");
} else {
resultView.setText("response:" + msg.obj.toString());
}
break;
}
}
};
/**
* 测试okhttp的get方法
*/
private void testOkhttpGet() {
String url = "http://api.k780.com/?app=weather.history";
OkHttpClient okHttpClient = new OkHttpClient();
okhttp3.Request request = new okhttp3.Request.Builder().url(url).get().build();//.get()可以不要,Builder的默认构造方法里面就是get请求
final Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Message message = Message.obtain();
message.what = 0;
message.obj = e.getMessage();
mHandler.sendMessage(message);
Log.d(TAG, "onFailure: " + message.obj.toString());
}
@Override
public void onResponse(Call call, okhttp3.Response response) throws IOException {
Message message = Message.obtain();
message.what = 1;
message.obj = response.body().string();//string不能调用两次 被调用一次就关闭了,这里调用两次会报异常
mHandler.sendMessage(message);
Log.d(TAG, "response: " + message.obj.toString());
}
});
}
/**
* 测试okhttp的post方法
*/
private void testOkhttpPost() {
String url = "http://api.k780.com/?app=weather.history";//
// &weaid=1&date=2018-08-13&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json";
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("weaid", "1")
.add("date", "2018-08-13")
.add("appkey", "10003")
.add("sign", "b59bc3ef6191eb9f747dd4e83c99f2a4")
.add("format", "json")
.build();
okhttp3.Request request = new okhttp3.Request.Builder()
.url(url)
.post(body)
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Message message = Message.obtain();
message.what = 0;
message.obj = e.getMessage();
mHandler.sendMessage(message);
Log.d(TAG, "response: " + message.obj.toString());
}
@Override
public void onResponse(Call call, okhttp3.Response response) throws IOException {
Message message = Message.obtain();
message.what = 1;
message.obj = response.body().string();//string不能调用两次 被调用一次就关闭了,这里调用两次会报异常
mHandler.sendMessage(message);
Log.d(TAG, "response: " + message.obj.toString());
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.id_http_get_button:
testOkhttpGet();
break;
case R.id.id_http_post_button:
testOkhttpPost();
break;
}
}
}
然后我们进行简单的封装,封装前我们需要了解okhttp基本使用没提到的两个知识点
1)设置缓存以及超时
/**
* 设置超时和缓存
*/
private void settings(Context context) {
File cacheDir = context.getExternalCacheDir().getAbsoluteFile();//缓存目录
int cacheSize = 30 * 1024 * 1024;//缓存大小
OkHttpClient.Builder builder = new OkHttpClient.Builder();
//注意这里本来是可以采用链式调用的
builder.connectTimeout(15, TimeUnit.SECONDS);//设置连接超时15s
builder.readTimeout(15, TimeUnit.SECONDS);//设置读取超时15s
builder.writeTimeout(15, TimeUnit.SECONDS);//设置写入超时15s
builder.cache(new Cache(cacheDir, cacheSize));
builder.build();
}
2)网络请求的cancle
public void cancelWithTag(OkHttpClient client, Object tag) {
if (client == null || tag == null) return;
for (Call call : client.dispatcher().queuedCalls()) {
if (tag.equals(call.request().tag())) {
call.cancel();
}
}
for (Call call : client.dispatcher().runningCalls()) {
if (tag.equals(call.request().tag())) {
call.cancel();
}
}
}
public void cancelAll(OkHttpClient client) {
if (client == null) {
return;
}
for (Call call : client.dispatcher().runningCalls()) {
call.cancel();
}
for (Call call : client.dispatcher().queuedCalls()) {
call.cancel();
}
}
2、封装后
/**
* Created by wwxd on 2018/8/29.
*/
public interface ResponseCallBack {
public void onFailure(Throwable e);
public void onSuccess(Response response);
}
public class OKHttpManager {
public static final String TAG = "OKHttpManager";
public static final long DEFAULT_TIMEOUT = 60; //默认的超时时间,单位:秒
private Handler mHandler;
private OkHttpClient okHttpClient;
private static volatile OKHttpManager mInstance;//注意这里的使用volatile修饰变量,
private ResponseCallBack callBack;
private OKHttpManager() {
mHandler = new Handler(Looper.getMainLooper());
okHttpClient = settings();
}
/**
* 使用静态内部类的机制,构造单例
*
* @return OKHttpManager
*/
public static OKHttpManager getInstance() {
return OKHttpManagerHolder.okHttpManager;
}
public static class OKHttpManagerHolder {
private static OKHttpManager okHttpManager = new OKHttpManager();
}
/**
* 设置超时
*/
private OkHttpClient settings() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
//注意这里本来是可以采用链式调用的
builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
builder.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
builder.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
return builder.build();
}
public void doGet(String url, ResponseCallBack callBack) {
this.callBack = callBack;
Request request = new Request.Builder().url(url).get().build();
execute(request);
}
public void doPost(String url, RequestBody body, ResponseCallBack callBack) {
this.callBack = callBack;
okhttp3.Request request = new okhttp3.Request.Builder()
.tag(url.hashCode())//通过访问url的hashcode打标签
.url(url)
.post(body)
.build();
execute(request);
}
private void execute(final Request request) {
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {
callBack.onFailure(e);
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
//注意这里的string()方法只能被调用一次,否者后面会报错,因为流已经被关闭,所以这里注释掉日志
// Log.d(TAG,response.body().string());
callBack.onSuccess(response);
}
});
}
public Handler getHandler() {
return mHandler;
}
public void runOnUIThread(Runnable runnable) {
mHandler.post(runnable);
}
public void cancelWithTag(OkHttpClient client, Object tag) {
if (client == null || tag == null) return;
for (Call call : client.dispatcher().queuedCalls()) {
if (tag.equals(call.request().tag())) {
call.cancel();
}
}
for (Call call : client.dispatcher().runningCalls()) {
if (tag.equals(call.request().tag())) {
call.cancel();
}
}
}
public void cancelAll(OkHttpClient client) {
if (client == null) {
return;
}
for (Call call : client.dispatcher().runningCalls()) {
call.cancel();
}
for (Call call : client.dispatcher().queuedCalls()) {
call.cancel();
}
}
}
public class NewOkHttpFragment extends Fragment implements View.OnClickListener {
private static final String TAG = "NewOkHttpFragment";
private TextView resultView;
private Button getView;
private Button postView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_okhttp_new, container, false);
getView = (Button) view.findViewById(R.id.id_http_get_button);
postView = (Button) view.findViewById(R.id.id_http_post_button);
resultView = (TextView) view.findViewById(R.id.id_result_okhttp_view);
initListener();
return view;
}
private void initListener() {
getView.setOnClickListener(this);
postView.setOnClickListener(this);
}
/**
* 测试okhttp的get方法
*/
private void testOkhttpGet() {
String url = "http://api.k780.com/?app=weather.history";
OKHttpManager.getInstance().doGet(url, new ResponseCallBack() {
@Override
public void onFailure(Throwable e) {
showResult(e.getMessage());
}
@Override
public void onSuccess(Response response) {
try {
showResult(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
/**
* 测试okhttp的post方法
*/
private void testOkhttpPost() {
String url = "http://api.k780.com/?app=weather.history";
RequestBody body = new FormBody.Builder()
.add("weaid", "1")
.add("date", "2018-08-13")
.add("appkey", "10003")
.add("sign", "b59bc3ef6191eb9f747dd4e83c99f2a4")
.add("format", "json")
.build();
OKHttpManager.getInstance().doPost(url, body, new ResponseCallBack() {
@Override
public void onFailure(Throwable e) {
showResult(e.getMessage());
}
@Override
public void onSuccess(Response response) {
try {
showResult(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
private void showResult(final String content) {
OKHttpManager.getInstance().runOnUIThread(new Runnable() {
@Override
public void run() {
if (resultView != null) {
if (TextUtils.isEmpty(content)) {
resultView.setText("null");
} else {
resultView.setText(content);
}
}
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.id_http_get_button:
testOkhttpGet();
break;
case R.id.id_http_post_button:
testOkhttpPost();
break;
}
}
}
上面仅仅是简单的封装,仅仅只是抛砖引玉,有很多优秀的开源的封装,如:okgo 作者写的特别好,界面如下: