1. 程式人生 > 其它 >OKhttp網路請求實戰(請求表單,上傳圖片,上傳多張圖片)

OKhttp網路請求實戰(請求表單,上傳圖片,上傳多張圖片)

今天和大家分享一個okhttp網路請求的實戰案例,歡迎新手學生,大佬指點,話不多說直接上乾貨。

我是直接手動新增的架包,手動匯入,記住一定要匯入。新增依賴也可以哈,看個人愛好(要架包的私信或者留言,留郵箱,或者什麼我發給你們)

然後在新增依賴:(允許我裝個x用rxjava2了,載入圖片用的是glide,支援多張上傳圖片)

implementation 'io.reactivex.rxjava2:rxjava:2.2.19'
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    implementation 'com.google.code.gson:gson:2.8.5'

最重要的一步來了,記住了 新增網路許可權:

!--相機許可權-->
    <uses-permission android:name="android.permission.CAMERA" />
    <!--讀檔案許可權-->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!--使用特性-->
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
    <uses-permission android:name="android.permission.INTERNET" />

配置的都差不多準備完成了開始幹程式碼吧:用rxjava介面是要有的:

public interface MyNetWorkCallback<T> {

    void onSuccess(T t);
    void onError(int errorCode, String errorMsg);

}

繼續在上:

public interface IHttp {
    <T> void get(String url, MyNetWorkCallback<T> callback);
    <T> void get(String url, Map<String, String> params, MyNetWorkCallback<T> callback);
    <T> void get(String url, Map<String, String> params, Map<String, String> headers, MyNetWorkCallback<T> callback);
    <T> void post(String url, Map<String, String> params, MyNetWorkCallback<T> callback);
    void upload(String url, String path, Map<String, String> params, String fileType, MediaType MEDIA_TYPE, final MyNetWorkCallback<String> callback);
    void download();
    void loadImage(String url, ImageView imageView);

}

這個類幹啥來的忘記了,場時間不用了,但是也寫山了,你們可以不用

public class HttpFactroy {
    public static IHttp create(){
        return OkHttpUtils.getInstance();
    }
}

主要的類來了,單例走起:

/**
 * 基於OKhttp傳送網路請求
 * Created by 2018/1/10.
 *
 * @Author King
 * @Email [email protected]
 */

public class OkHttpUtils implements IHttp {

    private OkHttpClient okHttpClient;
    //建構函式私有化
    private OkHttpUtils(){
        okHttpClient = new OkHttpClient.Builder().build();
    }

    private static OkHttpUtils okHttpUtils;

    //提供一個公共的、靜態的、返回值型別是當前本類的物件
    public static OkHttpUtils getInstance(){
        if(okHttpUtils == null){
            synchronized (OkHttpUtils.class){
                if(okHttpUtils == null) {
                    okHttpUtils = new OkHttpUtils();
                }
            }
        }
        return okHttpUtils;
    }

    @Override
    public <T> void get(String url, MyNetWorkCallback<T> callback) {

    }
    /**
     * 上傳多張圖片及引數
     * @param reqUrl URL地址
     * @param paramssa 引數
     * @param pic_key 上傳圖片的關鍵字
     */
    public Observable<String> sendMultipart(final String reqUrl, final Map<String, String> paramssa, final String pic_key, final List<File> filessa){
        return Observable.create(new ObservableOnSubscribe<String>(){
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Exception {
                MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder();
                multipartBodyBuilder.setType(MultipartBody.FORM);
                //遍歷map中所有引數到builder
                if (paramssa != null){
                    for (String key : paramssa.keySet()) {
                        multipartBodyBuilder.addFormDataPart(key, paramssa.get(key));
                    }
                }
                //遍歷paths中所有圖片絕對路徑到builder,並約定key如“upload”作為後臺接受多張圖片的key
                if (filessa != null){
                    for (File file : filessa) {
                        multipartBodyBuilder.addFormDataPart(pic_key, file.getName(), RequestBody.create(MEDIA_TYPE_PNG, file));
                    }
                }
                //構建請求體
                RequestBody requestBody = multipartBodyBuilder.build();
                Request.Builder RequestBuilder = new Request.Builder();
                RequestBuilder.url(reqUrl);// 新增URL地址
                RequestBuilder.post(requestBody);
                Request request = RequestBuilder.build();
                okHttpClient.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(okhttp3.Call call, IOException e) {
                        emitter.onError(e);
                        emitter.onComplete();
                        call.cancel();
                    }

                    @Override
                    public void onResponse(okhttp3.Call call, Response response) throws IOException {
                        String str = response.body().string();
                        emitter.onNext(str);
                        emitter.onComplete();
                        call.cancel();
                    }
                });
            }
        });
    }
    /**
     * 傳送get請求
     * @param url 請求地址
     * @param params 請求引數
     * @param callback 回撥
     * @param <T> 請求回來的資料對應的JavaBean
     */
    @Override
    public <T> void get(String url, Map<String, String> params, final MyNetWorkCallback<T> callback) {
        StringBuffer sb = new StringBuffer(url);
        if(params != null && params.size() > 0){
            sb.append("?");
            Set<String> keys = params.keySet();
            for (String key : keys) {
                String value = params.get(key);
                sb.append(key).append("=").append(value).append("&");
            }
            url = sb.deleteCharAt(sb.length()-1).toString();
        }
        Request request = new Request.Builder().url(url).build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(okhttp3.Call call, IOException e) {
                App.context.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //執行在主執行緒
                        callback.onError(404,e.getMessage().toString());
                    }
                });
            }

            @Override
            public void onResponse(okhttp3.Call call, Response response) throws IOException {
                final String jsonData = response.body().string();
                //執行在子執行緒中
                App.context.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //執行在主執行緒
                        callback.onSuccess(getGeneric(jsonData,callback));
                    }
                });
            }
        });
    }

    @Override
    public <T> void get(String url, Map<String, String> params, Map<String, String> headers, final MyNetWorkCallback<T> callback) {

        StringBuffer sb = new StringBuffer(url);
        if(params != null && params.size() > 0){
            sb.append("?");
            Set<String> keys = params.keySet();
            for (String key : keys) {
                String value = params.get(key);
                sb.append(key).append("=").append(value).append("&");
            }
            url = sb.deleteCharAt(sb.length()-1).toString();
        }
        Request.Builder builder = new Request.Builder();
        if(headers != null && headers.size() > 0){
            Set<String> keys = headers.keySet();
            for (String key : keys){
                String value = headers.get(key);
                builder.addHeader(key,value);
            }
        }
        Request request = builder.url(url).build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(okhttp3.Call call, IOException e) {
                App.context.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //執行在主執行緒
                        callback.onError(404,e.getMessage().toString());
                    }
                });
            }

            @Override
            public void onResponse(okhttp3.Call call, Response response) throws IOException {
                final String jsonData = response.body().string();
                //執行在子執行緒中
                App.context.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //執行在主執行緒
                        callback.onSuccess(getGeneric(jsonData,callback));
                    }
                });
            }
        });
    }

    /**
     * post方法上傳表單
     * @param url
     * @param params
     * @param callback
     * @param <T>
     */
    @Override
    public <T> void post(String url, Map<String, String> params, final MyNetWorkCallback<T> callback) {

        FormBody.Builder builder = new FormBody.Builder();
        if(params !=null && params.size() > 0){
            Set<String> keys = params.keySet();
            for (String key : keys) {
                String value = params.get(key);
                builder.add(key,value);
            }
        }
        Request request = new Request.Builder().url(url).post(builder.build()).build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(okhttp3.Call call, IOException e) {
                App.context.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //執行在主執行緒
                        callback.onError(404,e.getMessage().toString());
                    }
                });
            }

            @Override
            public void onResponse(okhttp3.Call call, Response response) throws IOException {
                final String jsonData = response.body().string();
                //執行在子執行緒中
                App.context.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //執行在主執行緒
                        callback.onSuccess(getGeneric(jsonData,callback));
                    }
                });
            }
        });
    }


    @Override
    public void upload(String url, String path, Map<String, String> params, String fileType, MediaType MEDIA_TYPE, final MyNetWorkCallback<String> callback) {
        File file = new File(path);
        MultipartBody.Builder  multiRequestBody = new MultipartBody.Builder();
        if(params !=null && params.size() > 0){
            Set<String> keys = params.keySet();
            for (String key : keys) {
                String value = params.get(key);
                multiRequestBody.setType(MultipartBody.FORM)
                        .addFormDataPart(key, value);// 提交普通欄位
            }
        }
        // 上傳檔案使用MultipartBody.Builder
        RequestBody requestBody = multiRequestBody
                .setType(MultipartBody.FORM)
                .addFormDataPart(fileType, file.getName(), RequestBody.create(MEDIA_TYPE, file)) // 提交圖片,第一個引數是鍵(name="第一個引數"),第二個引數是檔名,第三個是一個RequestBody
                .build();
        // POST請求
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(okhttp3.Call call, IOException e) {
                App.context.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //執行在主執行緒
                        callback.onError(404,e.getMessage().toString());
                    }
                });
            }

            @Override
            public void onResponse(okhttp3.Call call, Response response) throws IOException {
                final String upLoadResult=response.body().string();
                //執行在子執行緒中
                App.context.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //執行在主執行緒
                        callback.onSuccess(upLoadResult);
                    }
                });
            }
        });
    }

    @Override
    public void download() {

    }

    @Override
    public void loadImage(String url, ImageView imageView) {
        Glide.with(App.context).load(url).into(imageView);
    }
    /**
     * 自動解析json至回撥中的JavaBean
     * @param jsonData
     * @param callBack
     * @param <T>
     * @return
     */
    private <T> T getGeneric(String jsonData, MyNetWorkCallback<T> callBack){
        Gson gson = new Gson();
        //通過反射獲取泛型的例項
        Type[] types = callBack.getClass().getGenericInterfaces();
        Type[] actualTypeArguments = ((ParameterizedType) types[0]).getActualTypeArguments();
        Type type = actualTypeArguments[0];
        T t = gson.fromJson(jsonData,type);
        return t;
    }
    //取消
    public void cancel(String url, Map<String, String> params){
        FormBody.Builder builder = new FormBody.Builder();
        if(params !=null && params.size() > 0){
            Set<String> keys = params.keySet();
            for (String key : keys) {
                String value = params.get(key);
                builder.add(key,value);
            }
        }
        Request request = new Request.Builder().url(url).post(builder.build()).build();
        okHttpClient.newCall(request).cancel();
    }
}

你會發現很多問題哈紅的什麼的APP類得有吧()要不怎麼檢測更新呢:

public  class App extends Application {
    public static MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
    public static MainActivity context = null;

}

準備工作都完成了,別拖延大家時間了開始使用吧:表單請求:

private Map<String, String> map = new HashMap<>();
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//很重要的一行,要不然你就空指標去吧
        App.context = this;

    }

隨便寫個方法看你心情吧:

map.put("currentLang", "2");
                OkHttpUtils.getInstance().post(ApiUrl.HTTP_LOG, map, new MyNetWorkCallback<寫自己的Bean>() {
                    @Override
                    public void onSuccess(寫自己的Bean s) {
//解析
                        Gson gson = new Gson();
//變成實體類了自己用吧,隨便用已經在子執行緒了隨便吐司。
                        寫自己的Bean logBean = gson.fromJson(s, 寫自己的Bean.class);
                        Toast.makeText(MainActivity.this, "登入成功", Toast.LENGTH_SHORT).show();

                    }

                    @Override
                    public void onError(int errorCode, String errorMsg) {
                        Toast.makeText(MainActivity.this, "請求失敗", Toast.LENGTH_SHORT).show();
                    }
                });

要圖片的嗎?來了:

Map<String, String> map = new HashMap<>();
        map.put("accessToken", toKen);
OkHttpUtils.getInstance().sendMultipart(path, map, "imgData", 存放圖片的集合listfiles)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.newThread())
                .subscribe(new Subscriber<String>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable throwable) {
                        dialog.dismiss();
                        Toast.makeText(ComputerRoomPatrolavtivity.this, "上傳失敗了", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onNext(String s) {
                        s = s.trim();
                        s = s.substring(1, s.length() - 1);//去除首尾雙引號。
                        String str = s.replace("\\", "");//去除所有的\
                        Gson gson = new Gson();
                        Log.e("TAG", "str=" + str);
                            ToastShow.show(ComputerRoomPatrolavtivity.this, "上傳成功");
                        } else {
                            dialog.dismiss();
                            ToastShow.show(ComputerRoomPatrolavtivity.this, "失敗" + bean.getErrorMessage());
                        }
                    }
                });

友情提示一下,我的張片上傳之前都壓縮了,這樣上傳比較爽。我用的是魯班壓縮可能很舊了湊合看吧

implementation 'top.zibin:Luban:1.1.3'
Luban.get(this)
                .load(file)                     //傳人要壓縮的圖片
                .putGear(Luban.THIRD_GEAR)      //設定壓縮檔次,預設三擋
                .setCompressListener(new OnCompressListener() { //設定回撥

                    @Override
                    public void onStart() {
                        // TODO 壓縮開始前呼叫,可以在方法內啟動 loading UI
                    }

                    @Override
                    public void onSuccess(File file) {
                        // TODO 壓縮成功後呼叫,返回壓縮後的圖片檔案
                        listFileImages.add(file);
                            //網路請求
                            httpssa(listFileImages,toKen,dataId);
                    }

                    @Override
                    public void onError(Throwable e) {
                        // TODO 當壓縮過去出現問題時呼叫
                    }
                }).launch(); 

目前的專案還沒有涉及到長傳圖片,等涉及到了我自己用了我在改進,

在友情提示rxjava當中的長傳圖片觀察者模式可能有些更改,自己看下最新的吧,然後呼叫,應該舊可以了,用不好的話的等我更新吧。

感謝新手借鑑,大佬指點。