OkHttp基本用法
URL和Uri
- 所屬的包不同。URI位置在java.net.URI,顯然是Java提供的一個(gè)類秽梅。而Uri位置在android.net.Uri,是由Android提供的一個(gè)類。所以初步可以判斷剿牺,Uri是URI的“擴(kuò)展”以適應(yīng)Android系統(tǒng)的需要。
- 作用的不同环壤。URI類代表了一個(gè)URI(這個(gè)URI不是類晒来,而是其本來的意義:通用資源標(biāo)志符——Uniform Resource Identifier)實(shí)例。官方文檔Uri類是一個(gè)不可改變的URI引用郑现,包括一個(gè)URI和一些碎片湃崩,碎片時(shí)跟在URI中“#”后面的部分。建立并且轉(zhuǎn)換URI引用接箫。出于對性能的考慮Uri類對無效的行為不敏感攒读,對于無效的輸入沒有定義相應(yīng)的行為,如果沒有另外制定辛友,它將返回垃圾而不是拋出一個(gè)異常薄扁。
綜上所述,Uri是Android開發(fā)的废累,擴(kuò)展了Java中URI的一些功能來特定的適用于Android開發(fā)邓梅。參考自Uri詳解之——Uri結(jié)構(gòu)與代碼提取
那什么時(shí)候需要用到java.net.URL呢。當(dāng)需要訪問某個(gè)網(wǎng)頁時(shí)邑滨,例如https://www.baidu.com日缨,這就是URL。這里有一篇值得閱讀的博客關(guān)于URL編碼
fragment掖看,用于聚焦到資源的某部分匣距。
OkHttp基礎(chǔ)用法
OkHttp是一款優(yōu)秀的HTTP框架,它支持get請求和post請求哎壳,支持基于Http的文件上傳和下載毅待,支持加載圖片,支持下載文件透明的GZIP壓縮耳峦,支持響應(yīng)緩存避免重復(fù)的網(wǎng)絡(luò)請求恩静,支持使用連接池來降低響應(yīng)延遲問題。
配置OkHttp
AndroidStudio可以通過從Maven下載jar包。在build.gradle(app)中構(gòu)建驶乾,
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okio:okio:1.11.0'
}
由于okhttp內(nèi)部依賴okio邑飒,所以同時(shí)導(dǎo)入okio。
關(guān)鍵類
OkHttpClient级乐,Request疙咸,RequestBody,Call风科,Callback撒轮,Response,ResponseBody
Http Get
//創(chuàng)建okHttpClient對象
OkHttpClient mOkHttpClient = new OkHttpClient();
//創(chuàng)建一個(gè)Request
final Request request = new Request.Builder()
.url("https://github.com/hongyangAndroid")
.build();
//new call
Call call = mOkHttpClient.newCall(request);
//請求加入調(diào)度
call.enqueue(new Callback()
{
@Override
public void onFailure(Request request, IOException e)
{
}
@Override
public void onResponse(final Response response) throws IOException
{
//String htmlStr = response.body().string();
}
});
代碼分析:
- 首先實(shí)例化一個(gè)OkHttpClient對象贼穆,OkHttp官方文檔并不建議我們創(chuàng)建多個(gè)OkHttpClient题山,因此全局使用一個(gè)。
- 創(chuàng)建一個(gè)請求(Request)故痊,可以通過RequestBuilder來設(shè)置參數(shù)顶瞳,例如header,method愕秫。但是至少有一個(gè)URL
- 通過request的對象去構(gòu)造得到一個(gè)Call對象慨菱,類似于將你的請求封裝成了任務(wù),既然是任務(wù)戴甩,就會(huì)有execute()和cancel()等方法符喝。
- 以異步的方式去執(zhí)行請求,所以我們調(diào)用的是call.enqueue甜孤,將call加入調(diào)度隊(duì)列协饲,然后等待任務(wù)執(zhí)行完成,我們在Callback中即可得到結(jié)果课蔬。
當(dāng)整個(gè)GET成功囱稽,我們就回調(diào)在onResponse()方法中的方法處理ResponseBody包含的數(shù)據(jù)。通過response.body()方法得到ResponseBody對象二跋。ResponseBody有幾種方式轉(zhuǎn)換返回的數(shù)據(jù)战惊,
- string(),獲得返回的字符串扎即,方法對于小文檔來說十分方便吞获、高效。但是如果響應(yīng)體太大(超過1MB)谚鄙,應(yīng)避免適應(yīng) string()方法 各拷,因?yàn)樗麜?huì)將把整個(gè)文檔加載到內(nèi)存中。
- btyes()闷营,返回二進(jìn)制字節(jié)數(shù)組烤黍。
- byteStream()知市,返回InputStream。
Call有一個(gè)線程阻塞方法速蕊,execute()嫂丙。可以直接調(diào)用這個(gè)方法返回一個(gè)Response规哲。
注意當(dāng)我們使用Call.execute()方法返回的Response跟啤,首先要進(jìn)行判斷是否成功。調(diào)用Response.isSuccessful()(Returns true if the code is in [200..300),這里的code指的是Http響應(yīng)消息的狀態(tài)碼)方法來判斷唉锌。
Http Post
關(guān)鍵類
MediaType隅肥,F(xiàn)ormEncodingBuilder
POST提交Json數(shù)據(jù)
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
f (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
}
使用Request的post方法來提交請求體RequestBody
POST提交鍵值對
很多時(shí)候我們會(huì)需要通過POST方式把鍵值對數(shù)據(jù)傳送到服務(wù)器。 OkHttp提供了很方便的方式來做這件事情袄简。
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody formBody = new FormEncodingBuilder()
.add("platform", "android")
.add("name", "bug")
.add("subject", "XXXXXXXXXXXXXXX")
.build();
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
}
實(shí)踐
圖片的下載
封裝OkHttp的GET訪問
public static void get(String url, Callback callback) {
URL requestURL = null;
try {
requestURL = new URL(Constant.BASE_URL + url);
} catch (MalformedURLException e) {
e.printStackTrace();
}
Request request = new Request.Builder()
.url(requestURL)
.build();
Call call = mClient.newCall(request);
call.enqueue(callback);
}
public static void getImage(String url, Callback callback) {
Request request = new Request.Builder()
.url(url)
.build();
Call call = mClient.newCall(request);
call.enqueue(callback);
}
調(diào)用封裝的訪問方法
HttpUtil.get(imageUrl, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
startActivity();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {
//獲取到真正圖片下載URL
JSONObject jsonObject = new JSONObject(response.body().string());
String imageUrl = jsonObject.getString("img");
loadImage(imageUrl, imageFile);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
下載圖片并保存
private void loadImage(String url, final File file) {
HttpUtil.getImage(url, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
startActivity();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
byte[] imageBytes = response.body().bytes();
//保存圖片到app私有文件中
saveImage(file, imageBytes);
startActivity();
}
});
}
總結(jié)腥放,這里主要思想就是利用ResponseBody.bytes()方法實(shí)現(xiàn)圖片的下載。
檢測網(wǎng)絡(luò)連接
既然App需要連接網(wǎng)絡(luò)來下載一些文件绿语,那么應(yīng)該在下載之前判斷用戶是否打開數(shù)據(jù)連接(蜂窩數(shù)據(jù)捉片,wifi等)。確保連接正常后再進(jìn)行網(wǎng)絡(luò)操作汞舱。
Internet權(quán)限在6.0中屬于安全權(quán)限,所以只需要在AndroidManifest.xml中申請權(quán)限就可以
獲取網(wǎng)絡(luò)狀態(tài)
獲取連接管理對象
// 獲取手機(jī)所有連接管理對象(包括對wi-fi,net等連接的管理)
Context context = activity.getApplicationContext();
ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
獲取NetworkInfo對象
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
判斷當(dāng)前連接是否可用
if(networkInfo != null) {
return networkInfo.isAvailable();
}
注意權(quán)限
由于需要訪問連接狀態(tài)宗雇,所以需要申請安全權(quán)限ACCESS_NETWORK_STATE昂芜。
問題
ConnectivityManager包含了所有的數(shù)據(jù)連接,wifi赔蒲,蜂窩數(shù)據(jù)泌神,藍(lán)牙...當(dāng)設(shè)備同時(shí)有很多數(shù)據(jù)連接保持連接狀態(tài)時(shí),怎么判斷某一個(gè)連接是否可用呢舞虱?
雜技
獲取屏幕的寬欢际,高像素
DisplayMetrics metrics = getResources().getDisplayMetrics();
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;