package com.fxy.common; import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Handler; import android.os.Message; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.Gravity; import android.view.View; import android.view.WindowManager; import android.widget.PopupWindow; import android.widget.TextView; import android.widget.Toast; import com.alibaba.sdk.android.oss.internal.OSSAsyncTask; import com.elvishew.xlog.XLog; import com.fxy.R; import com.fxy.adapter.GridImageAdapter; import com.fxy.baselibrary.util.DateUtil; import com.fxy.baselibrary.util.JsonUtil; import com.fxy.baselibrary.util.RxTimeTool; import com.fxy.bean.ActionBean; import com.fxy.constant.SPCache; import com.fxy.net.MyDialogCallback; import com.fxy.net.Urls; import com.fxy.realm.AsyncUploadRealm; import com.fxy.view.FullyGridLayoutManager; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.luck.picture.lib.PictureSelector; import com.luck.picture.lib.config.PictureConfig; import com.luck.picture.lib.config.PictureMimeType; import com.luck.picture.lib.entity.LocalMedia; import com.luck.picture.lib.permissions.Permission; import com.luck.picture.lib.permissions.RxPermissions; import com.lzy.okgo.OkGo; import com.lzy.okgo.model.Response; import org.greenrobot.eventbus.EventBus; import org.json.JSONObject; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import io.reactivex.functions.Consumer; import io.realm.Realm; import io.realm.RealmResults; public class AsyncUpload { private final Activity mActivity; private final Context mContext; private int maxSelectNum = 9; private GridImageAdapter adapter; private final RecyclerView mRecyclerView; private PopupWindow pop; private boolean onlyCamera = false; private boolean isCompress = false; private int compressQuality = 100;//默认值 private int minimumCompressSize = 100;//最小压缩 //资源类型 private int pictureType=1; private String uploadType = ""; //文件上传类型 protected String fileKey = ""; //通知地址 private String notifyUrl = ""; //唯一标识 private String uniqueTag = ""; //通知地址 private HashMap notifyParam = new HashMap<>(); private HashMap limitOperate = new HashMap<>(); protected Realm mRealm; private List awaitUploadList=new ArrayList<>(); // private List selectList = new ArrayList<>(); //上传图片路径 private ArrayList ossPhotoList =new ArrayList<>(); private String mPrefix="tally"; //是否停止上传 private String resourceUrl = ""; private String resourceType = ""; private String resourcePrefix = "/fxy"; private OssService ossService; private CosService cosService; //是自动上传 private boolean isAutoUpload = true; private boolean allowUpload = false; public AsyncUpload(Activity activity, RecyclerView rvShowImg, String prefix,String fileKey, String notifyUrl,boolean isAutoUpload){ mActivity = activity; mContext = activity.getBaseContext(); mRecyclerView = rvShowImg; this.fileKey = fileKey; this.mPrefix = prefix; this.notifyUrl = notifyUrl; this.isAutoUpload = isAutoUpload; //自动上传则允许继续上次 this.allowUpload = isAutoUpload; initAdapter(); initData(); } private void initData() { SPCache spCache = SPCache.getInstance(mContext); resourceUrl = spCache.getResourceHost()+"/"; resourceType = spCache.getResourceType(); resourcePrefix = spCache.getResourcePrefix(); mRealm = Realm.getDefaultInstance(); uploadType = mActivity.getClass().getSimpleName(); limitOperate = new HashMap<>(); uniqueTag = this.fileKey+UUID.randomUUID().toString(); } public void setCompress(Boolean isCompress) { this.isCompress = isCompress; } public void setCompress(Boolean isCompress,int compressQuality,int minimumCompressSize) { this.isCompress = isCompress; this.compressQuality = compressQuality; this.minimumCompressSize = minimumCompressSize; } public void setUploadType(String fileKey) { this.fileKey = fileKey; } public void setPictureType(int pictureType){ this.pictureType = pictureType; } public void setOnlyCamera(boolean onlyCamera){ this.onlyCamera = onlyCamera; } public void setMaxSelectNum(int num){ this.maxSelectNum = num; } public void setNotifyParam( HashMap map){ this.notifyParam = map; } //操作限制 public void setLimitOperate(HashMap map){ this.limitOperate = map; } /** * 设置操作类型 * @return */ public String getUploadType() { return fileKey; } public int getAwaitNum(){ RealmResults realmResults = mRealm.where(AsyncUploadRealm.class) .equalTo("isDelete",0) .equalTo("pushStatus",0) .equalTo("uploadType",uploadType) .sort("pushStatus").findAll(); realmResults.load(); return realmResults.size(); } public List getSelectList (){ return selectList; } public List getOssPhotoList (){ return ossPhotoList; } public void emptyRemake(){ selectList.clear(); ossPhotoList.clear(); adapter.clearData(); uniqueTag = this.fileKey+UUID.randomUUID().toString(); } //销毁 public void removeHandler(){ if (uploadHandler!=null){ uploadHandler.removeCallbacksAndMessages(null); } } /** * 获取选中图片 * @param data */ public void getSelectImg (Intent data){ List fileList = PictureSelector.obtainMultipleResult(data); for (int i = 0; i < fileList.size(); i++) { addUploadFile(fileList.get(i)); selectList.add(fileList.get(i)); } adapter.setList(selectList); adapter.notifyDataSetChanged(); //设置自动 if (isAutoUpload){ asyncUpload(); } } public String getUniqueTag(){ return this.uniqueTag; } @SuppressLint("HandlerLeak") private Handler uploadHandler = new Handler() { @Override public void handleMessage(Message msg) { try { //XLog.e(msg); int current = (Integer) msg.arg1; switch (msg.what){ case 0: Toast.makeText(mActivity, "error", Toast.LENGTH_SHORT).show(); break; case 1://失败 if (awaitUploadList.size()>0){ AsyncUploadRealm asyncUploadRealm = awaitUploadList.get(current); awaitUploadList.remove(current); resultUpload(asyncUploadRealm.getId(),0,""); String message = (String) msg.obj; if (!message.isEmpty() && mActivity!=null){ Toast.makeText(mActivity, message, Toast.LENGTH_SHORT).show(); } } break; case 2://成功 //表示数据存在 if (awaitUploadList.size()>0){ AsyncUploadRealm asyncUploadRealm = awaitUploadList.get(current); awaitUploadList.remove(current); resultUpload(asyncUploadRealm.getId(),1,(String) msg.obj); } break; case 3: //设置进度条 EventBus.getDefault().post(new UploadProgressEvent(msg.arg2)); //progressDialog.show(); return; case 4: //获取上传状态 return; default: break; } // 通过接口对象传上传状态 if (uploadChangeListener!=null){ uploadChangeListener.uploadResult(true,fileKey); } } catch (Exception e) { XLog.e(e.getMessage()); e.printStackTrace(); // 通过接口对象传上传状态 if (uploadChangeListener!=null){ uploadChangeListener.uploadResult(false,fileKey); } } } }; // 持有一个接口对象 UploadChangeListener uploadChangeListener; // 状态变化监听 public interface UploadChangeListener { // 回调方法 可以多个 void uploadResult(boolean State, String actionType); void uploadFileKey(String actionType); } // 提供注册事件监听的方法 public void setOnChangeListener(UploadChangeListener uploadChangeListener) { this.uploadChangeListener = uploadChangeListener; } // 调用回调方法 //uploadChangeListener.uploadResult(false); public void filedUpload(int num){ // 例如 LocalMedia 里面返回三种path // 1.media.getPath(); 为原图path // 2.media.getCutPath();为裁剪后path,需判断media.isCut();是否为true // 3.media.getCompressPath();为压缩后path,需判断media.isCompressed();是否为true // 如果裁剪并压缩了,以取压缩路径为准,因为是先裁剪后压缩的 LocalMedia localMedia = awaitUploadList.get(num).getLocalMedia(); String urlPath =localMedia.getPath(); if (isCompress && localMedia.getCompressPath()!=null){ urlPath = localMedia.getCompressPath(); } if (urlPath.isEmpty()){ Message msg = new Message(); msg.obj = "文件路径不存在"; msg.what = 1; uploadHandler.sendMessage(msg); return; } String fileName = ""; String path_prefix = ""; String ossUrl = awaitUploadList.get(num).getOssUrl(); if (!ossUrl.isEmpty()){ // 找到最后一个斜杠的位置 int lastSlashIndex = ossUrl.lastIndexOf('/'); // 如果找到了斜杠,则从斜杠之后的位置开始切割 fileName = ossUrl.substring(lastSlashIndex + 1); path_prefix = ossUrl.substring(0,lastSlashIndex+ 1); }else{ path_prefix = resourcePrefix+"/android/"+mPrefix+"/"+RxTimeTool.getYestoryDate("yyyyMMd")+"/"; String fileSuffix = urlPath.lastIndexOf(".")>-1 ? urlPath.substring(urlPath.lastIndexOf(".")) : ""; fileName = UUID.randomUUID().toString() + fileSuffix; } if (resourceType.equals("tencent")){ if (cosService==null){ cosService = new CosService(mActivity.getBaseContext(),path_prefix); } //new cosThread(urlPath, fileName , num).start(); cosService.cosUpload(urlPath, fileName , num,uploadHandler); }else{ if (ossService ==null){ ossService = new OssService(mActivity,path_prefix); } ossService.ossUpload(urlPath, fileName , num,uploadHandler); //new ossThread(urlPath, fileName , num).start(); } // task.cancel(); // 可以取消任务 // task.waitUntilFinished(); // 可以等待直到任务完成 EventBus.getDefault().post(new UploadProgressEvent(0)); } private void initAdapter() { FullyGridLayoutManager manager = new FullyGridLayoutManager(mActivity, 3, GridLayoutManager.VERTICAL, false); mRecyclerView.setLayoutManager(manager); adapter = new GridImageAdapter(mActivity,mActivity, onAddPicClickListener,pictureType); adapter.setList(selectList); adapter.setSelectMax(maxSelectNum); mRecyclerView.setAdapter(adapter); adapter.setOnItemClickListener(new GridImageAdapter.OnItemClickListener() { @Override public void onItemClick(int position, View v) { if (selectList.size() > 0) { LocalMedia media = selectList.get(position); String pictureType = media.getPictureType(); int mediaType = PictureMimeType.pictureToVideo(pictureType); switch (mediaType) { case 1: // 预览图片 可自定长按保存路径 //PictureSelector.create(MainActivity.this).externalPicturePreview(position, "/custom_file", selectList); PictureSelector.create(mActivity).externalPicturePreview(position, selectList); break; case 2: // 预览视频 PictureSelector.create(mActivity).externalPictureVideo(media.getPath()); break; case 3: // 预览音频 PictureSelector.create(mActivity).externalPictureAudio(media.getPath()); break; } } } }); //回调语音 adapter.setOnAudioListener(new GridImageAdapter.OnAudioListener() { @Override public void onSaveResult(Intent data) { getSelectImg(data); } }); } public GridImageAdapter.onAddPicClickListener onAddPicClickListener = new GridImageAdapter.onAddPicClickListener() { @SuppressLint("CheckResult") @Override public void onAddPicClick() { //获取写的权限 RxPermissions rxPermission = new RxPermissions(mActivity); rxPermission.requestEach(Manifest.permission.WRITE_EXTERNAL_STORAGE) .subscribe(new Consumer() { @Override public void accept(Permission permission) { if (permission.granted) {// 用户已经同意该权限 //第一种方式,弹出选择和拍照的dialog if (limitOperate.containsKey("disabled")){ String message = "暂时无法拍照"; if(limitOperate.containsKey("error")){ message = limitOperate.get("error").toString(); } if ( mActivity!=null){ Toast.makeText(mActivity, message, Toast.LENGTH_SHORT).show(); } return; } if (pictureType==PictureConfig.TYPE_AUDIO){ authAudio(); }else { if (onlyCamera){ //第二种方式,直接进入相册,但是 是有拍照得按钮的 authCamera(); }else{ showPop(); } } } else { Toast.makeText(mContext, "拒绝", Toast.LENGTH_SHORT).show(); } } }); //监听返回当前某个上传类型 if (uploadChangeListener!=null){ uploadChangeListener.uploadFileKey(fileKey); } } }; private void showAlbum() { //参数很多,根据需要添加 PictureSelector.create(mActivity) .openGallery(PictureMimeType.ofImage())// 全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio() .maxSelectNum(maxSelectNum)// 最大图片选择数量 .minSelectNum(1)// 最小选择数量 .imageSpanCount(4)// 每行显示个数 .selectionMode(PictureConfig.MULTIPLE)// 多选 or 单选PictureConfig.MULTIPLE : PictureConfig.SINGLE .previewImage(true)// 是否可预览图片 .isCamera(true)// 是否显示拍照按钮 .isZoomAnim(true)// 图片列表点击 缩放效果 默认true //.setOutputCameraPath("/CustomPath")// 自定义拍照保存路径 .enableCrop(true)// 是否裁剪 .compress(true)// 是否压缩 //.sizeMultiplier(0.5f)// glide 加载图片大小 0~1之间 如设置 .glideOverride()无效 .glideOverride(160, 160)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度 .withAspectRatio(1, 1)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定义 //.selectionMedia(selectList)// 是否传入已选图片 //.previewEggs(false)// 预览图片时 是否增强左右滑动图片体验(图片滑动一半即可看到上一张是否选中) //.cropCompressQuality(90)// 裁剪压缩质量 默认100 //.compressMaxKB()//压缩最大值kb compressGrade()为Luban.CUSTOM_GEAR有效 //.compressWH() // 压缩宽高比 compressGrade()为Luban.CUSTOM_GEAR有效 //.cropWH()// 裁剪宽高比,设置如果大于图片本身宽高则无效 .rotateEnabled(false) // 裁剪是否可旋转图片 //.scaleEnabled()// 裁剪是否可放大缩小图片 //.recordVideoSecond()//录制视频秒数 默认60s .forResult(PictureConfig.CHOOSE_REQUEST);//结果回调onActivityResult code } private void showPop() { View bottomView = View.inflate(mContext, R.layout.layout_bottom_dialog, null); TextView mAlbum = bottomView.findViewById(R.id.tv_album); TextView mCamera = bottomView.findViewById(R.id.tv_camera); TextView mCancel = bottomView.findViewById(R.id.tv_cancel); pop = new PopupWindow(bottomView, -1, -2); pop.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); pop.setOutsideTouchable(true); pop.setFocusable(true); WindowManager.LayoutParams lp = mActivity.getWindow().getAttributes(); lp.alpha = 0.5f; mActivity.getWindow().setAttributes(lp); pop.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { WindowManager.LayoutParams lp = mActivity.getWindow().getAttributes(); lp.alpha = 1f; mActivity.getWindow().setAttributes(lp); } }); pop.setAnimationStyle(R.style.main_menu_photo_anim); pop.showAtLocation(mActivity.getWindow().getDecorView(), Gravity.BOTTOM, 0, 0); View.OnClickListener clickListener = new View.OnClickListener() { @Override public void onClick(View view) { switch (view.getId()) { case R.id.tv_album: //相册 PictureSelector.create(mActivity) .openGallery(PictureMimeType.ofImage()) .maxSelectNum(maxSelectNum) .minSelectNum(1) .imageSpanCount(4) .selectionMode(PictureConfig.MULTIPLE) .compress(isCompress) // 压缩 .cropCompressQuality(compressQuality)// 裁剪压缩质量 默认100 .minimumCompressSize(minimumCompressSize) //最新压缩图片 .forResult(PictureConfig.CHOOSE_REQUEST); break; case R.id.tv_camera: //拍照 PictureSelector.create(mActivity) .openCamera(PictureMimeType.ofImage()) //只需要拍照 //.selectionMode(PictureConfig.SINGLE) //.isCamera(true) .compress(isCompress) // 压缩 .cropCompressQuality(compressQuality)// 裁剪压缩质量 默认100 .minimumCompressSize(minimumCompressSize) //最新压缩图片 .forResult(PictureConfig.CHOOSE_REQUEST); break; case R.id.tv_cancel: //取消 //closePopupWindow(); break; } closePopupWindow(); } }; mAlbum.setOnClickListener(clickListener); mCamera.setOnClickListener(clickListener); mCancel.setOnClickListener(clickListener); } /** * 外部直接调取拍照接口 */ public void authCamera(){ //拍照 PictureSelector.create(mActivity) .openCamera(PictureMimeType.ofImage()) //只需要拍照 //.selectionMode(PictureConfig.SINGLE) //.isCamera(true) //.compressMaxKB()//压缩最大值kb compressGrade()为Luban.CUSTOM_GEAR有效 .compress(isCompress) // 压缩 .cropCompressQuality(compressQuality)// 裁剪压缩质量 默认100 .minimumCompressSize(minimumCompressSize) //最新压缩图片 .forResult(PictureConfig.CHOOSE_REQUEST); //监听返回当前某个上传类型 if (uploadChangeListener!=null){ uploadChangeListener.uploadFileKey(fileKey); } } /** * 自动打开录音 */ public void authAudio(){ // 自带音频 PictureSelector.create(mActivity) .openCamera(PictureMimeType.ofAudio()) //只需要音频 .selectionMode(PictureConfig.TYPE_AUDIO) .compress(isCompress) // 压缩 .forResult(PictureConfig.CHOOSE_REQUEST); //监听返回当前某个上传类型 if (uploadChangeListener!=null){ uploadChangeListener.uploadFileKey(fileKey); } } /** * 关闭弹窗 */ public void closePopupWindow() { if (pop != null && pop.isShowing()) { pop.dismiss(); pop = null; } } //存储数据问题 private void asyncUpload(){ if (!getIsNetwork()){ //无网络时在请求检查是否有网络 return; } if (awaitUploadList==null || awaitUploadList.size()==0){ RealmResults realmResults = mRealm.where(AsyncUploadRealm.class) .equalTo("isDelete",0) .equalTo("pushStatus",0) // .equalTo("notifyKey",fileKey) .equalTo("uploadType",uploadType) .sort("pushStatus").findAll(); realmResults.load(); awaitUploadList.addAll(realmResults); } if (awaitUploadList.size()>0){ filedUpload(0); } } //取消任务 public void taskCancel(){ } public void setStartUpload(){ allowUpload = true; asyncUpload(); } public void setStopUpload(){ if(ossService !=null){ ossService.taskCancel(); } allowUpload = false; EventBus.getDefault().post(new UploadProgressEvent(0)); } private void addUploadFile(LocalMedia localMedia){ String realmId = UUID.randomUUID().toString(); String scan_date = DateUtil.getCurDateStr(DateUtil.FORMAT_YMDHMS); //同步操作写法一: mRealm.beginTransaction(); //会创建对象和user表 AsyncUploadRealm takePhotosRealm = mRealm.createObject(AsyncUploadRealm.class,realmId); Gson gson = new Gson(); String localMediaStr = gson.toJson(localMedia); takePhotosRealm.setLocalMediaStr(localMediaStr); takePhotosRealm.setOssUrl(""); takePhotosRealm.setScanDate(scan_date); takePhotosRealm.setUploadType(uploadType); takePhotosRealm.setNotifyKey(fileKey); takePhotosRealm.setNotifyParam(gson.toJson(notifyParam)); takePhotosRealm.setNotifyUrl(notifyUrl); takePhotosRealm.setUniqueTag(uniqueTag); String path_prefix = resourcePrefix+"/android/"+mPrefix+"/"+RxTimeTool.getYestoryDate("yyyyMMd")+"/"; String urlPath = isCompress && localMedia.getCompressPath()!=null ? localMedia.getCompressPath() : localMedia.getPath(); String fileSuffix = urlPath.lastIndexOf(".")>-1 ? urlPath.substring(urlPath.lastIndexOf(".")) : ""; String fileName = UUID.randomUUID().toString() + fileSuffix; takePhotosRealm.setOssUrl(path_prefix+fileName); ossPhotoList.add("/"+path_prefix+fileName); // Date date = new Date(); takePhotosRealm.setCreateTime(date.getTime()); takePhotosRealm.setPushStatus(0); //提交事务,操作就被执行 mRealm.commitTransaction(); } /** * 设置是否完成 * @param realmId * @param isFinish */ private void setIsFinish(String realmId,Integer isFinish){ //更新值 mRealm.beginTransaction(); AsyncUploadRealm myObject = mRealm.where(AsyncUploadRealm.class).equalTo("id",realmId).findFirst(); myObject.setIsFinish(isFinish); mRealm.commitTransaction(); } /** * 上传结果 * @param tmpRealmId String * @param status Integer * @param photoPath String */ private void resultUpload(String tmpRealmId,Integer status,String photoPath){ if (tmpRealmId!=null && !tmpRealmId.isEmpty()){ int rePush = 0; //遍历删除 if (awaitUploadList.size()>0){ for (int i=0;i4 ? 1 : 0; } //更新值 mRealm.beginTransaction(); AsyncUploadRealm myObject = mRealm.where(AsyncUploadRealm.class).equalTo("id",tmpRealmId).findFirst(); assert myObject != null; myObject.setPushStatus(pushStatus); if (pushStatus == 1){ myObject.setIsFinish(pushStatus); } myObject.setOssUrl(photoPath); if (getIsNetwork() && status==0 ){ myObject.setRePush(myObject.getRePush()+1); } mRealm.commitTransaction(); } //可以允许上传 if (allowUpload){ //上传完,继续执行 asyncUpload(); } } //异步通知结果 private void asyncNotify(AsyncUploadRealm myObject){ try { JSONObject jsonObject = new JSONObject(myObject.getNotifyParam()); jsonObject.put(myObject.getNotifyKey(),myObject.getOssUrl()); jsonObject.put("realm_id",myObject.getId()); jsonObject.put("unique_tag",myObject.getUniqueTag()); final String tmpRealmId1 = myObject.getId(); OkGo.post(myObject.getNotifyUrl()).upJson(jsonObject) .execute(new MyDialogCallback(mContext, true, false) { @Override public void onSuccess(Response response) { super.onSuccess(response); try { ActionBean bean = JsonUtil.getObject(response.body(), ActionBean.class); if(bean.code == 1){ setIsFinish(tmpRealmId1,1); } } catch (Exception e) { e.printStackTrace(); XLog.e("回传图片地址错误",e.getMessage()); setIsFinish(tmpRealmId1,2); } } }); } catch (Exception e) { e.printStackTrace(); XLog.e("异步通知"+e.getMessage()); } } /** * 获取当前网络 * @return Boolean */ private Boolean getIsNetwork(){ boolean isNetwork = false; try { if (mActivity==null){ return isNetwork; } ConnectivityManager connectivityManager = (ConnectivityManager) mActivity.getSystemService(Context.CONNECTIVITY_SERVICE); if (connectivityManager == null) { XLog.d( "无法获取ConnectivityManager实例"); return isNetwork; } NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); if (networkInfo != null) { XLog.d( "当前网络状态:" + networkInfo.getState()); isNetwork = true; } else { XLog.d( "当前无网络连接"); isNetwork = false; } } catch (Exception e) { e.printStackTrace(); } return isNetwork; } }