好久沒逛簡書了。這周公司的項目也已經愉快的迭代了新版本,對於之前一直存留的東西一直沒怎么梳理,今天想說說這兩年特別火的網絡框架。okhttp我想大部分Android開發者都不陌生,因為它的到來。是我們Android開發者的一個福音,像之前我們一直都在用volley網絡請求 、android-async-http、xUtils框架等等,他們都有自己的優勢,詳細使用我在這里就不一一介紹了,Github有很多這樣的Demo、畢竟咱今天主要說的是okhttp,相比於上面說的那些,okhttp的使用就更多具體,好用,在業界的口碑也是非常好。再加上Google已經在6.0版本里面刪除了HttpClient相關API,如果有些開發者還是想用的話只能自己手動添加jar包了。我覺得為了更好的在應對目前流行的網絡訪問,了解使用okhttp還是非常有必要的,開始進入正題:
- 在使用的時候,對於咱們Android Studio的用戶,先添加依賴庫:
compile 'com.squareup.okhttp:okhttp:2.7.0' compile 'com.squareup.okio:okio:1.7.0'
- 或者使用使用以下這個,這個結合Retrofit(retrofit就是對okhttp做了一層封裝。把網絡請求都交給給了Okhttp,我們只需要通過簡單的配置就能使用retrofit來進行網絡請求)使用會更靈活,下次有時間把這個可以做一遍文章寫出來。\
compile 'com.squareup.okhttp3:okhttp:3.2.0'
Get請求
在OKHttp中,每一次網絡請求就是一個Request,我們只要在Request里填寫我們需要的url,header等其他參數,再通過Request構造出Call,Call內部去請求參數,得到回復,並將返回調用者。即可
1.同步,異步請求
先聲明 OkHttpClient client = new OkHttpClient(); 然后在子線程去執行以下操作(因為android本身是不能在主線程做網絡請求操作的,這樣會阻塞UI線程因此我們需要自己開啟一個線程) Request request = new Request.Builder() .url("https://www.baidu.com/") .build(); Response response = client.newCall(request).execute(); if(response.isSuccessful()){ Log.i("MainActivity",response.code()); Log.i("MainActivity",response.body().string()); } }, - 異步請求的話改一丟丟就行了 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(Response response) throws IOException { //NOT UI Thread if(response.isSuccessful()){ Log.i("MainActivity",response.code()); Log.i("MainActivity",response.body().string()); } } }); 大致步驟就是這樣了
2.POST請求
在進行post請求的時候,我們一般都是需要添加參數和header,甚至有請求的id和key
· 傳入header Request request = new Request.Builder() .url("https://api.github.com/repos/square/okhttp/issues") .header("User-Agent", "OkHttp Headers.java") .addHeader("Accept", "application/json; q=0.5") .addHeader("Accept", "application/vnd.github.v3+json") .build(); · 使用RequestBody添加參數,類似表單提交 RequestBody formBody = new FormEncodingBuilder() .add("name", "zhangsan") .add("password", "123456") .add("subject", "subjectmit") .build(); Request request = new Request.Builder() .url(url) .post(body) .build(); · 在傳入header或者post參數都是傳到Request里,最后的調用方式也和上面的GET方式一樣 Response response = client.newCall(request) . if (response.isSuccessful()) { return response.body().string(); }else { throw new IOException("Unexpected code " + response); } · 上面是異步請求的方式,如果是異步的話execute()改成enqueue就行了
3.還有文件上傳下載,提交表達等操作,都在以下代碼中進行了簡單的封裝
package com.lukey.okhttp_demo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Looper; import com.squareup.okhttp.Callback; import com.squareup.okhttp.FormEncodingBuilder; import com.squareup.okhttp.MediaType; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; import org.json.JSONObject; import java.io.IOException; import java.util.Map; /** * creator Lukey on 2016/8/9 */ public class OKManager { private OkHttpClient mClient; private volatile static OKManager manager; private final String TAG = OKManager.class.getSimpleName(); private Handler mHandler; //提交Json數據 private static final MediaType JSON = MediaType.parse("application/json;charset=utf-8"); //提交字符串 private static final MediaType MEDIA_TYPE_MARKWODN = MediaType.parse("text/x-markdown;charset=utf-8"); public OKManager() { mClient = new OkHttpClient(); mHandler = new Handler(Looper.getMainLooper()); } //采用單例模式獲取對象 public static OKManager getInstance() { OKManager instance = null; if (manager == null) { synchronized (OKManager.class) { if (instance == null) { instance = new OKManager(); manager = instance; } } } return instance; } /** * 同步請求,在android開發中不常用,因為會阻塞UI線程 * @param url * @return */ private String syncGetByURL(String url) { //構建一個request請求 Request request = new Request.Builder().url(url).build(); Response response = null; try { response = mClient.newCall(request).execute(); //同步請求數據 if (response.isSuccessful()) { return response.body().string(); } } catch (Exception e) { e.printStackTrace(); } return null; } /** * 請求指定的URL返回的結果是json字符串 * * @param url * @param callBack */ public void asyncJsonStringByURL(String url, final Func1 callBack) { final Request request = new Request.Builder().url(url).build(); mClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { e.printStackTrace(); } @Override public void onResponse(Response response) throws IOException { if (response != null && response.isSuccessful()) { onSuccessJsonStringMethod(response.body().string(), callBack); } } }); } /** * 請求返回的json對象 * * @param url * @param callBack */ public void asyncJsonObjectByURL(String url, final Func4 callBack) { final Request request = new Request.Builder().url(url).build(); mClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { e.printStackTrace(); } @Override public void onResponse(Response response) throws IOException { if (response != null && response.isSuccessful()) { onSuccessJsonObjectMethod(request.body().toString(), callBack); } } }); } /** * 請求返回的字節對象 * * @param url * @param callBack */ public void asyncGetByteURL(String url, final Func2 callBack) { final Request request = new Request.Builder().url(url).build(); mClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { e.printStackTrace(); } @Override public void onResponse(Response response) throws IOException { if (response != null && response.isSuccessful()) { onSuccessByteMethod(response.body().bytes(), callBack); } } }); } /** * 請求返回的結果是一個imageview類型 bitmap類型 * * @param url * @param callBack */ public void asyncDownLoadIamgeByURL(String url, final Func3 callBack) { final Request request = new Request.Builder().url(url).build(); mClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { e.printStackTrace(); } @Override public void onResponse(Response response) throws IOException { if (response != null && response.isSuccessful()) { byte[] data = response.body().bytes(); Bitmap bitmap = new CropSquareTrans().transform(BitmapFactory.decodeByteArray(data, 0, data.length)); callBack.onResponse(bitmap); } } }); } /** * 模擬表單提交 * * @param url * @param params * @param callBack */ public void sendComplexForm(String url, Map<String, String> params, final Func4 callBack) { FormEncodingBuilder formEncodingBuilder = new FormEncodingBuilder(); //表單對象 if (params != null && !params.isEmpty()) { for (Map.Entry<String, String> entry : params.entrySet()) { formEncodingBuilder.add(entry.getKey(), entry.getValue()); } } RequestBody requestBody = formEncodingBuilder.build(); //采用post方式提交 Request request = new Request.Builder().url(url).post(requestBody).build(); mClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { e.printStackTrace(); } @Override public void onResponse(Response response) throws IOException { if (response != null && response.isSuccessful()) { onSuccessJsonObjectMethod(response.body().string(), callBack); } } }); } /** * 向服務器提交String請求 * * @param url * @param content * @param callBack */ public void sendStringByPostMethod(String url, String content, final Func4 callBack) { final Request request = new Request.Builder() .url(url).post(RequestBody.create(MEDIA_TYPE_MARKWODN, content)).build(); mClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { e.printStackTrace(); } @Override public void onResponse(Response response) throws IOException { if (request != null && response.isSuccessful()) { onSuccessJsonObjectMethod(response.body().string(), callBack); } } }); } /** * 請求返回的結果是json字符串 * * @param jsonValue * @param callBack */ private void onSuccessJsonStringMethod(final String jsonValue, final Func1 callBack) { mHandler.post(new Runnable() { @Override public void run() { if (callBack != null) { try { callBack.onResponse(jsonValue); } catch (Exception e) { e.printStackTrace(); } } } }); } /** * 返回響應的結果是json對象 * * @param jsonValue * @param callBack */ private void onSuccessJsonObjectMethod(final String jsonValue, final Func4 callBack) { mHandler.post(new Runnable() { @Override public void run() { if (callBack != null) { try { callBack.onResponse(new JSONObject(jsonValue)); } catch (Exception e) { e.printStackTrace(); } } } }); } /** * 返回響應的是byte[] 數組 * * @param data * @param callBack */ private void onSuccessByteMethod(final byte[] data, final Func2 callBack) { mHandler.post(new Runnable() { @Override public void run() { if (callBack != null) { callBack.onResponse(data); } } }); } // 定義四個接口,對外部調用 interface Func1 { void onResponse(String result); } interface Func2 { void onResponse(byte[] result); } interface Func3 { void onResponse(Bitmap bitmap); } interface Func4 { void onResponse(JSONObject jsonObject); } }
4.最后在補充一個緩存數據的代碼
· 先設置一個路徑 private static String savePath = Environment.getExternalStorageDirectory() .getAbsolutePath() + "/mydata/dataCash"; private static File mCashFile = new File(savePath); private static int mCacheSize = 20 * 1024 * 1024; private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (!ConnectionUtil.isConnection(LdApplication.getInstance())) { request = request.newBuilder() .cacheControl(CacheControl.FORCE_CACHE) .build(); } else { request = request.newBuilder() .cacheControl(CacheControl.FORCE_NETWORK) .build(); } Response originalResponse = chain.proceed(request); if (ConnectionUtil.isConnection(LdApplication.getInstance())) { //有網的時候讀接口上的@Headers里的配置,可以在這里進行統一的設置 String cacheControl = request.cacheControl().toString(); return originalResponse.newBuilder() .header("Cache-Control", cacheControl) .removeHeader("Pragma") .build(); } else { return originalResponse.newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale=2419200") .removeHeader("Pragma") .build(); } } }; · 以下設置持久化Cookie public static void setCookie() { mClient.setCookieHandler(new CookieManager( new PersistentCookieStore(MyApplication.getInstance()), CookiePolicy.ACCEPT_ALL)); } MyApplication.getInstance() ---->在Application用單例的方式實現
5.在主界面中調用
public class MainActivity extends AppCompatActivity { private Button mButton; private final static String TAG = MainActivity.class.getSimpleName(); private OKManager mOKManager; private String image_path = "http://pic.mmfile.net/thumbs/2016/06/66970_13a13_236.jpg"; private String json_path = "http://api.avatardata.cn/Weather/Query?key=d79f47b8dcb74eb78ea3d74b88876145&cityname=%E6%B7%B1%E5%9C%B3"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = (Button) this.findViewById(R.id.button); mOKManager = OKManager.getInstance(); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mOKManager.asyncJsonStringByURL(json_path, new OKManager.Func1() { @Override public void onResponse(String result) { Logger.json(result.toString()); Log.d(TAG,result); } }); }}); } } · 布局很簡單一個點擊按鈕和一個顯示文本 · 然后別忘了在配置文件中添加權限哦~~~~ <uses-permission android:name="android.permission.INTERNET"/>