Retrofit+RxJava上传图片上传图片到后台

5,026 阅读3分钟

在做一个商城,第一个版本使用的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);
}