Retrofit+RxJava上傳圖片上傳圖片到後臺

一棵大白楊發表於2017-09-26

在做一個商城,第一個版本使用的OkHttp3來進行網路操作的,現在把第一個版本推倒重新做了個版本,於是就用上了正在如火如荼的Retrofit+RxJava來實現網路操作。在上傳圖片作為頭像時實現了一個上午也沒搞定,現在終於有時間再重新搞一下了。於是把使用OkHttp3上傳和Retrofit+RxJava上傳都總結了一下。

PS:圖片的獲取在不同版本上面可能會出現問題,不過這不是本文重點,主要是想展示一下上傳圖片時OkHttp3和Retrofit的引數問題。

申請許可權

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
複製程式碼

獲取照片

  1. 準備請求碼和臨時變數名

    private static final int PHOTO_REQUEST_CAREMA = 1;// 拍照
    private static final int PHOTO_REQUEST_GALLERY = 2;// 從相簿中選擇
    private static final int PHOTO_REQUEST_CUT = 3;// 裁剪之後
    private static final String PHOTO_FILE_NAME = "temp_photo.jpg";//臨時檔名
    private File tempFile;
    複製程式碼
  2. 開啟相簿獲取照片

    public void gallery() {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");
        startActivityForResult(intent, PHOTO_REQUEST_GALLERY);//攜帶請求碼
    }
    複製程式碼
  3. 開啟相機獲取照片

    public void camera() {
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
        if (hasSdcard()) {// 判斷儲存卡是否可以用,可用進行儲存
            tempFile = new File(Environment.getExternalStorageDirectory(), PHOTO_FILE_NAME);
            Uri uri = Uri.fromFile(tempFile); // 從檔案中建立uri
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        }
        startActivityForResult(intent, PHOTO_REQUEST_CAREMA);//攜帶請求碼
    }
    複製程式碼
  4. 裁剪圖片

    private void crop(Uri uri) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        // 裁剪框的比例,1:1
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // 裁剪後輸出圖片的尺寸大小
        intent.putExtra("outputX", 250);
        intent.putExtra("outputY", 250);
        intent.putExtra("outputFormat", "JPEG");// 圖片格式
        intent.putExtra("noFaceDetection", true);// 取消人臉識別
        intent.putExtra("return-data", true);
        startActivityForResult(intent, PHOTO_REQUEST_CUT); // 開啟一個帶有返回值的Activity,請求碼為PHOTO_REQUEST_CUT
    }複製程式碼
  5. 判斷是否掛在了SD卡

    private boolean hasSdcard() {
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            return true;
        } else {
            return false;
        }
    }複製程式碼
  6. 獲取的是external資料庫對應的Image檔案

    private Uri external(String external) {
        String myImageUrl = "content://media" + external;
        Uri uri = Uri.parse(myImageUrl);
        String[] proj = {MediaStore.Images.Media.DATA};
        Cursor actualimagecursor = this.managedQuery(uri, proj, null, null, null);
        int actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        actualimagecursor.moveToFirst();
        String img_path = actualimagecursor.getString(actual_image_column_index);
        File file = new File(img_path);
        Uri fileUri = Uri.fromFile(file);
        return fileUri;
    }複製程式碼
  7. 在回撥中取圖片

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == PHOTO_REQUEST_GALLERY) {
            // 從相簿返回的資料
            if (data != null) {// 得到圖片的全路徑
                Uri uri = data.getData();
                crop(uri);
            }
        } else if (requestCode == PHOTO_REQUEST_CAREMA) {//從相機返回的資料
            if (hasSdcard()) {
                crop(Uri.fromFile(tempFile));
            } else {
                Toast.makeText(MainActivity.this, "未找到儲存卡,無法儲存照片!", Toast.LENGTH_LONG).show();
            }
        } else if (requestCode == PHOTO_REQUEST_CUT) {//從剪下圖片返回的資料
            if (data != null) {
                Bitmap bitmap = data.getParcelableExtra("data");
                //將bitmap轉換為Uri
                Uri uri = Uri.parse(MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, null, null));
                //對非正確的Uri處理,這類Uri存在手機的external.db中,可以查詢_data欄位查出對應檔案的uri
                if (uri.getPath().contains("external")) {
                    uri = external(uri.getPath());
                }
               //在這可以拿到裁剪後的圖片Uri,然後進行你想要的操作
                upLoad2Server(uri);
            }
            try {
                tempFile.delete();//將臨時檔案刪除
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }複製程式碼

進行上傳操作(2種方法)

1.使用OkHttp3來上傳

    1. 新增依賴:
    compile 'com.squareup.okhttp3:okhttp:3.3.0'
    2. 上傳程式碼如下:
    private void upLoad2Server(Uri uri) {
        File file = null;
        try {
            file = new File(new URI(uri.toString()));
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        if (file != null) {
            builder.addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse
                    ("image*//*"), file));
        }
        MultipartBody requestBody = builder.build();
        Request request = new Request.Builder()
                .url("你的上傳介面")
                .post(requestBody)
                .build();
        OkHttpClient client = new OkHttpClient.Builder().connectTimeout(10000, TimeUnit.SECONDS).readTimeout(10000, TimeUnit.SECONDS).writeTimeout(10000, TimeUnit.SECONDS).build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        })
    }複製程式碼

2.使用Retrofit+RxJava來上傳

    1.新增依賴
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    compile 'com.squareup.retrofit2:converter-scalars:2.1.0'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
    compile 'io.reactivex:rxjava:1.2.4'
    compile 'io.reactivex:rxandroid:1.2.1'

    2.準備上傳介面
    @Multipart
    @POST("你的介面")
    Observable<ResponseBody> upload(@Part MultipartBody.Part imgs);

    public class NetApi {
    public static final String BASE_URL = "你的域名";
    private static NetApi mNetApi;
    private static Retrofit retrofit;
    private static NetService mNetService;

    private NetApi() {
    }

    public static NetApi getInstance() {
        if (null == mNetApi) {
            mNetApi = new NetApi();
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            mNetService = retrofit.create(NetService.class);
        }
        return mNetApi;
    }

    public void upload(Subscriber<ResponseBody> subscriber, MultipartBody.Part imgs) {
        mNetService.upload(imgs)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }
}
    3.上傳方法如下:
    private void upLoad2Server(Uri uri) {
    File file = null;
    try {
        file = new File(new URI(uri.toString()));
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }

    RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
    MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestBody);

    NetApi.getInstance().upload(new Subscriber<ResponseBody>() {
        @Override
        public void onCompleted() {
            Log.e("MainActivity", "onCompleted");
        }

        @Override
        public void onError(Throwable e) {
            Log.e("MainActivity", "onError,"+e.getMessage());
        }

        @Override
        public void onNext(ResponseBody responseBody) {
            try {
                Log.e("MainActivity", "onNext,=" + responseBody.string());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }, body);
}複製程式碼


相關文章