网络连接这块有安卓原生的工具:HttpClient和HttpURLConnection
由于HttpURLConnection使用是需要大量的写一些重复的代码,所以没有自己封装的话,需要填写太多多余的代码
之后接触到了OkHttp,新的连接工具,简便了许多而且使用了链式代码结构,方便了理解和编程。
我碰到的时候,已经是OkHttp3.4.2的版本了。那么我就用这个版本结合官方的代码来记录一下使用过程吧!
1.同步和异步的区别
由于安卓主线程是不允许做网络连接的。
同步是在一个线程下面执行代码,由于安卓主线程不允许,所以需要开辟新线程
异步是在新建了一个线程当结果完成后返回结果给线程,告诉线程完成了操作,所以可以直接写在主线程上面。
下面是一个简单的get请求连接操作
首先是同步
public void get() throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.get() //默认get方式 可省略不写
.url("https://www.baidu.com/")
.build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()){
Log.e("get","成功");
}else{
Log.e("get","失败");
}
}
需要使用的话需要在主线程上面开辟新线程
new Thread(new Runnable() {
@Override
public void run() {
try {
get();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
再次是异步
public void get2(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.get() //默认get方式 可省略不写
.url("https://www.baidu.com/")
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("get","失败");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("get","成功");
}
});
}
使用的话 直接在主线程
get2();
就可以执行的
2.POST
get方式在上面也说了个简单的例子,也可以理解get请求的使用了。
下面来说下post请求的使用吧!
先来一个简单的post请求,这边我就用官方例子的网址
post一个String给网址
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
public void post(){
OkHttpClient client = new OkHttpClient();
String string = ""
+ "Releases\n"
+ "--------\n"
+ "\n"
+ " * _1.0_ May 6, 2013\n"
+ " * _1.1_ June 15, 2013\n"
+ " * _1.2_ August 11, 2013\n";
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN,string))
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("post","失败");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("post","成功");
Log.e("post", "body: \n" + response.body().string());
}
});
}
下面是执行之后的结果打印
这边来理解一下
post是如何传参的
因为都知道get请求传参需要拼接url例如http://www.baidu.com/lz?name=xx&pwd=yy 这样
而post只需要把name和pwd放到传参的Map里面(一般都是键值对用Map保存)
OkHttp的传参是新建了一个RequestBody来存放参数
假如我们需要在网址中传入name和pwd的参数和值就是如下写法
FormBody.Builder builder = new FormBody.Builder();
builder.add("name","xx");
builder.add("pwd","yy");
RequestBody fromBody = builder.build();
新建好RequestBody之后在构建request请求的时候吧他附加上去
Request request = new Request.Builder()
.url(url)
.post(fromBody)
.build();
这样就执行完成了post传参的构建,之后就可以。
上面post长传一个String其实也是构建了一个RequestBody
就是在
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN,string))
实际就是构建了一个key为MEDIA_TYPE_MARKDOWN,value为string的RequestBody
然后post上去
那么其他的post也可以很好的理解了
如果要post一个文件就是
File file = new File("README.md");
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
.build();
postStream流的话需要重新构建下RequestBody
RequestBody requestBody = new RequestBody() {
@Override
public MediaType contentType() {
return MEDIA_TYPE_MARKDOWN;
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("Stream\n");
}
};
使用也是构建请求request
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(requestBody)
.build();
在来是post表单
官方解释是
使用FormBody.Builder建立一个请求体,它就像一个HTML 的标记。Names 和values将使用HTML兼容的表单URL编码进行编码。
那么看下使用吧
RequestBody formBody = new FormBody.Builder()
.add("search","Jurassic Park")
.build();
Request request = new Request.Builder()
.url("https://en.wikipedia.org/w/index.php")
.post(formBody)
.build();
结果就是获取到了搜索Jurassic Park这个网页的整个内容
差不多post的相关功能也说的差不多了。下面来看下请求之后从网址下来的数据吧!
3.请求获取的数据
下面我就只写了request的构建
其他代码其实和上面重复的是一样
先构建一个OkHttpClient对象
然后构建request请求
在使用OkHttpClient对象执行newCall方法
之后看是异步还是同步使用enqueue或者execute
这边用官方的网址
Request request = new Request.Builder()
.url("https://www.publicobject.com/helloworld.txt")
.build();
结果如下
看下在获取返回结果的代码吧
Log.e("GetAsyn", "body: \n" + response.body().string());
就是打印了response身体
这个body就是网页显示的内容的整个body
那么获取网页的报头呢
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.e("GetAsyn", headers.name(i) + ": " + headers.value(i));
}
结果如下
也可以特定的获取报头
例如 response.header("Server") 就只会获取报头中名字是Server的报头值
下面稍微说下有用到的一些东西吧
返回的response的说明
response.code()是服务器响应码
response.headers()是报头
response.body()是网页的body
然后body里面有一些属性
response.body().byteStream() 返回的就是InputStream
这个就是is流了 其他操作都是和原来的操作差不多了
response.body().contentLength() 返回的long
这个是获取的is流长度了
其他还有一些因为没怎么用到 就没得复述了!
获取Gson
因为和服务器交互一般都是JSON,然后谷歌开源的Gson可以很好的解析和构建
所以OkHttp就有这个例子
先来看下官方的一些注意:
需要注意的是ResponseBody.charStream()使用的Content-Type响应头进行解码时,所使用的字符集默认为UTF-8 。
先来看下官方的例子
private final OkHttpClient client = new OkHttpClient();
private final Gson gson = new Gson();
public void run() throws Exception {
Request request = new Request.Builder()
.url("https://api.github.com/gists/c2a7c39532239ff261be")
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Gist gist = gson.fromJson(response.body().charStream(), Gist.class);
for (Map.Entry<String, GistFile> entry : gist.files.entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue().content);
}
}
static class Gist {
Map<String, GistFile> files;
}
static class GistFile {
String content;
}
我写好后执行结果如下
图案就不发全了 就是上面get例子里面的那个图
结语
至此一些OkHttp的常用就算是完成了。
下载上传之类的我就放在下里面讲吧!
其实知道了Is流和post的传参机制 其实 下载和上传其实就是以前的写法罢了!