Android應用層(網絡編程)四(okHttp使用解析)

Android Studio 配置gradle:

compile 'com.squareup.okhttp:okhttp:2.7.5'
compile 'com.squareup.okio:okio:1.7.0'

1. 異步Get請求

最簡單的Get請求,老規矩請求百度:

public void getAsynHttp(){
        OkHttpClient okHttpClient = new OkHttpClient();
        final com.squareup.okhttp.Request request= new com.squareup.okhttp.Request.Builder().url("http://baidu.com").build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(com.squareup.okhttp.Request request, IOException e) {

            }

            @Override
            public void onResponse(com.squareup.okhttp.Response response) throws IOException {
                String str = response.body().string();
                Log.i("zsj", str);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplicationContext(), "請求成功", Toast.LENGTH_LONG).show();
                    }
                });
            }
        });
    }

值得關注的是,onRespsonse回調並不是UI線程

2. 同步GET請求

public String getSyncHttp() throws IOException{
        OkHttpClient okHttpClient = new OkHttpClient();
        final com.squareup.okhttp.Request request = new com.squareup.okhttp.Request.Builder().url("http://baidu.com").build();
        Call call = okHttpClient.newCall(request);
        com.squareup.okhttp.Response mResponse = call.execute();
        if (mResponse.isSuccessful()){
            return mResponse.body().string();
        }
        else{
            throw new IOException("Unexpected code" + mResponse);
        }
    }

同步Get請求和異步調用區別就是調用了call的execute()方法

3. 異步POST請求

public void postAsynHttp(){
        OkHttpClient okHttpClient = new OkHttpClient();

        com.squareup.okhttp.RequestBody fromBody = new FormEncodingBuilder().add("size", "10").build();
        com.squareup.okhttp.Request request = new com.squareup.okhttp.Request.Builder().url("http://39.108.135.114:8001/ZRobot/function/getAppResponce").post(fromBody).build();

        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(com.squareup.okhttp.Request request, IOException e) {

            }

            @Override
            public void onResponse(com.squareup.okhttp.Response response) throws IOException {
                final String str = response.body().string();
                Log.i("zsj", str);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplicationContext(), str, Toast.LENGTH_LONG).show();
                    }
                });
            }
        });
    }
  • post與get不同的就是要要創建RequestBody並傳進Request中
  • 同樣,其回調不在UI線程

4. 請求緩存設置

全局用戶唯一的緩存訪問實例,okhttp框架全局必須只有一個OkHttpClient實例(new OkHttpClient()),並在第一次創建實例的時候,配置好緩存。

Step 1 : 設置緩存路徑和大小,並設置給okHttpClient:(okHttpClient需要是一個全局的實例)

okHttpClient = new OkHttpClient();
File sdcache = getExternalCacheDir();
int cacheSize = 10*1024*1024;
okHttpClient.setCache(new Cache(sdcache.getAbsoluteFile(), cacheSize));

Step 2 : 異步請求

public void getAsynHttpCache(){
        final com.squareup.okhttp.Request request = new com.squareup.okhttp.Request.Builder().url("http://www.baidu.com").build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(com.squareup.okhttp.Request request, IOException e) {

            }

            @Override
            public void onResponse(com.squareup.okhttp.Response response) throws IOException {
                if(response.cacheResponse() != null){
                    String str = response.cacheResponse().toString();
                    Log.i("zsj", "cache--" + str);
                }
                else{
                    response.body().string();
                    String str = response.networkResponse().toString();
                    Log.i("zsj", "net--" + str);
                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplicationContext(), "緩存post請求成功", Toast.LENGTH_LONG).show();
                    }
                });
            }
        });

    }

5. 設置超時時間

mOkHttpClient = new OkHttpClient();
mOkHttpClient.setConnectTimeout(15, TimeUnit.SECONDS);
mOkHttpClient.setWriteTimeout(20, TimeUnit.SECONDS);
mOkHttpClient.setReadTimeout(20, TimeUnit.SECONDS);

6. 取消請求

  • 使用call.cancel()可以立即停止掉一個正在執行的call。如果一個線程正在寫請求或者讀響應,將會引發IOException。當用戶離開一個應用時或者跳到其他界面時,使用Call.cancel()可以節約網絡資源,另外不管同步還是異步的call都可以取消。
  • 也可以通過tags來同時取消多個請求。當你構建一請求時,使用RequestBuilder.tag(tag)來分配一個標籤。之後你就可以用OkHttpClient.cancel(tag)來取消所有帶有這個tag的call。

Step 1 : 爲了模擬場景,創建一個定時的線程池

private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

Step 2 : 實現取消請求

private  void cancel(){
       final Request request = new Request.Builder()
               .url("http://www.baidu.com")
               .cacheControl(CacheControl.FORCE_NETWORK)
               .build();
       Call call=null;
       call = mOkHttpClient.newCall(request);
       final Call finalCall = call;
       //100毫秒後取消call
       executor.schedule(new Runnable() {
           @Override public void run() {
               finalCall.cancel();
           }
       }, 100, TimeUnit.MILLISECONDS);
       call.enqueue(new Callback() {
           @Override
           public void onFailure(Request request, IOException e) {
           }
           @Override
           public void onResponse(final Response response) {
               if (null != response.cacheResponse()) {
                   String str = response.cacheResponse().toString();
                   Log.i("wangshu", "cache---" + str);
               } else {
                   try {
                       response.body().string();
                   } catch (IOException e) {
                       Log.i("wangshu", "IOException");
                       e.printStackTrace();
                   }
                   String str = response.networkResponse().toString();
                   Log.i("wangshu", "network---" + str);
               }
           }
       });
          Log.i("wangshu", "是否取消成功"+call.isCanceled());
   }

7. 關於封裝

OkHttpFinal是一個很不錯的選擇

oKHttp 2.x和3.x的注意內容

1. OkHttp3異步POST請求沒有FormEncodingBuilder類,替代它的是功能更加強大的FormBody

private void postAsynHttp() {
     mOkHttpClient=new OkHttpClient();
     RequestBody formBody = new FormBody.Builder()
             .add("size", "10")
             .build();
     Request request = new Request.Builder()
             .url("http://api.1-blog.com/biz/bizserver/article/list.do")
             .post(formBody)
             .build();
     Call call = mOkHttpClient.newCall(request);
     call.enqueue(new Callback() {
         @Override
         public void onFailure(Call call, IOException e) {
         }
         @Override
         public void onResponse(Call call, Response response) throws IOException {
             String str = response.body().string();
             Log.i("zsj", str);
             runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
                     Toast.makeText(getApplicationContext(), "請求成功", Toast.LENGTH_SHORT).show();
                 }
             });
         }
     });
 }

2. OkHttp3不能通過OkHttpClient直接設置超時時間和緩存,而是通過OkHttpClient.Builder來設置

  • 通過builder配置好OkHttpClient後用builder.build()來返回OkHttpClient,所以我們通常不會調用new OkHttpClient()來得到OkHttpClient,而是通過builder.build():
File sdcache = getExternalCacheDir();
int cacheSize = 10 * 1024 * 1024;
OkHttpClient.Builder builder = new OkHttpClient.Builder()
        .connectTimeout(15, TimeUnit.SECONDS)
        .writeTimeout(20, TimeUnit.SECONDS)
        .readTimeout(20, TimeUnit.SECONDS)
        .cache(new Cache(sdcache.getAbsoluteFile(), cacheSize));
OkHttpClient mOkHttpClient=builder.build();

補全okHttp的用法

1.異步上傳文件

  • 上傳文件本身是一個Post請求

Step 1 : 定義上傳文件類型

public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");

Setp 2 : 將根目錄中的zhongshijie.txt文件上傳到服務器

private void postAsynFile() {
    mOkHttpClient=new OkHttpClient();
    File file = new File("/sdcard/zhongshijie.txt");
    Request request = new Request.Builder()
            .url("https://api.github.com/markdown/raw")
            .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
            .build();
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.i("zsj",response.body().string());
            }
        });
    }

文件權限需要加上

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

2. 異步下載文件

private void downAsynFile() {
     mOkHttpClient = new OkHttpClient();
     String url = "http://img.my.csdn.net/uploads/201603/26/1458988468_5804.jpg";
     Request request = new Request.Builder().url(url).build();
     mOkHttpClient.newCall(request).enqueue(new Callback() {
         @Override
         public void onFailure(Call call, IOException e) {
         }
         @Override
         public void onResponse(Call call, Response response) {
             InputStream inputStream = response.body().byteStream();
             FileOutputStream fileOutputStream = null;
             try {
                 fileOutputStream = new FileOutputStream(new File("/sdcard/wangshu.jpg"));
                 byte[] buffer = new byte[2048];
                 int len = 0;
                 while ((len = inputStream.read(buffer)) != -1) {
                     fileOutputStream.write(buffer, 0, len);
                 }
                 fileOutputStream.flush();
             } catch (IOException e) {
                 Log.i("zsj", "IOException");
                 e.printStackTrace();
            }
            Log.d("zsj", "文件下載成功");
        }
    });
}

3. 異步上傳Multipart文件

這種場景很常用,我們有時會上傳文件同時還需要傳其他類型的字段,OkHttp3實現起來很簡單,需要注意的是沒有服務器接收我這個Multipart文件,所以這裏只是舉個例子,具體的應用還要結合實際工作中對應的服務器。

首先定義上傳文件類型:

private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
private void sendMultipart(){
    mOkHttpClient = new OkHttpClient();
    RequestBody requestBody = new MultipartBody.Builder()
            .setType(MultipartBody.FORM)
            .addFormDataPart("title", "wangshu")
            .addFormDataPart("image", "wangshu.jpg",
                    RequestBody.create(MEDIA_TYPE_PNG, new File("/sdcard/wangshu.jpg")))
            .build();
    Request request = new Request.Builder()
            .header("Authorization", "Client-ID " + "...")
            .url("https://api.imgur.com/3/image")
            .post(requestBody)
            .build();
   mOkHttpClient.newCall(request).enqueue(new Callback() {
       @Override
       public void onFailure(Call call, IOException e) {
       }
       @Override
       public void onResponse(Call call, Response response) throws IOException {
           Log.i("wangshu", response.body().string());
       }
   });
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章