初識okHttp

參考文章:
http://blog.csdn.net/lmj623565791/article/details/47911083

  • okHttp提供的方法有以下幾點(從上述文章中摘抄而來):
  • 一般的get請求
  • 一般的post請求
  • 基於Http的文件上傳
  • 文件下載
  • 加載圖片
  • 支持請求回調,直接返回對象、對象集合
  • 支持session的保持

1. get請求

//創建okHttpClient對象
OkHttpClient mOkHttpClient = new OkHttpClient();
//創建一個Request
final Request request = new Request.Builder()
                .url("https://github.com/hongyangAndroid")
                .build();
//new call
Call call = mOkHttpClient.newCall(request); 
//請求加入調度
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();
                    //調用主線程更新UI,mainHandler是Activity的變量,直接拷貝代碼會報錯,後面會提供demo下載
                    mainHandler.post(new Runnable(){
                         public void run() {
                            ImageView view5 = findView(R.id.imageview2);
                            view5.setImageBitmap(ImageUtils.getLoacalBitmap(abstractPath));
                            TextView view1 = findView(R.id.result5);
                            view1.setText("存儲位置:"+abstractPath);
                        }
                    });
            }
        });             


異步執行的是:
call.enqueue(new Callback() {//方法實現});

同步請求:我在UI主線程直接調用同步請求時候報錯了,而在子線程中執行同步請求時成功了,這裏沒太搞明白。突然想到,我是測試時是在onCreate中直接調用同步GET請求,有可能是請求返回了,接着就要更新UI,而這時還沒有出onCreate方法,渲染尚未完成,更新UI就這樣報錯了,不知道是否正確,待後面驗證。

 Response mResponse = call.execute();

2.POST請求

Request request = buildMultipartFormRequest(
        url, new File[]{file}, new String[]{fileKey}, null);
FormEncodingBuilder builder = new FormEncodingBuilder();   
builder.add("username","張三");

Request request = new Request.Builder().url(url).post(builder.build()).build();
 mOkHttpClient.newCall(request).enqueue(new Callback(){
    @Override
            public void onFailure(Request request, IOException e) {
               //返回主線程提示失敗信息
            }

            @Override
            public void onResponse(Response response) throws IOException {
                //同get請求返回處理方式
            }
 });

與get請求區別就是需要添加額外參數
FormEncodingBuilder builder = new FormEncodingBuilder();   
builder.add("username","張三");
Request request = new Request.Builder().url(url).post(builder.build()).build();

3. 文件上傳

文件上傳使用與POST請求類似,只是POST的參數形式不一樣而已。

File file = new File(Environment.getExternalStorageDirectory(), "balabala.mp4");

RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);

RequestBody requestBody = new MultipartBuilder()
     .type(MultipartBuilder.FORM)
     .addPart(Headers.of("Content-Disposition", "form-data; name=\"username\""), 
          RequestBody.create(null, "李四"))
     .addPart(Headers.of("Content-Disposition", "form-data; name=\"mFile\"; 
         filename=\"wjd.mp4\""), fileBody)
     .build();

Request request = new Request.Builder()
                    .url("http://192.168.1.100:8080/okHttpDemo/fileUpload") 
                    .post(requestBody)
                    .build();

Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback(){
        @Override
            public void onFailure(Request request, IOException e) {
               //
            }

            @Override
            public void onResponse(Response response) throws IOException {
                //
            }
});

4. 文件下載

文件下載實際就是直接訪問文件網絡地址,,返回後從Response拿到數據流程,保存本地即可。

final Request request = new Request.Builder().url(url).build();
        final Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(final Request request, final IOException e) {
                currentActivity.httpError(url, new HashMap());
            }

            @Override
            public void onResponse(Response response) {
                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;
                try {
                    //拿到數據流程
                    is = response.body().byteStream();
                    //根據指定的存放位置創建文件,用以保存下載的文件
                    File file = new File(destFileDir, getFileName(url));
                    //建立輸出流
                    fos = new FileOutputStream(file);
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                    }
                    fos.flush();
                    Map params = new HashMap<>();
                    //currentActivity是調用方法傳過來的當前UI所在界面。
                    currentActivity.completeDownload(file.getAbsolutePath());
                } catch (IOException e) {
                    e.printStackTrace();
                    currentActivity.httpError(url, new HashMap(), e);
                } finally {
                    try {
                        if (is != null) is.close();
                    } catch (IOException e) {
                    }
                    try {
                        if (fos != null) fos.close();
                    } catch (IOException e) {
                    }
                }

            }
        });

5. 展示網絡圖片

和文件下載原理一樣的,拿到數據流後,直接創建Bitmap,顯示到指定ImageView即可。

 public void displayImage(final Handler mHandler, final ImageView view, final String imgUrl, final int errorResId) {
        final Request request = new Request.Builder().url(imgUrl).build();
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        view.setImageResource(errorResId);
                    }
                });
            }

            @Override
            public void onResponse(Response response) {
                InputStream is = null;
                try {
                    is = response.body().byteStream();
                    ImageUtils.ImageSize actualImageSize = ImageUtils.getImageSize(is);
                    ImageUtils.ImageSize imageViewSize = ImageUtils.getImageViewSize(view);
                    int inSampleSize = ImageUtils.calculateInSampleSize(actualImageSize, imageViewSize);
                    try {
                        is.reset();
                    } catch (IOException e) {
                        response = _getAsyn(imgUrl);
                        is = response.body().byteStream();
                    }

                    BitmapFactory.Options ops = new BitmapFactory.Options();
                    ops.inJustDecodeBounds = false;
                    ops.inSampleSize = inSampleSize;
                    final Bitmap bm = BitmapFactory.decodeStream(is, null, ops);
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            view.setImageBitmap(bm);
                        }
                    });
                } catch (Exception e) {
                    setErrorResId(mHandler, view, errorResId);

                } finally {
                    if (is != null) try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

    }

另附上圖片處理工具類,某位大神封裝的,是誰沒記住,這裏分享同來
package com.mydemo.okhttp;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.lang.reflect.Field;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

/**
 */
public class ImageUtils {
    /**
     * 根據InputStream獲取圖片實際的寬度和高度
     */
    public static ImageSize getImageSize(InputStream imageStream) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(imageStream, null, options);
        return new ImageSize(options.outWidth, options.outHeight);
    }

    public static class ImageSize {
        int width;

        int height;

        public ImageSize() {
        }

        public ImageSize(int width, int height) {
            this.width = width;
            this.height = height;
        }

        @Override
        public String toString() {
            return "ImageSize{" + "width=" + width + ", height=" + height + '}';
        }
    }

    public static int calculateInSampleSize(ImageSize srcSize, ImageSize targetSize) {
        // 源圖片的寬度
        int width = srcSize.width;
        int height = srcSize.height;
        int inSampleSize = 1;

        int reqWidth = targetSize.width;
        int reqHeight = targetSize.height;

        if (width > reqWidth && height > reqHeight) {
            // 計算出實際寬度和目標寬度的比率
            int widthRatio = Math.round((float) width / (float) reqWidth);
            int heightRatio = Math.round((float) height / (float) reqHeight);
            inSampleSize = Math.max(widthRatio, heightRatio);
        }
        return inSampleSize;
    }

    /**
     * 根據ImageView獲適當的壓縮的寬和高
     */
    public static ImageSize getImageViewSize(View view) {

        ImageSize imageSize = new ImageSize();

        imageSize.width = getExpectWidth(view);
        imageSize.height = getExpectHeight(view);

        return imageSize;
    }

    /**
     * 根據view獲得期望的高度
     */
    private static int getExpectHeight(View view) {

        int height = 0;
        if (view == null) return 0;

        final ViewGroup.LayoutParams params = view.getLayoutParams();
        // 如果是WRAP_CONTENT,此時圖片還沒加載,getWidth根本無效
        if (params != null && params.height != ViewGroup.LayoutParams.WRAP_CONTENT) {
            height = view.getWidth(); // 獲得實際的寬度
        }
        if (height <= 0 && params != null) {
            height = params.height; // 獲得佈局文件中的聲明的寬度
        }

        if (height <= 0) {
            height = getImageViewFieldValue(view, "mMaxHeight");// 獲得設置的最大的寬度
        }

        // 如果寬度還是沒有獲取到,憋大招,使用屏幕的寬度
        if (height <= 0) {
            DisplayMetrics displayMetrics = view.getContext().getResources().getDisplayMetrics();
            height = displayMetrics.heightPixels;
        }

        return height;
    }

    /**
     * 根據view獲得期望的寬度
     */
    private static int getExpectWidth(View view) {
        int width = 0;
        if (view == null) return 0;

        final ViewGroup.LayoutParams params = view.getLayoutParams();
        // 如果是WRAP_CONTENT,此時圖片還沒加載,getWidth根本無效
        if (params != null && params.width != ViewGroup.LayoutParams.WRAP_CONTENT) {
            width = view.getWidth(); // 獲得實際的寬度
        }
        if (width <= 0 && params != null) {
            width = params.width; // 獲得佈局文件中的聲明的寬度
        }

        if (width <= 0)

        {
            width = getImageViewFieldValue(view, "mMaxWidth");// 獲得設置的最大的寬度
        }
        // 如果寬度還是沒有獲取到,憋大招,使用屏幕的寬度
        if (width <= 0)

        {
            DisplayMetrics displayMetrics = view.getContext().getResources().getDisplayMetrics();
            width = displayMetrics.widthPixels;
        }

        return width;
    }

    /**
     * 通過反射獲取imageview的某個屬性值
     */
    private static int getImageViewFieldValue(Object object, String fieldName) {
        int value = 0;
        try {
            Field field = ImageView.class.getDeclaredField(fieldName);
            field.setAccessible(true);
            int fieldValue = field.getInt(object);
            if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {
                value = fieldValue;
            }
        } catch (Exception e) {
        }
        return value;

    }

    public static Bitmap getLoacalBitmap(String url) {
        try {
            FileInputStream fis = new FileInputStream(url);
            return BitmapFactory.decodeStream(fis);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}

獲取sdcard位置,及不限層級創建文件夾方法
 public static String getSDPath() {
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);// 判斷sd卡是否存在
        if (sdCardExist) {
            sdDir = Environment.getExternalStorageDirectory();// 獲取跟目錄
        }
        return sdDir.toString();
    }

    public static String mkdirs(String path) {
        String sdcard = getSDPath();
        if (path.indexOf(getSDPath()) == -1) {
            path = sdcard + (path.indexOf("/") == 0 ? "" : "/") + path;
        }
        File destDir = new File(path);
        if (!destDir.exists()) {
            path = createDir(path);
            if (path == null) {
                return null;
            }
        }
        return path;
    }

    private static String createDir(String path) {
        String sdPath = getSDPath();
        String[] dirs = path.replace(sdPath, "").split("/");
        StringBuffer filePath = new StringBuffer(sdPath);
        for (String dir : dirs) {
            if (!"".equals(dir) && !dir.equals(sdPath)) {
                filePath.append("/").append(dir);
                File destDir = new File(filePath.toString());
                if (!destDir.exists()) {
                    boolean b = destDir.mkdirs();
                    if (!b) {
                        return null;
                    }
                }
            }
        }
        return filePath.toString();
    }

下一篇將分享我在使用時的封裝。

發佈了37 篇原創文章 · 獲贊 0 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章