RxJava+Retrofit+MVP实现相册相机图片上传
2017-07-25 21:31
381 查看
简介
又有一段不分享帖子了,今天刚做了一个模块的代码,实现的效果是获取相机和相册的图片有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时创建单例 4000 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和我联系也可以关注我的公众号更多精彩内容!!
相关文章推荐
- Rxjava+Retrofit实现多图片上传
- 使用MVP框架,retrofit结合Rxjava以及fresco加载图片,用recycleview实现
- 用Swift实现iOS相机及相册图片上传
- Android进阶封装之一个类实现兼容Android 6.0权限、适配Android7.0 拍照: 相机与相册上传图片就用我好啦!
- 终极封装 Rxjava+Retrofit+okhttp+mvp实现
- Retrofit+Rxjava实现文件上传和下载功能
- 安卓基础--实现从系统相机,相册获取图片
- Android调用手机相机和相册拿到图片保存上传
- 上传图片(来源:相机和相册)
- 安卓开发小米4,酷派 手机适配和调用系统相机相册做图片上传的问题
- 调用系统相机、相册、剪裁图片并上传(常用于上传头像,兼容Android7.0)
- 安卓学习笔记---Retrofit2.0 实现图文(参数+图片)上传方法总结
- 微信小程序开发之从相册获取图片 使用相机拍照 本地图片上传
- swift如何上传带param参数头像或图片,并使用相册图片或者相机
- 使用MVP+Retrofit+RxJava实现的的Android Demo (上)使用Nuclues库实现MVP
- Rxjava+Retrofit+MVP实现购物车功能
- 使用南尘的ImagePicker实现仿微信的相册图片选择以及拍照上传
- Android中相机拍摄照片,以及相册选择图片压缩上传(压缩后保存进SD中)(可用于修改头像等)
- Android中使用OKHttp上传图片,从相机和相册中获取图片并剪切
- 安卓开发调用相机和本地图库选择照片并上传(上传retrofit实现)