Android 上传图片到服务器 okhttp一
【目录】
(一)上传图片到服务器一 ---------------------------------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一的更多相关文章
- Android 上传图片到服务器二--------调用相机7.0以上权限问题
[目录] (一)上传图片到服务器一 ---------------------------------Android代码 (二)上传图片到服务器二--------------------------- ...
- Android上传图片到服务器
一.android需要导入异步请求的jar包 AsyncHttpClient public static void reg(final Context cont,Bitmap photodata,S ...
- android 上传图片到服务器Tomcat(Struts2)
在做android开发的时候,有时你会用到图片的上传功能,在我的android项目中,我是选中图片,点击上传多张图片 android客户端上传图片部分的代码如下: package com.exampl ...
- android上传图片至服务器
本实例实现了android上传手机图片至服务器,服务器进行保存 服务器servlet代码publicvoid doPost(HttpServletRequest request, HttpServle ...
- Android上传图片到服务器,服务端利用.NET WCFRest服务读取文件的解决方案
在项目中遇到要将Android设备拍摄的照片上传的服务器,将文件保存在服务器本地的文件夹中,数据库中保存的是图片文件名.整个上传是将图片生成二进制流通过HTTP请求上传到服务端,服务端是基于.NET环 ...
- 通过android 客户端上传图片到服务器
昨天,(在我的上一篇博客中)写了通过浏览器上传图片到服务器(php),今天将这个功能付诸实践.(还完善了服务端的代码) 不试不知道,原来通过android 向服务端发送图片还真是挺麻烦的一件事. 上传 ...
- Java服务器对外提供接口以及Android端向服务器请求数据
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5056780.html 讲解下java服务器是如何对移动终端提供接口的,以什么数据格式提供出去,移动端又是怎么 ...
- Android使用RxJava+Retrofit2+Okhttp+MVP练习的APP
Android使用RxJava+Retrofit2+Okhttp+MVP练习的APP 项目截图 这是我的目录结构 五步使用RxJava+Retrofit2+Okhttp+RxCache 第一步 ...
- okhttputils【 Android 一个改善的okHttp封装库】使用(一)
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 本文使用的OKHttp封装库是张鸿洋(鸿神)写的,因为在项目中一直使用这个库,所以对于一些常用的请求方式都验证过,所以特此整理下. ...
随机推荐
- 可能是史上最全的机器学习和Python(包括数学)速查表
新手学习机器学习很难,就是收集资料也很费劲.所幸Robbie Allen从不同来源收集了目前最全的有关机器学习.Python和相关数学知识的速查表大全.强烈建议收藏! 机器学习有很多方面. 当我开始刷 ...
- SSM-SpringMVC-27:SpringMVC类型转换之日期类型初步
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本案例是上面的异常和日期类型转换结合的一个小小的Demo 案例开始 1.自定义处理器和处理方法: packag ...
- Java开源生鲜电商平台-搜索模块的设计与架构(源码可下载)
Java开源生鲜电商平台-搜索模块的设计与架构(源码可下载) 说明:搜索模块针对的是买家用户,在找菜品找的很费劲下的一种查询方面.目前也是快速的检索商品. 对于移动端的APP买家用户而言,要求的速度在 ...
- 你不知道的JavaScript--Item3 隐式强制转换
JavaScript的数据类型分为六种,分别为null,undefined,boolean,string,number,object. object是引用类型,其它的五种是基本类型或者是原始类型.我们 ...
- map和flatmap的区别+理解、学习与使用 Java 中的 Optional
转自:map和flatmap的区别 对于stream, 两者的输入都是stream的每一个元素,map的输出对应一个元素,必然是一个元素(null也是要返回),flatmap是0或者多个元素(为n ...
- 字符串匹配KMP算法的讲解C++
转自http://blog.csdn.net/starstar1992/article/details/54913261 也可以参考http://blog.csdn.net/liu940204/art ...
- Linux服务器安装Oracle服务端总结
摘要: 通过ssh远程连接linux服务器,上传Oracle11g的安装包,在无图形化界面的情况,安装Oracle服务器端.本例中linux服务器系统为CentOS6.5. #环境设置 1.检查服务器 ...
- 【codeforces 698C】LRU
题目链接: http://codeforces.com/problemset/problem/698/C 题目大意: n个物品,k个格子,第i个物品每次被选取的概率为$p_{i}$,如果格子里没有该物 ...
- bzoj 1592 dp
就是dp啊 f[i][j]表示到第i位,最后一位高度是j的最小花费 转移::f[i][j]=minn(f[i-1][k])+abs(a[i]-num[j]);(k<=j) #include< ...
- bzoj 1076 奖励关 状压+期望dp
因为每次选择都是有后效性的,直接dp肯定不行,所以需要逆推. f[i][j]表示从第i次开始,初始状态为j的期望收益 #include<cstdio> #include<cstrin ...