最近在一直在做的一個(gè)APK,以前的上傳和下載的都是使用別人封裝好的sdk,依懶性太強(qiáng)株搔,剛好最近有時(shí)間采缚,打算舍棄以前的sdk,使用OKHTTP來完成上傳和下載的工作淡溯。在此總結(jié)下自己的心得兵琳,在做這個(gè)功能的時(shí)候勃蜘,自己是一個(gè)小白硕噩,什么都不知道,現(xiàn)在總算是踉踉蹌蹌的把功能做完了缭贡,其實(shí)還是還是有一些地方不是很懂炉擅,但是還是打算將自己的過程大概總結(jié)下。很簡單阳惹,大神可以忽略谍失,哈哈
在此借鑒大神的博客,粗略的理解下okhttp的原理
Okhttp:是一款HTTP框架莹汤,它支持get請(qǐng)求和post請(qǐng)求快鱼,支持基于Http的文件上傳和下載,支持加載圖片纲岭,支持下載文件透明的GZIP壓縮抹竹,支持響應(yīng)緩存避免重復(fù)的網(wǎng)絡(luò)請(qǐng)求,支持使用連接池來降低響應(yīng)延遲問題止潮。
okhttp的簡單原理(如下兩幅圖的理解均為大神博客的參考):
okhttp在請(qǐng)求的時(shí)候會(huì)有一個(gè)engine窃判,這個(gè)engine就像是一個(gè)管理站,他控制著需要那種方式的請(qǐng)求喇闸,比如是異步還是同步袄琳。在connetion的時(shí)候,就是真正建立連接的時(shí)候燃乍,有自己的線程池機(jī)制唆樊,更選擇更優(yōu)化的處理方式。而真正達(dá)到服務(wù)端的時(shí)候刻蟹,會(huì)先經(jīng)過路由逗旁,路由其實(shí)就是一個(gè)注冊(cè)表(個(gè)人理解)是一套協(xié)議,比如代理座咆,IP地址等痢艺,選擇正確的協(xié)議去打開server的大門。下面是請(qǐng)求的流程:
1 ?將okhttp-2.7.5.jar ?okio-1.7.0.jar 放入lib底下介陶,同時(shí)在buid.gradle底下引入
2 開始步入正軌堤舒,
@ 1 加載證書
此方法最后返回一個(gè)SSLSocketFactory,目的:為了給okhttpClient.setSSLSocketFactory()設(shè)置
?@2 請(qǐng)求過程:
OkhttpClient client = new OkhttpClient();
client.setSSLSocketFactory(Util.initSSLSocketFactory(context));
RequestBody fromBody =new FormEncodingBuilder().add(string,value),主要是設(shè)置https的url的body
Request request =new Request.Builder().post(fromBody).url(testurl).build();
Call call = client.newCall(request);
call.enqueue(new okhttp.callback()){
? ? ? ?onfail()
? ? ? onresponse()
}
上面的代碼主要是傳一個(gè)url哺呜,得到服務(wù)器響應(yīng),然后返回json數(shù)據(jù)
假如我們需要向某一個(gè)url傳一個(gè)文件舌缤,這個(gè)時(shí)候應(yīng)該怎么做呢,這是我遇到的坑,在網(wǎng)上找好久的文章国撵,終于把問題解決了陵吸,在此給大家說一下
證書以及請(qǐng)求等過程都是一樣的,主要是body部分的區(qū)別:
MultipartBuilder builder =new MultipartBuilder().type(MultipartBuilder.FORM);
File file =new File(上傳文件的路徑);
RequestBody dbBody = RequestBody.create(MediaType.parse("text/plain"), file);
builder.addFormDataPart(string, value).addFormDataPart("filePath", file.getName(), dbBody);
RequestBody multipartBody = builder.build();
在開發(fā)這個(gè)小需求的時(shí)候介牙,還遇到一個(gè)問題壮虫,困擾了我很久,就是將上傳文件的進(jìn)度也要顯示出來环础,自己的做法如下
a:重寫requestBody(百度上有很多例子), b: 寫一個(gè)關(guān)于進(jìn)度的RequestProgressListener,主要是得到流后的回調(diào)
private Sinksink(Sink sink) {
return new ForwardingSink(sink) {
//當(dāng)前寫入字節(jié)數(shù)
? ? ? ? long bytesWritten =0L;
? ? ? ? //總字節(jié)長度囚似,避免多次調(diào)用contentLength()方法
? ? ? ? long contentLength =0L;
? ? ? ? @Override
? ? ? ? public void write(Buffer source, long byteCount)throws IOException {
super.write(source, byteCount);
? ? ? ? ? ? if (contentLength ==0) {
//獲得contentLength的值,后續(xù)不再調(diào)用
? ? ? ? ? ? ? ? contentLength = contentLength();
? ? ? ? ? ? }
//增加當(dāng)前寫入的字節(jié)數(shù)
? ? ? ? ? ? bytesWritten += byteCount;
? ? ? ? ? ? //回調(diào)
? ? ? ? ? ? mRequestProgressListener.onRequestProgress(bytesWritten, contentLength, bytesWritten ==contentLength);
? ? ? ? }
};
@3如果是需要進(jìn)度的話线得,下面這個(gè)步驟中需要有部分修改
將剛才重寫的CmlBody代替fromBody饶唤,同時(shí)傳入進(jìn)度的listener
Request request =new Request.Builder().post(fromBody).url(testurl).build();
MD5加密的理解(項(xiàng)目中有用到MD5加密,在此將自己的一點(diǎn)理解附上)
public static String digest(String content){
StringBuilder builder = new StringBuilder();
try {
MessageDigest msgDitest = MessageDigest.getInstance("MD5");
msgDitest.update(content.getBytes());
byte[] digests = msgDitest.digest();
builder.append(Integer.toHexString(digests[i] & 0xff ));