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

来源:互联网 发布:qq飞车奇迹数据 编辑:程序博客网 时间:2024/05/13 04:01

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

方案原理:

  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();// 按顺序处理任务    @Override    public void onCreate() {        super.onCreate();        EventBus.getDefault().register(this);        LogUtils.e(TAG, "UploadService is onCreate");    }    /**     * 通过EventBus接受传递过来的数据     *     * @param submitPostBena     */    @Subscribe    public 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 的数量一定要和压缩图片的数量一致        }        @Override        public 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;        }        @Override        public void run() {            Bitmap smallBitmap = BitmapUtils.getSmallBitmap(filePath);            String tempPath = BitmapUtils.compressImage(smallBitmap);            if (!TextUtils.isEmpty(tempPath)) {                newPath.add(tempPath);                countDownLatch.countDown();            }        }    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        return super.onStartCommand(intent, flags, startId);    }    @Nullable    @Override    public IBinder onBind(Intent intent) {        return null;    }    @Override    public 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 inSampleSize        options.inJustDecodeBounds = false;// Decode bitmap with inSampleSize set        Bitmap 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即清空baos            options -= 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();    }}

0 0
原创粉丝点击