Android 上传图片到服务器 okhttp一

时间:2022-03-03 09:23:14

【目录】

(一)上传图片到服务器一 ---------------------------------Android代码

(二)上传图片到服务器二---------------------------------Android 系统7.0以上调用相机兼容问题

(三)上传图片到服务器三-----------------------------------后台服务器代码

一、相关知识

①Android权限申请

②网络访问框架OKHttp

③内存溢出问题:图片压缩

④Android 系统7.0以上调用系统相机无效

⑤有关图片上传过程中遇到的内存溢出问题

二、效果展示

Android 上传图片到服务器 okhttp一

二、代码

①HTML

          <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
>
<android.support.v7.widget.RecyclerView
android:id="@+id/rvPic"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"> </android.support.v7.widget.RecyclerView> <TextView
android:id="@+id/tvNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0/8"
android:textColor="#666666"
android:layout_gravity="right|bottom"
android:paddingRight="@dimen/dp_10"/> </LinearLayout>
<Button android:id="@+id/btn_Enter"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_45"
android:layout_alignParentBottom="true"
android:background="@drawable/selecter_button"
android:text="确认上传"
android:textColor="@color/inButtonText"
android:textSize="@dimen/dp_18" />

②Java代码

<基本功能>

实体类

 public class LoadFileVo {

     File file;

     int pg; //图片下方的进度条

     boolean isUpload = false; //标识该文件是否上传

     Bitmap bitmap;

     public Bitmap getBitmap() {
return bitmap;
} public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
} public boolean isUpload() {
return isUpload;
} public void setUpload(boolean upload) {
isUpload = upload;
} public LoadFileVo() {
} public LoadFileVo(File file, int pg) {
this.file = file;
this.pg = pg;
} public LoadFileVo(File file, boolean isUpload, int pg,Bitmap bitmap) {
this.file = file;
this.pg = pg;
this.isUpload = isUpload;
this.bitmap = bitmap;
} public File getFile() {
return file;
} public void setFile(File file) {
this.file = file;
} public int getPg() {
return pg;
} public void setPg(int pg) {
this.pg = pg;
}
}

适配器

 /*
*Create By 小群子 2018/12/10
*/ public class LoadPicAdapter extends RecyclerView.Adapter<LoadPicAdapter.MyViewHolder> { Context context;
List<LoadFileVo> fileList = null;
View view;
int picNum = 8;//列表的图片个数最大值 public LoadPicAdapter(Context context, List<LoadFileVo> fileList) {
this.context = context;
this.fileList = fileList;
} public LoadPicAdapter(Context context, List<LoadFileVo> fileList, int picNum) {
this.context = context;
this.fileList = fileList;
this.picNum = picNum;
} public interface OnItemClickListener {
void click(View view, int positon); void del(View view);
} OnItemClickListener listener; public void setListener(OnItemClickListener listener) {
this.listener = listener;
} @Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { view = LayoutInflater.from(context).inflate(R.layout.load_item_pic, parent, false);
return new MyViewHolder(view);
} @Override
public void onBindViewHolder(MyViewHolder holder, final int position) { //通过默认设置第一个为空文件为添加退保,且在文件个数小于最大限制值的情况。当图片个数等于最大限制值,第一个则不是添加按钮
if (position == 0&&fileList.get(position).getBitmap()==null) {
holder.ivPic.setImageResource(R.drawable.addpic);//加号图片
holder.ivPic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
listener.click(view, position);
}
});
holder.ivDel.setVisibility(View.INVISIBLE);
holder.bg_progressbar.setVisibility(View.GONE); } else {
// Uri uri = Uri.parse(fileList.get(position).getFile().getPath());
// holder.ivPic.setImageURI(uri); holder.ivPic.setImageBitmap(fileList.get(position).getBitmap());
//使用压缩后的图片进行填充到界面上
holder.ivDel.setVisibility(View.VISIBLE);
holder.bg_progressbar.setVisibility(View.VISIBLE);
holder.bg_progressbar.setProgress(fileList.get(position).getPg());
} holder.ivDel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//判断图片是否上传,上传后将无法删除
if (fileList.get(position).isUpload()) {
Toast.makeText(context, "该图片已上传!", Toast.LENGTH_SHORT).show();
} else {
fileList.remove(position);
if (fileList.size()==picNum-1&&fileList.get(0).getBitmap()!=null){
fileList.add(0,new LoadFileVo());
}//如果数量达到最大数时,前面的加号去掉,然后再减去时,则添加前面的加号
notifyDataSetChanged();
if (listener!=null){
listener.del(view);//传递接口,计算图片个数显示在界面中
} }
}
}); } @Override
public int getItemCount() {
return fileList.size();
} static class MyViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.ivPic)
ImageView ivPic;
@BindView(R.id.ivDel)
ImageView ivDel;
@BindView(R.id.bg_progressbar)
ProgressBar bg_progressbar; View view; MyViewHolder(View view) {
super(view);
this.view = view;
ButterKnife.bind(this, view);
}
}
}

item 布局//布局自行优化

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/dp_110"
android:layout_height="@dimen/dp_115" > <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="@dimen/dp_5"> <ImageView
android:id="@+id/ivPic"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_100"
android:scaleType="centerCrop"
android:src="@drawable/ic_pick"
/> <ProgressBar
android:id="@+id/bg_progressbar"
style="@style/StyleProgressBarMini"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_5"
android:background="@drawable/shape_progressbar_mini"
android:max="100"
android:progress="60" />
</LinearLayout>
<ImageView
android:id="@+id/ivDel"
android:layout_width="@dimen/dp_25"
android:layout_height="@dimen/dp_25"
android:src="@drawable/delete_round"
android:layout_alignParentRight="true"/> </RelativeLayout>
 List<LoadFileVo> fileList = new ArrayList<>();
LoadPicAdapter adapter = null; //这里使用ButterKnife
@BindView(R.id.rvPic)
RecyclerView rvPic; @BindView(R.id.tvNum)
TextView tvNum; //初始化Adapter
//设置图片选择的接口
private void initAdapter() {
fileList.add(new LoadFileVo());
adapter = new LoadPicAdapter(this, fileList,8);
rvPic.setAdapter(adapter);
rvPic.setLayoutManager(new GridLayoutManager(this, 3));
adapter.setListener(new LoadPicAdapter.OnItemClickListener() {
@Override
public void click(View view, int positon) {
if (fileList.size()>8){
showShortToast("一次最多上传8张图片!");
}else {
selectPic(); //选择添加图片方法
} } @Override
public void del(View view) {
tvNum.setText((fileList.size()-1)+"/8");
}
});
}

《核心代码》

 String mPhtotPath;
Uri uriImage;
File mPhotoFile = null; //选择图片
private void selectPic() { //动态请求权限,除此之外还需进行Androidmanifest.xml中进行请求 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
1);
} final CharSequence[] items = {"相册", "拍照"};
AlertDialog.Builder dlg = new AlertDialog.Builder(EndLoadMstActivity.this);
dlg.setTitle("添加图片");
dlg.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
// 这里item是根据选择的方式,
if (item == 0) {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, 0);
} else {
try {
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
mPhtotPath = getSDPath() + "/" + getPhotoFileName();
mPhotoFile = new File(mPhtotPath);
if (!mPhotoFile.exists()) {
mPhotoFile.createNewFile();
}
// uriImage = FileProvider.getUriForFile(EndLoadMstActivity.this, getPackageName() + ".provider", createImageFile()); uriImage = FileProvider.getUriForFile(EndLoadMstActivity.this, "com.ahbcd.app.tms.provider", mPhotoFile);
Log.i("TAG", "onClick: "+mPhtotPath+"---------" + getPackageName() + ".provider");
// uriImage = Uri.fromFile(mPhotoFile);以上一句代替解决相机兼容问题
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uriImage); startActivityForResult(intent, 1); } catch (Exception e) {
e.printStackTrace();
}
}
}
}).create();
dlg.show();
} public String getSDPath() {
File sdDir = null;
boolean sdCardExsit = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
if (sdCardExsit) {
sdDir = Environment.getExternalStorageDirectory();
}
return sdDir.toString();
} private String getPhotoFileName() {
Date date = new Date(System.currentTimeMillis());
SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyyMMdd_HHmmss");
return dateFormat.format(date) + ".jpg";
}

注:这里需要在Android中配置一个proveder 具体请参考 Android 系统7.0以上调用相机兼容问题

《获取返回的图片》

 //重写onActivityResult方法
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2; //图片宽高都为原来的二分之一,即图片为原来的四分之一
Bitmap bitmap = BitmapFactory.decodeFile(mPhtotPath, options);
if (bitmap != null) {
if (uriImage != null) {
saveUritoFile(uriImage,1);
} if (!bitmap.isRecycled()) {
bitmap.recycle(); //回收图片所占的内存
System.gc(); //提醒系统及时回收
}
}
}
if (requestCode == 0) {
if (data != null) {
Uri uri = data.getData();
saveUritoFile(uri,0);
}
} } //将Uri图片类型转换成File,BitMap类型
//在界面上显示BitMap图片,以防止内存溢出
//上传可选择File文件上传 private void saveUritoFile(Uri uriImage,int type) {
Bitmap photoBmp = null; if (uriImage != null) {
try {
// photoBmp = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uriImage);
// ByteArrayOutputStream fos = new ByteArrayOutputStream();
// photoBmp.compress(Bitmap.CompressFormat.JPEG, 80, fos);
//以上代码压缩不行,还是会造成内存溢出 BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2; //图片宽高都为原来的二分之一,即图片为原来的四分之一
photoBmp = BitmapFactory.decodeStream(this.getContentResolver()
.openInputStream(uriImage), null, options); File file = new File("");
if (type==0){
file = FileParseUtils.getFileByUri(this, uriImage); }else {
if (mPhotoFile!=null){
file = mPhotoFile;
} }
// File file = new File("");
// try {
// file = new File(new URI(uriImage.toString()));
// } catch (URISyntaxException e) {
// e.printStackTrace();
// }
fileList.add(new LoadFileVo(file, false, 0, photoBmp));
tvNum.setText((fileList.size()-1)+"/8");
if (fileList.size()>8){ //判断时候达到最大数量,如果达到最大数量,则去掉前面的加号
fileList.remove(0);
} adapter.notifyDataSetChanged(); } catch (IOException e) {
e.printStackTrace();
Log.i("TAG", "saveUritoFile: ---------压缩图片异常!");
} } }

图片上传到后台OKhttp

 //一张张图片轮流上传
public void netUpload(int i, final String joData) {//用jsonOject方式转string传递其他参数
try { if (!isRequestHttp) {
isRequestHttp = true;
final int finalI = i;
enterEnable(false); if (fileList.get(finalI).isUpload()) {
netUpload(finalI + 1, joData);
} else { RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("mstjson",msg) //其他信息
.addFormDataPart("file", file.getName(),
RequestBody.create(MediaType.parse("application/octet-stream"), file))//文件
.build();
Request request = new Request.Builder()
.url(uploadPic---这里是图片上传的地址).post(requestBody)
.build();
okHttpClient.newCall(request).enqueue(new UICallBack() {
@Override
public void onFailureUI(Call call, IOException e) {
showShortToast("连接服务器失败");
isRequestHttp = true;
enterEnable(true); } @Override
public void onResponseUI(Call call, Response response) {
try { isRequestHttp = false; String result = response.body().string();
Utils.log("上传图片结果:" + result); if (!response.isSuccessful()) {
Utils.log("响应失败:" + response.code());
showShortToast("响应失败:" + response.code());
enterEnable(true); return;
}
if (result.equals("{}")) {
showShortToast("获取服务端数据为空");
enterEnable(true); return;
}
JSONObject jsonObject = new JSONObject(result);
if (jsonObject.getString("IsError").equals("true")) {
showShortToast(jsonObject.getString("ErrMsg"));
enterEnable(true); } else {
String Data = jsonObject.getString("Data");
fileList.get(finalI).setPg(100);
fileList.get(finalI).setUpload(true);
adapter.notifyDataSetChanged(); if (finalI == fileList.size() - 1) {
showShortToast("上传成功!"); btnEnter.setText("已上传"); } else {
netUpload((finalI + 1), joData);
} }
} catch (Exception e) {
isRequestHttp = true;
hideLoadingDialog();
showShortToast("上传凭证发生异常!");
LogToFile.e("上传凭证发生异常," + e);
enterEnable(true); }
}
}); }
}
} catch (Exception e) {
isRequestHttp = true;
hideLoadingDialog(); showShortToast("上传图片请求异常!");
LogToFile.e("上传图片请求异常," + e);
enterEnable(true); }
} //用来提示用户文件上传的情况。同时也是避免同时反复操作
public void enterEnable(boolean isEnabled) {
if (isEnabled) {
btnEnter.setText("重新上传");
btnEnter.setEnabled(true);
btnEnter.setBackgroundResource(R.drawable.selecter_button);
btnEnter.setTextColor(getResources().getColor(R.color.inButtonText)); } else {
btnEnter.setText("正在上传···");
btnEnter.setEnabled(false);
btnEnter.setBackgroundResource(R.drawable.buttonshap);
btnEnter.setTextColor(getResources().getColor(R.color.outButtonText));
}
}