第二阶段冲刺五
今天主要完成的任务:客户端上传文件到服务器
遇到的困难:图片上传的数量不确定,有时会为空,而okhttputils框架不能上传空文件
解决办法:判断文件是否为空,并采用HashMao方式进行图片的储存
源程序代码:
Record.java
package com.itheima.network.fragment; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.Button; import android.widget.EditText; import android.widget.GridView; import android.widget.ImageView; import android.widget.RadioGroup; import android.widget.SimpleAdapter; import android.widget.SimpleAdapter.ViewBinder; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import com.itheima.network.R; import com.itheima.network.func_reference.MyDialog; import com.itheima.network.store.FindUserId; import com.jph.takephoto.app.TakePhoto; import com.jph.takephoto.app.TakePhotoImpl; import com.jph.takephoto.compress.CompressConfig; import com.jph.takephoto.model.CropOptions; import com.jph.takephoto.model.InvokeParam; import com.jph.takephoto.model.TContextWrap; import com.jph.takephoto.model.TResult; import com.jph.takephoto.permission.InvokeListener; import com.jph.takephoto.permission.PermissionManager; import com.jph.takephoto.permission.TakePhotoInvocationHandler; import com.zhy.http.okhttp.OkHttpUtils; import com.zhy.http.okhttp.callback.StringCallback; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Set; import okhttp3.Call; public class Record extends Fragment implements MyDialog.OnButtonClickListener, AdapterView.OnItemClickListener, TakePhoto.TakeResultListener, InvokeListener { private MyDialog dialog;// 图片选择对话框 public static final int NONE = 0; public static final int PHOTOHRAPH = 1;// 拍照 public static final int PHOTOZOOM = 2; // 缩放 public static final int PHOTORESOULT = 3;// 结果 public static final String IMAGE_UNSPECIFIED = "image/*"; private GridView gridView; // 网格显示缩略图 private final int IMAGE_OPEN = 4; // 打开图片标记 private String pathImage; // 选择图片路径 private Bitmap bmp; // 导入临时图片 private ArrayList<HashMap<String, Bitmap>> imageItem; private SimpleAdapter simpleAdapter; // 适配器 private EditText note; // 笔记文本 private EditText title; // 标题文本 private EditText kemu; //学科 private Button handin; // 上传按钮 private RadioGroup rg; // 单选按钮组 private boolean judge; // 判定公开/私有 private View mview; private Context mContext; TakePhoto takePhoto; InvokeParam invokeParam; String imagePath; File file; Uri uri; int size; CropOptions cropOptions; Bitmap bitmap; File test; @SuppressLint("SourceLockedOrientationActivity") @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view=View.inflate(getActivity(), R.layout.fragment_record,null); getTakePhoto().onCreate(savedInstanceState); mview=view; mContext=view.getContext(); //上传文件到服务器中 init(); //加载图片与回显 initData(); initEvents(); return view; } public void initEvents() { //各控件初始化 file = new File(mContext.getExternalCacheDir(), System.currentTimeMillis() + ".png"); uri = Uri.fromFile(file); size = Math.min(getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels); cropOptions = new CropOptions.Builder().setOutputX(size).setOutputX(size).setWithOwnCrop(false).create(); } private void init() { //声明 note = mview.findViewById(R.id.Wnote); gridView= mview.findViewById(R.id.gridView); handin = mview.findViewById(R.id.handin); title = mview.findViewById(R.id.title); kemu = mview.findViewById(R.id.kemu); rg = mview.findViewById(R.id.rg); note.setHorizontallyScrolling(true); gridView.setOnItemClickListener(this); dialog = new MyDialog(this.getActivity()); dialog.setOnButtonClickListener(this); // activity中调用其他activity中组件的方法 LayoutInflater layout = this.getLayoutInflater(); View view = layout.inflate(R.layout.layout_select_photo, null); //单选按钮(公开/私有) rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { if(checkedId == R.id.ok){ judge = true; }else{ judge = false; } } }); handin.setOnClickListener(new View.OnClickListener() { //是否公开 private String see_str = ""; //正文 private String note_str = ""; //标题 private String title_str = ""; //学科 private String kemu_str = ""; //年级(传参获取) private String year_str = "3"; FindUserId findUserId=new FindUserId(getActivity()); String user_str=findUserId.ReadUserName(); int userID=findUserId.ReadUserId(); @Override public void onClick(View v) { Map<String,File> fileMap=new HashMap<>(); if(judge){ see_str = "public"; }else{ see_str = "private"; } note_str = note.getText().toString(); title_str = title.getText().toString(); kemu_str = kemu.getText().toString(); //图片文件,设定最多上传3张,不包括+号图片。 int pic_i=0; for(HashMap<String, Bitmap> pic:imageItem){ Set<String> set=pic.keySet(); for(String key:set){ if(pic_i==0){ //跳过默认的+号图片 pic_i++; continue; } //取出bitmap,转换成file,上传 else if(pic_i==1){ Bitmap fbm1 = pic.get(key); //设置文件命名前缀部分 String image1user = user_str+"_image1"; //调用方法生成图片文件 File mFile1 = doImage(fbm1,image1user); fileMap.put("image1.png",mFile1); pic_i++; } else if(pic_i==2){ Bitmap fbm2 = pic.get(key); //设置文件命名前缀部分 String image2user = user_str+"_image2"; //调用方法生成图片文件 File mFile2 = doImage(fbm2,image2user); fileMap.put("image2.png",mFile2); pic_i++; } else if(pic_i==3){ Bitmap fbm3 = pic.get(key); //设置文件命名前缀部分 String image3user = user_str+"_image3"; //调用方法生成图片文件 File mFile3= doImage(fbm3,image3user); fileMap.put("image3.png",mFile3); pic_i++; } } } String URL="http://39.101.190.190:8080/CloudNoteServlet/UserServlet"+"?method=uploading&title="+title_str+ "&see="+see_str+"&kemu="+kemu_str+"&userID="+userID; String noteuser = user_str+"_note"; File Notefile = doString(note_str,noteuser); fileMap.put("note.txt",Notefile); Map<String, String> params = new HashMap<>(); params.put("username",user_str); OkHttpUtils.post() .files("files",fileMap) .url(URL) .params(params) .build() .connTimeOut(20000) .writeTimeOut(20000) .readTimeOut(20000) .execute(new StringCallback( ) { @Override public void onError(Call call, Exception e, int id) { Toast.makeText(getActivity(),"上传文件出现异常,请重试"+id,Toast.LENGTH_SHORT).show(); } @Override public void onResponse(String response, int id) { if(response.equals("fail")) { Toast.makeText(getActivity(),"上传文件失败"+id,Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(getActivity(),"上传文件成功"+id,Toast.LENGTH_SHORT).show(); } } }); } }); } private void initData() { /* * 载入默认图片添加图片加号 */ bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_addpic); // 加号 imageItem = new ArrayList<HashMap<String, Bitmap>>(); HashMap<String, Bitmap> map = new HashMap<String, Bitmap>(); map.put("itemImage", bmp); imageItem.add(map); simpleAdapter = new SimpleAdapter(this.getActivity(), imageItem, R.layout.griditem_addpic, new String[] { "itemImage" }, new int[] { R.id.imageView1 }); simpleAdapter.setViewBinder(new ViewBinder() { @Override public boolean setViewValue(View view, Object data, String textRepresentation) { // TODO Auto-generated method stub if (view instanceof ImageView && data instanceof Bitmap) { ImageView i = (ImageView) view; i.setImageBitmap((Bitmap) data); return true; } return false; } }); gridView.setAdapter(simpleAdapter); } //Bitmap转file public File doImage(Bitmap fbitmap, String user) { ByteArrayOutputStream fbaos = new ByteArrayOutputStream(); fbitmap.compress(Bitmap.CompressFormat.JPEG,100,fbaos); int options = 100; //判断是否大于20kb,是则继续压缩 while(fbaos.toByteArray().length/1024>20 &&options>10){ fbaos.reset(); options-=10; fbitmap.compress(Bitmap.CompressFormat.JPEG,options,fbaos); long length = fbaos.toByteArray().length; } SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); Date date = new Date(System.currentTimeMillis()); String filename = user+"_"+format.format(date); String filepath = mContext.getExternalFilesDir(null).toString()+"/CloudNoteImage"; File pathfile = new File(filepath); if(!pathfile.exists()){ pathfile.mkdir(); } File file = new File(filepath,filename+".png"); //注意创建文件,否则会发生文件读取错误 if(!file.exists()){ try{ file.createNewFile(); }catch (IOException e){ e.printStackTrace(); } } try{ FileOutputStream fos = new FileOutputStream(file); try{ fos.write(fbaos.toByteArray()); fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); } }catch (IOException e){ e.printStackTrace(); } return file; } //将正文信息写入txt文件 public File doString(String strwrite, String user){ //取时间 SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); Date date = new Date(System.currentTimeMillis()); //生成文件名 String filename = user+"_"+format.format(date); String filepath =mContext.getExternalFilesDir(null).toString()+"/CloudNoteTXT"; //创建文件 File pathfile = new File(filepath); if(!pathfile.exists()){ pathfile.mkdir(); } File file = new File(filepath,filename+".txt"); if(!file.exists()){ try{ file.createNewFile(); }catch (IOException e){ e.printStackTrace(); } } try{ FileOutputStream outputStream = new FileOutputStream(file); outputStream.write(strwrite.getBytes()); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } return file; } //调用相机 @Override public void camera() { takePhoto.onPickFromCaptureWithCrop(uri, cropOptions); } //调用相册 @Override public void gallery() { takePhoto.onPickFromGalleryWithCrop(uri, cropOptions); } @Override public void cancel() { // TODO Auto-generated method stub dialog.cancel(); } @Override public void onResume() { // TODO Auto-generated method stub super.onResume(); //判定有图片添加 if (!TextUtils.isEmpty(pathImage)) { //bitmap回显 Bitmap addbmp = BitmapFactory.decodeFile(pathImage); //将信息存入Map中 HashMap<String, Bitmap> map = new HashMap<String, Bitmap>(); map.put("itemImage", addbmp); imageItem.add(map); //在griditem_addpic.xml中向imageView1添加图片 simpleAdapter = new SimpleAdapter(this.getActivity(), imageItem, R.layout.griditem_addpic, new String[] { "itemImage" }, new int[] { R.id.imageView1 }); simpleAdapter.setViewBinder(new ViewBinder() { @Override public boolean setViewValue(View view, Object data, String textRepresentation) { // TODO Auto-generated method stub if (view instanceof ImageView && data instanceof Bitmap) { ImageView i = (ImageView) view; i.setImageBitmap((Bitmap) data); return true; } return false; } }); gridView.setAdapter(simpleAdapter); simpleAdapter.notifyDataSetChanged(); // 刷新后释放防止手机休眠后自动添加 pathImage = null; dialog.dismiss(); } } @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) { // TODO Auto-generated method stub if (imageItem.size() == 4&&position==0) { // 第一张为默认图片,点击+号时才判定是否已满 Toast.makeText(this.getActivity(), "图片数3张已满", Toast.LENGTH_SHORT).show(); } else if (position == 0) { // 点击图片位置为+ 0对应0张图片 // 选择图片 dialog.show(); // 通过onResume()刷新数据 } else { dialog(position); } } /* * Dialog对话框提示用户删除操作 position为删除图片位置 */ protected void dialog(final int position) { AlertDialog.Builder builder = new Builder(this.getActivity()); builder.setMessage("确认移除已添加图片吗?"); builder.setTitle("提示"); builder.setPositiveButton("确认", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); imageItem.remove(position); simpleAdapter.notifyDataSetChanged(); } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); } @Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { getTakePhoto().onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data); } @Override public void onSaveInstanceState(@NonNull Bundle outState) { getTakePhoto().onSaveInstanceState(outState); super.onSaveInstanceState(outState); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); //以下代码为处理Android6.0、7.0动态权限所需 PermissionManager.TPermissionType type = PermissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults); PermissionManager.handlePermissionsResult(getActivity(), type, invokeParam, this); } @Override public PermissionManager.TPermissionType invoke(InvokeParam invokeParam) { PermissionManager.TPermissionType type = PermissionManager.checkPermission(TContextWrap.of(this), invokeParam.getMethod()); if (PermissionManager.TPermissionType.WAIT.equals(type)) { this.invokeParam = invokeParam; } return type; } public TakePhoto getTakePhoto() { //获得TakePhoto实例 if (takePhoto == null) { takePhoto = (TakePhoto) TakePhotoInvocationHandler.of(this).bind(new TakePhotoImpl(this, this)); } //设置压缩规则,最大500kb takePhoto.onEnableCompress(new CompressConfig.Builder().setMaxSize(500 * 1024).create(), true); return takePhoto; } @Override public void takeSuccess(final TResult result) { //成功取得照片 test = new File(result.getImage().getOriginalPath()); if(test.exists()){ bitmap = BitmapFactory.decodeFile(result.getImage().getOriginalPath()); // 将图片放入gridview中 HashMap<String, Bitmap> map = new HashMap<String, Bitmap>(); map.put("itemImage", bitmap); imageItem.add(map); simpleAdapter = new SimpleAdapter(this.getActivity(), imageItem, R.layout.griditem_addpic, new String[] { "itemImage" }, new int[] { R.id.imageView1 }); simpleAdapter.setViewBinder(new ViewBinder() { @Override public boolean setViewValue(View view, Object data, String textRepresentation) { // TODO Auto-generated method stub if (view instanceof ImageView && data instanceof Bitmap) { ImageView i = (ImageView) view; i.setImageBitmap((Bitmap) data); return true; } return false; } }); gridView.setAdapter(simpleAdapter); simpleAdapter.notifyDataSetChanged(); dialog.dismiss(); } } @Override public void takeFail(TResult result, String msg) { //取得失败 Toast.makeText(mContext,"设置失败",Toast.LENGTH_SHORT).show(); } @Override public void takeCancel() { //取消 } }
运行截图: