简介
又有一段不分享帖子了,今天刚做了一个模块的代码,实现的效果是获取相机和相册的图片有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和我联系也可以关注我的公众号更多精彩内容!!