手机端发帖,多张图片上传是个问题.最近重构项目代码,正好碰到这个,这里把解决的方案整理,以备后用.

方案原理:

  1. 创建上传任务表, 帖子内容发布的时候将数据存放到任务表中,并传递数据到service中.
  2. 启动服务,遍历任务表中内容,创建上传任务.如果接收到上传任务,创建任务,加入上传任务队列中.(上传任务顺序可以自定义)
  3. 包含图片的上传任务.开启多线程压缩(使用线程池管理压缩线程),压缩完毕后返回压缩后临时图片位置
  4. 上传成功后,根据返回值处理临时目录, 删除任务表中上传成功任务

Activity 和 Service 之间的数据通信使用的是 EventBus
数据上传使用的的是retrofit + okHttp


不多说,直接上代买

上传服务:


public class UploadService extends Service {private static final String TAG = UploadService.class.getSimpleName();private ExecutorService executorService = Executors.newFixedThreadPool(3);private ExecutorService singleTaskService = Executors.newSingleThreadExecutor();// 按顺序处理任务@Overridepublic void onCreate() {super.onCreate();EventBus.getDefault().register(this);LogUtils.e(TAG, "UploadService is onCreate");}/*** 通过EventBus接受传递过来的数据** @param submitPostBena*/@Subscribepublic void receiveUploadData(SubmitPostBena submitPostBena) {createSubmitTask(submitPostBena);}/*** 查询任务表中是否有数据   (未实现任务表)*/private void queryTaskTable() {//mTaskCount = queryFromTable().size();//查询数据库//List<SubmitPostBena> postsBeen = new ArrayList<>();//for (int i = 0; i < postsBeen.size(); i++) { //循环创建提交帖子任务//    createSubmitTask(postsBeen.get(i));//}}/*** 创建提交帖子数据任务** @param bean 要提交的提子数据*/private void createSubmitTask(SubmitPostBena bean) {singleTaskService.execute(new TaskRunnable(bean));}/*** 任务*/private class TaskRunnable implements Runnable {private CountDownLatch countDownLatch;private List<String> newPath = Collections.synchronizedList(new ArrayList<String>());//返回值private List<String> faile = Collections.synchronizedList(new ArrayList<String>());//提交失败返回值private SubmitPostBena bean;TaskRunnable(SubmitPostBena bean) {this.bean = bean;countDownLatch = new CountDownLatch(bean.getImagePaths().size());//这地方有个小坑,countDown 的数量一定要和压缩图片的数量一致}@Overridepublic void run() {synchronized (UploadService.class) {try {if (bean.isImagePost()) {LogUtils.e(TAG, "开始任务处理图片压缩");CompressTask(countDownLatch, newPath, bean.getImagePaths()); //处理压缩问题countDownLatch.await();bean.setImagePaths(newPath);LogUtils.e(TAG, "压缩完成");}submitData(bean, faile); //提交} catch (Exception e) {e.printStackTrace();}}}}/*** 创建处理压缩任务** @param countDownLatch 线程同步辅助工具,用于记录图片压缩线程全部执行完毕后通知提交线程提交* @param newPath        处理过后的图片的地址* @param imagePath      原始图片地址*/private void CompressTask(CountDownLatch countDownLatch, List<String> newPath, List<String> imagePath) {for (int i = 0; i < imagePath.size(); i++) {String path = imagePath.get(i);executorService.execute(new CompressRunnable(countDownLatch, path, newPath));}}/*** 压缩任务*/private class CompressRunnable implements Runnable {private String filePath;private List<String> newPath;private CountDownLatch countDownLatch;/*** 压缩图片处理** @param countDownLatch 线程同步辅助类,用于基数当前线程是否完成,如果完成,线程数量减少1* @param imagePath      要处理图片的路径* @param newPath        处理后图片的新路径*/CompressRunnable(CountDownLatch countDownLatch, String imagePath, List<String> newPath) {this.newPath = newPath;this.filePath = imagePath;this.countDownLatch = countDownLatch;}@Overridepublic void run() {Bitmap smallBitmap = BitmapUtils.getSmallBitmap(filePath);String tempPath = BitmapUtils.compressImage(smallBitmap);if (!TextUtils.isEmpty(tempPath)) {newPath.add(tempPath);countDownLatch.countDown();}}}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onDestroy() {super.onDestroy();EventBus.getDefault().unregister(this);LogUtils.e(TAG, "UploadService is onDestroy");executorService.shutdownNow();singleTaskService.shutdownNow();}private void submitData(SubmitPostBena mBean, List<String> faile) {if (SystemUtils.checkNet(this)) {//上传方法}}
}

图片压缩:


public class BitmapUtils {/*** 根据路径获得图片并压缩,返回bitmap用于显示** @param filePath 图片路径* @return*/public static Bitmap getSmallBitmap(String filePath) {final BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(filePath, options);options.inSampleSize = calculateInSampleSize(options, 480, 800);// Calculate inSampleSizeoptions.inJustDecodeBounds = false;// Decode bitmap with inSampleSize setBitmap bitmap = BitmapFactory.decodeFile(filePath, options);return bitmap;}/*** 计算图片的缩放值** @param options* @param reqWidth* @param reqHeight* @return*/public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {final int height = options.outHeight;final int width = options.outWidth;int inSampleSize = 1;if (height > reqHeight || width > reqWidth) {final int heightRatio = Math.round((float) height / (float) reqHeight);final int widthRatio = Math.round((float) width / (float) reqWidth);inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;}return inSampleSize;}public static String compressImage(Bitmap image) {ByteArrayOutputStream baos = new ByteArrayOutputStream();image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中int options = 90;while (baos.toByteArray().length / 1024 > 100) {//循环判断如果压缩后图片是否大于100kb,大于继续压缩baos.reset();//重置baos即清空baosoptions -= 10;image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中if (options < 0) options = 0;}String tempName = UUID.randomUUID().toString().replace("-", "") + ".jpg";File fileDir = new File(Commons.PHOTOCACHE_TEMP);if (!fileDir.exists()) {fileDir.mkdirs();}File file = new File(fileDir, tempName);try {if (file.exists())file.delete();FileOutputStream fos = new FileOutputStream(file);image.compress(Bitmap.CompressFormat.JPEG, 50, fos);fos.flush();fos.close();if (!image.isRecycled()) {image.recycle();}} catch (IOException e) {e.printStackTrace();}LogUtils.e("压缩后图片大小 >>>> ", file.length() + "");return file.getPath();}
}

Android Service后台多线程压缩并提交图片及数据相关推荐

  1. Android Service后台下载 广播(Eventbus)通知并展示

    因为好多项目都会用到比如后台下载apk,下载图片,音视频,这个时候就需要我们用Service进行后台下载了,首先讲一下我的思路一个简单的service后台图片下载展示,我需要创建一个service并注 ...

  2. Android SERVICE后台服务进程的自启动和保持

    Service组件在android开发中经常遇到,其经常作为后台服务,需要始终保持运行,负责处理一些必要(见不得人)的任务.而一些安全软件,如360等,会有结束进程的功能,如果不做Service的保持 ...

  3. Android service后台执行定时任务

    Android 的定时任务 1,Java的API提供的Timer类 Android 中使用容易受手机的休眠系统影响(例如:手机休眠,导致了这个功能的停止). 2,Android的Alarm机制 Ala ...

  4. Android SERVICE后台服务进程的守护

    Service组件在android开发中经常遇到,其经常作为后台服务,需要始终保持运行,负责处理一些必要(见不得人)的任务.而一些安全软件,如360等,会有结束进程的功能,如果不做Service的保持 ...

  5. android后台自播放音乐,Android实现后台播放音乐(Service方式)

    Android实现后台播放音乐(Service方式) 实现: 在res文件夹下添加raw文件夹,添加mp3/4格式的音乐文件 注意命名规则只能是a-z,0-9,和下划线_ 不能大写字母和- Andro ...

  6. 图形引擎实战:手游Android端后台下载技术分享

    一.功能特点 手游android端后台下载SDK是畅游自主研发的一款移动平台android端后台文件下载工具包,它主要提供网络文件的后台下载功能,功能完善,性能高,可以满足游戏制作有关后台下载文件的需 ...

  7. Android中的多线程(字节跳动)

    文章目录 Handler机制(Android中的消息队列机制) Handler机制为Android系统解决了以下两个问题 Handler常用方法 Handler的使用 补充知识点 Handler原理 ...

  8. android 浏览器源码分析,从源码出发深入理解 Android Service

    原标题:从源码出发深入理解 Android Service 原文链接: 建议在浏览器上打开,删除了大量代码细节,:) 本文是 Android 系统学习系列文章中的第三章节的内容,介绍了 Android ...

  9. android demo示例代码,Android Service demo例子使用详解(示例代码)

    Android Service demo例子使用详解\ 概述 Service 是 Android 的四大组件之一,它主要的作用是后台执行操作,Activity 属于带有 UI 界面跟用户进行交互,而 ...

最新文章

  1. 七号信令:SCCP层简介
  2. 全国大学生智能汽车竞赛获奖证书文字
  3. Tomcat 8熵池阻塞变慢详解
  4. 从入门到熟悉 HTTPS 的 9 个问题
  5. c++ 和 C语言 中数组语法的比较
  6. mysql command line client 目标不对_MySql轻松入门系列-第一站 从源码角度轻松认识mysql整体框架图...
  7. 学习视觉和语言的多粒度对齐?字节提出新多模态预训练方法 X-VLM:代码已开源!...
  8. 小程序云开发使用where查询遇到的问题
  9. 小程序 、h5图片铺满div,自适应容器大小
  10. Docker入门之五数据管理
  11. arm linux输出到lcd,求助 armlinux中实现lcd显示
  12. Android查看appPackage和Activity的多种方法
  13. hadoop开发步骤
  14. TP框架的目录结构总结
  15. 基于RV1126平台imx291分析 --- mipi csi 注册
  16. js播放Amr音频_Mp3转Amr
  17. mysql 重置密码_mysql忘记密码如何重置密码,以及修改root密码的三种方法
  18. 大数据与应用统计学的区别与联系
  19. H5 vue单页面 活体检测
  20. win7音量图标点了没反应的修复方法

热门文章

  1. 可在控制台中执行字符动画的js插件
  2. 图形学日记(二)几何造型技术
  3. asp mysql 符号乱码_asp MYSQL出现问号乱码的解决方法
  4. 分带在中央经线在arcgis中的一些表示
  5. 通用计算机的发展历程是巨型机大型机小型机,办公自动化概论ppt 第1章 计算机基础知识.ppt...
  6. joseph环c语言课程设计,Joseph环的C语言模拟实现
  7. 每日一练20210527
  8. 大容量数据传输,原来可以这么玩
  9. Java开发环境实验报告,太香了
  10. Linux编程基础:第1章初识Linux 课后习题