【目录】

(一)上传图片到服务器一 ---------------------------------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. nginx常用配置系列-虚拟主机

    本来准备详尽的出一份nginx配置讲解,但nginx功能配置繁多,平常使用中使用最多的一般有: 1. 虚拟主机配置 2. HTTPS配置 3. 静态资源处理 4. 反向代理 ============= ...

  2. PAT1032: Sharing (25)

    1032. Sharing (25) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue To store Engl ...

  3. 利用AOP实现SqlSugar自动事务

    先看一下效果,带接口层的三层架构: BL层: public class StudentBL : IStudentService { private ILogger mLogger; private r ...

  4. SSM-SpringMVC-02:SpringMVC最简单的小案例

     ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 咱们这个案例做什么? 就是用处理器代替Servlet处理请求 开发步骤: 1.引入jar包 <!--单 ...

  5. Azure Go Management SDK 中国版使用示例

    简介 刚学习go几天,尝试调用Azure的SDK进行管理API的操作,基本思路是基于注册的AD Application信息生成token,然后再使用Token生成serviceClient,然后再进行 ...

  6. HQL: The Hibernate Query Language

    Chapter 14. HQL: The Hibernate Query Language 14.1. Case Sensitivity 14.2. The from clause 14.3. Ass ...

  7. bzoj3598 [Scoi2014]方伯伯的商场之旅

    数位dp,我们肯定枚举集合的位置,但是如果每次都重新dp的话会很麻烦,所以我们可以先钦定在最低位集合,dp出代价,然后再一步步找到正确的集合点,每次更改的代价也dp算就好了. #include < ...

  8. 利用FT232实现USB转串口

    FT232B数据手册:http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232BL_BQ.pdf 常用的USB转串口的芯片有F ...

  9. hystrix基本配置项(2)

    ①配置HystrixCommand HystxixCommand支持如下的配置: GroupKey:该命令属于哪一个组,可以帮助我们更好的组织命令. CommandKey:该命令的名称 ThreadP ...

  10. SAP GUI个性化设置

    大概从GUI730开始,GUI品牌化一直不被默认支持,在GUI设置选项里处于灰色状态,如下图: 不过用户还是可以修改注册表的方式来进行修改,让它可以设置! 首先运行Regedit,在目录:HKEY_L ...