【目录】

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

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

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

一、相关知识

①Android权限申请

②网络访问框架OKHttp

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

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

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

二、效果展示

二、代码

①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));
}
}

Android 上传图片到服务器 okhttp一的更多相关文章

  1. Android 上传图片到服务器二--------调用相机7.0以上权限问题

    [目录] (一)上传图片到服务器一 ---------------------------------Android代码 (二)上传图片到服务器二--------------------------- ...

  2. Android上传图片到服务器

    一.android需要导入异步请求的jar包 AsyncHttpClient  public static void reg(final Context cont,Bitmap photodata,S ...

  3. android 上传图片到服务器Tomcat(Struts2)

    在做android开发的时候,有时你会用到图片的上传功能,在我的android项目中,我是选中图片,点击上传多张图片 android客户端上传图片部分的代码如下: package com.exampl ...

  4. android上传图片至服务器

    本实例实现了android上传手机图片至服务器,服务器进行保存 服务器servlet代码publicvoid doPost(HttpServletRequest request, HttpServle ...

  5. Android上传图片到服务器,服务端利用.NET WCFRest服务读取文件的解决方案

    在项目中遇到要将Android设备拍摄的照片上传的服务器,将文件保存在服务器本地的文件夹中,数据库中保存的是图片文件名.整个上传是将图片生成二进制流通过HTTP请求上传到服务端,服务端是基于.NET环 ...

  6. 通过android 客户端上传图片到服务器

    昨天,(在我的上一篇博客中)写了通过浏览器上传图片到服务器(php),今天将这个功能付诸实践.(还完善了服务端的代码) 不试不知道,原来通过android 向服务端发送图片还真是挺麻烦的一件事. 上传 ...

  7. Java服务器对外提供接口以及Android端向服务器请求数据

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5056780.html 讲解下java服务器是如何对移动终端提供接口的,以什么数据格式提供出去,移动端又是怎么 ...

  8. Android使用RxJava+Retrofit2+Okhttp+MVP练习的APP

    Android使用RxJava+Retrofit2+Okhttp+MVP练习的APP 项目截图     这是我的目录结构 五步使用RxJava+Retrofit2+Okhttp+RxCache 第一步 ...

  9. okhttputils【 Android 一个改善的okHttp封装库】使用(一)

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 本文使用的OKHttp封装库是张鸿洋(鸿神)写的,因为在项目中一直使用这个库,所以对于一些常用的请求方式都验证过,所以特此整理下. ...

随机推荐

  1. css基础--深入理解弹性盒flex布局

    欢迎访问我的个人博客:http://www.xiaolongwu.cn 1. 前言 flex弹性盒,是一种布局方式,当页面需要适应不同的屏幕大小以及设备类型时,它依然能确保元素 拥有更恰当的排布行为, ...

  2. Spring Boot实战笔记(八)-- Spring高级话题(条件注解@Conditional)

    一.条件注解@Conditional 在之前的学习中,通过活动的profile,我们可以获得不同的Bean.Spring4提供了一个更通用的基于条件的Bean的创建,即使用@Conditional注解 ...

  3. PAT1011:World Cup Betting

    1011. World Cup Betting (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Wit ...

  4. IntelliJ IDEA中 todo的使用

    在代码的注释部分加入TODO 大小写忽略,如下图所示 查看项目中有哪些待办项,所下图所示

  5. Python初级教程

    Python语言的特点 优点: - 简单 - 易学 - 免费,开源 - 高层语言 - 可移植性(可再多平台运行) - 解释性(不需要编译,可直接运行) - 面向对象 - 可扩展性(缺点:运行效率相对较 ...

  6. Java 面试知识点解析(五)——网络协议篇

    前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...

  7. How to set spring boot active profiles with maven profiles

    In the previous post you could read about separate Spring Boot builds for a local development machin ...

  8. toString()方法详解

    在类型转换中,经常用到方法valueOf()和toString(),上一篇讲了valueOf()方法,这一篇来说说toString()方法.toSting()方法返回返回对象的字符串表现. [1]基本 ...

  9. linux常用命令:创建文件和文件夹

    1.首先说一下touch 创建文件的命令,touch可以用于创建二进制文件,用法非常简单.用法:touch+文件名,touch与文件名之间一定要有空格.图中先用之前分享过的命令来查看一下/目录下面有多 ...

  10. Java 学习笔记 (七) Java 参数

    head first java page 74 实参: argument 形参: parameter 方法会运用形参, 调用的一方会传入实参. 实参是传给方法的值.当它传入方法后就成了形参, 参数跟局 ...