RxJava+Retrofit+MVP实现相册相机图片上传

简介

又有一段不分享帖子了,今天刚做了一个模块的代码,实现的效果是获取相机和相册的图片有Post请求上传到服务器,感觉遇到的了一些坑,
翻帖子的时候就感觉这方面的帖子不是太多,爬出坑之后想和大家分享一下自己的经验,希望以后各位做这方面的时候少爬些坑。

效果展示

这里写图片描述

代码展示

通过上面的效果我们是用的新框架RXJava和Retrofit+MVP实现上传的效果,初步的UI就不和大家多分享了我和大家讲解一下,我会一步一步讲解最后大家可以实现。

1:第一步:
  我们用的是Rxjava2.0+Retrofit2.0所以我们先导入下面的依赖
    dependencies {
    compile 'io.reactivex.rxjava2:rxjava:2.1.1'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    compile 'com.squareup.retrofit2:converter-scalars:+'
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
    //图片显示我们有的glide
    compile 'com.github.bumptech.glide:glide:3.8.0'
    //6.0以后的动态权限封装
        compile 'com.mylhyl:acp:1.1.7'
    }
2:第二步

我们先定义我们的Retrofit的接口,大家都知道Retrofit是一注解和动态代理的原理实现网络请求的,它也是对OKHttp进行的封装,这是我们定义的接口,用的是Post请求;

public interface Port {
//上传图片
@Multipart
@POST("userAction_uploadImage.action")
Observable<UploadPhotoBean> uploadPhoto(@Part("user.file") MultipartBody file,
@Part MultipartBody.Part... parts);
}

3:第三步:

然后我是自己封装了一个Retrofit的网络请求类,并添加拦截器代码如下:

public class HttpMethods {
  private static final int DEFAULT_TIMEOUT = 5;
     private final Retrofit mRetrofit1;
    private static String thpath;
    private final Port mPort;
    //构造方法私有
    private HttpMethods(String path) {
     HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        //手动创建一个OkHttpClient并设置超时时间
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
          httpClientBuilder.cookieJar(new CookiesManager(MyApp.getinster()));
        httpClientBuilder.addInterceptor(loggingInterceptor);
        httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
        //实例化一个网络框架
        mRetrofit1 = new Retrofit.Builder()
                .client(httpClientBuilder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(path)
                .build();
        mPort = mRetrofit1.create(Port.class);
    }
    //在访问HttpMethods时创建单例
    private static class SingletonHolder{

        private static final HttpMethods INSTANCE = new HttpMethods(thpath);
    }
      //获取单例
    public static HttpMethods getInstance(String path){
        thpath=path;
        return SingletonHolder.INSTANCE;
    }
     /**
     * 实现图片上传的方法
     * @param multipartBody
     * @param map
     * @param observer
     */
    public  void uploadPhoto(MultipartBody multipartBody, Map<String,String> map, Observer observer){
    //这些是我们需要的参数,如果我们要改变的话就直接改参数就可以
        MultipartBody.Part timer =                MultipartBody.Part.createFormData("user.currenttimer",map.get("user.currenttimer"));
        MultipartBody.Part picWidth =
                MultipartBody.Part.createFormData("user.picWidth",map.get("user.picWidth"));
        MultipartBody.Part picHeight =
                MultipartBody.Part.createFormData("user.picHeight",map.get("user.picHeight"));
        MultipartBody.Part sign =
                MultipartBody.Part.createFormData("user.sign",map.get("user.sign"));

        mPort.uploadPhoto(multipartBody,timer,picWidth,picHeight,sign)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
    }
}
4:第四步:
就该显示布局了把数据显示到跳转的页面上,我是一个fragment上面跳转到Activity上面,
在通过Activity里面回传到Fragment上面,我们可以先定义一个Button按钮实现跳转,放在我们需要点击的方法里面;
      Intent intent=new Intent(getActivity(),XiangjiActivity.class);
                startActivityForResult(intent, 1);
5:第五步:
我们跳到了一个Activity里面,我们的xml里面用一个Recyclerview来实现显示图片的列表,代码如下:
```
//定义一个集合来存放图片路径
    private List<String> paths = new ArrayList<>();
//定义了一个方法是获取相册信息的方法
   public void initdata() {
   //我们调用别人封装的添加6.0网络权限的类,就是我们上面到的依赖
    Acp.getInstance(this).request(new AcpOptions.Builder()
                    .setPermissions(
  //读、写和照相的权限                          Manifest.permission.READ_EXTERNAL_STORAGE
                            ,Manifest.permission.WRITE_EXTERNAL_STORAGE
                    ,   Manifest.permission.CAMERA)
                    .build(),
            new AcpListener() {
                @Override
                public void onGranted() {
                //得到我们的照片路径
                    Cursor cursor = getContentResolver().query(
                            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
                    //遍历相册
                    while (cursor.moveToNext()) {
                        String path = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA));
                        //将图片路径添加到集合
                        paths.add(path);
                    }
                    cursor.close();
                }
                @Override
                public void onDenied(List<String> permissions) {
                    Toast.makeText(XiangjiActivity.this,"没权限",Toast.LENGTH_SHORT).show();
                }
            });

//判断集合是否为空不空的话就调去下面的方法
if (paths != null) {
//方法是适配器给Recyclerview适配数据
xiangcedata();
}else {
Toast.makeText(XiangjiActivity.this,”数据为空”,Toast.LENGTH_SHORT).show();
}
}
“`

6:第六步:
适配适配器的数据,我用的适配recyclerview_helper的方法,不用写适配器直接就可以适配数据,点击条目回传数据到Fragment;
public void xiangcedata(){
//recyclerview_helper的适配器几行代码不用书写Adapter就实现数据也是导入依赖
        CommonAdapter<String> mAdapter = new CommonAdapter<String>(XiangjiActivity.this, R.layout.xiangceliebiao, paths) {
            @Override
            public void convert(BaseViewHolder holder, final int position) {
                View itemView = holder.getItemView();
                ImageView immg = itemView.findViewById(R.id.xiangce_image);
                if (position == 0) {
                    immg.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {

                        }
                    });
                }else {

                    immg.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
  //实现数据回传的方法
                            Intent mIntent = new Intent();
                            mIntent.putExtra("path", paths.get(position));
                            // 设置结果,并进行传送
                          setResult(1, mIntent);
                            finish();
                        }
                    });
                    //使用谷歌官方提供的Glide加载图片
                    Glide.with(XiangjiActivity.this).load(new File(paths.get(position))).diskCacheStrategy(DiskCacheStrategy.ALL).centerCrop().into(immg);
                }
            }
        };
        mHrecyclerviewXiangce.setAdapter(mAdapter);

    }
7:第七步:
数据已经通过 setResult(1, mIntent)把数据回传到Fragment里面了,然后我们可以拿到数据了对数据进行操代码:
 @Override//intent回传的方法
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        //得到数据
        String path = data.getStringExtra("path");
        //数据添加到本地Imageview上面
        Glide.with(getActivity()).load(new File(path)).diskCacheStrategy(DiskCacheStrategy.ALL).centerCrop().into(mCircleimgMine);
        //使用谷歌官方提供的Glide加载图片
        File file = new File(path);

        try {
            //压缩图片的大小并后期
            Bitmap bitmap = ImageResizeUtils.resizeImage(path, RESIZE_PIC);
            width = bitmap.getWidth()/2;
            height = bitmap.getHeight()/2;
            //图片压缩的方法
            FileOutputStream fos = new FileOutputStream(path);
            if (bitmap != null) {
                if (bitmap.compress(Bitmap.CompressFormat.JPEG, 85, fos)) {
                    fos.close();
                    fos.flush();
                }
                if (!bitmap.isRecycled()) {
                    bitmap.isRecycled();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
       //调用Retrofit  Post的方法
        uploadFile(file);

    }
8:第八步:

拿到数据我们就网络解析了

//封装方法实现网络请求并获得数据是否成功
       public void uploadFile(File file){


                if(!file.exists()){
                    Toast.makeText(getActivity(),"图片不存在",Toast.LENGTH_SHORT).show();
                    return;
                }
       //拆分数据
                String [] arr = file.getAbsolutePath().split("/");

                RequestBody requestFile =
                        RequestBody.create(MediaType.parse("multipart/form-data"), file);
//获取当前时间
                long ctimer = System.currentTimeMillis() ;
         //拼写参数
                Map<String,String> map = new HashMap<String,String>();
                map.put("user.currenttimer",ctimer+"");
                map.put("user.picWidth",width+"");
                map.put("user.picHeight",height+"");
    //把MAP集合转换字符串,调去封装的.so库实现
                String sign = JNICore.getSign(SortUtils.getMapResult(SortUtils.sortString(map)));

                map.put("user.sign",sign);


                MultipartBody body = new MultipartBody.Builder()
                        .addFormDataPart("image",arr[arr.length-1],requestFile)
                        .build();
  //调我们封装的Retrofit实现类并传参数、网络路径得到对象在ONText方法里面
    HttpMethods.getInstance(DataUrl.registerpath).uploadPhoto(body, map, new Observer<UploadPhotoBean>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {

                    }

                    @Override//得到数据的方法
                     public void onNext(@NonNull UploadPhotoBean uploadPhotoBean) {
                        Log.d("eeee", "onNext: "+uploadPhotoBean.toString());
                           Toast.makeText(getActivity(),uploadPhotoBean.getResult_message(),Toast.LENGTH_SHORT).show();
                    }

                    @Override//异常的方法
                    public void onError(@NonNull Throwable e) {
                        Log.d("eeee", "onErroy: "+e.toString());
                    }

                    @Override
                    public void onComplete() {

                    }
                });
            }
以上总结
这样大家就可以实现我们的效果了,或许我们看着会很乱,是为了个大家分析一下每个方法的用途和作用,下面我会把两个里面的方法联合起来给大家展示一下。
fragment的全部代码,xml就掠过了
  private int INT_TOP=1;
    public String LocalPhotoName;
    public  final int RESIZE_PIC = 720 ;
    private int width ;
    private int height ;
    @Override
    protected int attachLayoutRes() {
        return R.layout.mine_fragment;
    }

    @Override
    protected void initViews() {
    }

    @Override
    protected void updateViews(boolean isRefresh) {
    }
    @OnClick({R.id.autola_mine, R.id.autolayout_mine_text, R.id.autola_mine_setting})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.autola_mine:
                Intent intent=new Intent(getActivity(),XiangjiActivity.class);
                startActivityForResult(intent, INT_TOP);
                break;
            case R.id.autolayout_mine_text:
                TZutil.onClick(view,getActivity(), ParticularsActivity.class);
                break;
            case R.id.autola_mine_setting:
                TZutil.onClick(view,getActivity(), SettingActivity.class);
                break;
        }
    }


            public void uploadFile(File file){


                if(!file.exists()){
                    Toast.makeText(getActivity(),"图片不存在",Toast.LENGTH_SHORT).show();
                    return;
                }
                String [] arr = file.getAbsolutePath().split("/");

                RequestBody requestFile =
                        RequestBody.create(MediaType.parse("multipart/form-data"), file);

                long ctimer = System.currentTimeMillis() ;
                Map<String,String> map = new HashMap<String,String>();
                map.put("user.currenttimer",ctimer+"");
                map.put("user.picWidth",width+"");
                map.put("user.picHeight",height+"");
                String sign = JNICore.getSign(SortUtils.getMapResult(SortUtils.sortString(map)));

                map.put("user.sign",sign);


                MultipartBody body = new MultipartBody.Builder()
                        .addFormDataPart("image",arr[arr.length-1],requestFile)
                        .build();
        //        BaseApiClient.getInstance(getActivity(),DataUrl.registerpath).shangchuan(DataUrl.tupian,body,map,new BaseObserBean<String>(getActivity()){
        //            @Override
        //            public void Next(String data) {
        //                Log.d("wwww", "Next:------> "+data);
        //            }
        //        });

                HttpMethods.getInstance(DataUrl.registerpath).uploadPhoto(body, map, new Observer<UploadPhotoBean>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {

                    }

                    @Override
                    public void onNext(@NonNull UploadPhotoBean uploadPhotoBean) {
                        Log.d("eeee", "onNext: "+uploadPhotoBean.toString());
                           Toast.makeText(getActivity(),uploadPhotoBean.getResult_message(),Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        Log.d("eeee", "onErroy: "+e.toString());
                    }

                    @Override
                    public void onComplete() {

                    }
                });
            }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        String path = data.getStringExtra("path");
        Glide.with(getActivity()).load(new File(path)).diskCacheStrategy(DiskCacheStrategy.ALL).centerCrop().into(mCircleimgMine);
        //使用谷歌官方提供的Glide加载图片
        File file = new File(path);

        try {
            //压缩图片的大小并后期
            Bitmap bitmap = ImageResizeUtils.resizeImage(path, RESIZE_PIC);
            width = bitmap.getWidth()/2;
            height = bitmap.getHeight()/2;
            //图片压缩的方法
            FileOutputStream fos = new FileOutputStream(path);
            if (bitmap != null) {
                if (bitmap.compress(Bitmap.CompressFormat.JPEG, 85, fos)) {
                    fos.close();
                    fos.flush();
                }
                if (!bitmap.isRecycled()) {
                    bitmap.isRecycled();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        uploadFile(file);

    }
}
Activity的xml文件
<com.lvr.library.recyclerview.HRecyclerView
        android:id="@+id/hrecyclerview_xiangce"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </com.lvr.library.recyclerview.HRecyclerView>``
Activity的代码:

public class XiangjiActivity extends MVPBaseActivity<XiangjiContract.View, XiangjiPresenter> implements XiangjiContract.View {
    @BindView(R.id.img_phone_kuaijieht)
    ImageView mImgPhoneKuaijieht;
    @BindView(R.id.hrecyclerview_xiangce)
    HRecyclerView mHrecyclerviewXiangce;
    private List<String> paths = new ArrayList<>();


    @Override
    protected int attachLayoutRes() {
        return R.layout.xiangce;
    }

    @Override
    protected void initViews() {
      mHrecyclerviewXiangce .setLayoutManager(new GridLayoutManager(this,3));
        initdata();

    }

    public void initdata() {
        Acp.getInstance(this).request(new AcpOptions.Builder()
                        .setPermissions(
                                Manifest.permission.READ_EXTERNAL_STORAGE
                                ,Manifest.permission.WRITE_EXTERNAL_STORAGE
                        ,   Manifest.permission.CAMERA)
                        .build(),
                new AcpListener() {
                    @Override
                    public void onGranted() {
                        Cursor cursor = getContentResolver().query(
                                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
                        //遍历相册
                        while (cursor.moveToNext()) {
                            String path = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA));
                            //将图片路径添加到集合
                            paths.add(path);
                        }
                        cursor.close();
                    }
                    @Override
                    public void onDenied(List<String> permissions) {
                        Toast.makeText(XiangjiActivity.this,"没权限",Toast.LENGTH_SHORT).show();
                    }
                });
        if (paths != null) {
          xiangcedata();
        }else {
               Toast.makeText(XiangjiActivity.this,"数据为空",Toast.LENGTH_SHORT).show();
        }

    }
    public void xiangcedata(){
        CommonAdapter<String> mAdapter = new CommonAdapter<String>(XiangjiActivity.this, R.layout.xiangceliebiao, paths) {
            @Override
            public void convert(BaseViewHolder holder, final int position) {
                View itemView = holder.getItemView();
                ImageView immg = itemView.findViewById(R.id.xiangce_image);
                if (position == 0) {
                    immg.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {

                        }
                    });
                }else {

                    immg.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            Intent mIntent = new Intent();
                            mIntent.putExtra("path", paths.get(position));
                            // 设置结果,并进行传送
                          setResult(1, mIntent);
                            finish();
                        }
                    });
                    //使用谷歌官方提供的Glide加载图片
                    Glide.with(XiangjiActivity.this).load(new File(paths.get(position))).diskCacheStrategy(DiskCacheStrategy.ALL).centerCrop().into(immg);
                }
            }
        };
        mHrecyclerviewXiangce.setAdapter(mAdapter);

    }


}
总体总结
分享了全部的实现流程,希望能给大家多小带来帮助,
也希望大神们的指点和切磋,有问题请留言,会第一时间回复!
感觉有意思的可以点赞,有不太明白的朋友可以加我QQ3532877729和我联系也可以关注我的公众号更多精彩内容!!

这里写图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值