zoukankan      html  css  js  c++  java
  • Android -线程池 批量上传图片 -附php接收代码

    (出处:http://www.cnblogs.com/linguanh/)

    目录:

      1,前序

      2,类特点

      3,用法

      4,java代码

      5,php代码

    1,前序

      还是源于重构,看着之前为赶时间写着的碎片化的代码,甚是悲剧,臃肿且长,其实重构也是一个提高的过程,重构过程中会接触到更多的知识点。至少,我现在意识到,那怕是听过、有这样的意识而没真正动过手都是不行的,多线程并发最好使用线程池而不要一味地 new Thread(...).start()。下面我分享个自己刚写好的图片批量上传类,顺带server端接口代码,已经过测试,一套直接可用。

    2,本类特点

      1、耦合度低,操作简单、使用时仅 6 行代码即可直接 批量上传完图片;

      2、使用的是软化线程池对象,内存消耗这方面可以放心地交给系统处理;

      3、采用链式操作,配置方便;

      4、自带上传函数,光学习这个都够了;

      5、懒人必备...

    3,使用例子

    new PicUpLoadExecutor(3)// 并发数       
         .withUpLoadUrl(url) // 服务端接口文件的url
    .withHandler(handler) // 发完后发消息的handler
    .exec(picBitmaps); // 要上传的图片bitmaps

    4,client端java类

    注释已经很丰富,不懂请留言

    package cn.share.bananacloud.post.send;

    import android.graphics.Bitmap;
    import android.os.Handler;
    import android.util.Log;

    import java.io.BufferedReader;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.DataOutputStream;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.lang.ref.SoftReference;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ThreadFactory;

    /**
     *  Created by 林冠宏 on 2016/4/30.
     *
     *  1,线程池批量上传图片类,选用 newFixedThreadPool
     *  2,以 Bitmap 数组为例子
     *  3,自定义一个 图片上传 函数
     *
     */

    public class PicUpLoadExecutor {

        private static final String TAG = "PicUpLoadHelper";
        public static final int UpLoadFinish = 0x321;

        /** 如果你不想内存不足是它们被gc掉,请换为强引用 */
        private SoftReference<ExecutorService> fixedThreadPool = null;

        /** 并发数>0 --1 ~ 128,用 short 足以 */
        private short poolSize = 1;
        private Handler handler = null;
        private ExecListenter ExecListenter;
        private String url = null;

        public PicUpLoadExecutor(short poolSize){
            fixedThreadPool = new SoftReference<ExecutorService>(Executors.newFixedThreadPool(poolSize));
        }

        public PicUpLoadExecutor(short poolSize,ThreadFactory threadFactory){
            fixedThreadPool = new SoftReference<ExecutorService>(Executors.newFixedThreadPool(poolSize,threadFactory));
        }

        /** 设置并发数 */
        /*public PicUpLoadExecutor withPoolSize(short poolSize){
            this.poolSize = poolSize;
            return this;
        }*/

        /** 设置图片总数,已直接换为图片数目 */
        /*public PicUpLoadHelper withPicSize(short poolSize){
            this.picSize = picSize;
            return this;
        }*/

        /** 设置图片上传路径 */
        public PicUpLoadExecutor withUpLoadUrl(String url){
            this.url = url;
            return this;
        }

        /** 设置handler */
        public PicUpLoadExecutor withHandler(Handler handler){
            this.handler = handler;
            return this;
        }

        /** 设置自定义 run 函数接口 */
        /*public PicUpLoadHelper withExecRunnableListenter(ExecRunnableListenter ExecRunnableListenter){
            this.ExecRunnableListenter = ExecRunnableListenter;
            return this;
        }*/

        /** 设置开始前接口 */
        public PicUpLoadExecutor withBeforeExecListenter(ExecListenter ExecListenter){
            this.ExecListenter = ExecListenter;
            return this;
        }


        public ExecutorService getFixedThreadPool(){
            return fixedThreadPool.get();
        }

        /** 开发原则--接口分离 */

        /** 自定义run接口 */
        public interface ExecRunnableListenter{
            void onRun(int i);
        }

        /** 开始任务前接口,没用到,可自行设置 */
        public interface ExecListenter{
            void onBeforeExec();
        }

        /** 为减少 程序计数器 每次在循环时花费在 if else 的时间,这里还是 重载一次 好 */

        public void exec(final Bitmap[] bitmaps,final ExecRunnableListenter ExecRunnableListenter){
            if(bitmaps==null){
                return;
            }
            if(ExecRunnableListenter!=null){
                int picNums = bitmaps.length;
                for(int i=0;i<picNums;i++){
                    /** 自定义执行上传任务 */
                    final int picIndex = i;
                    fixedThreadPool.get().execute(new Runnable() {
                        @Override
                        public void run() {
                            ExecRunnableListenter.onRun(picIndex);
                        }
                    });
                }
            }
        }

        public void exec(final Bitmap[] bitmaps){
            if(bitmaps==null){
                return;
            }
            int picNums = bitmaps.length;
            for(int i=0;i<picNums;i++){
                /** 默认执行上传任务 */
                final int picIndex = i;
                fixedThreadPool.get().execute(new Runnable() {
                    @Override
                    public void run() {
                        /** 批量 上传 图片,此静态函数若有使用全局变量,必须要 加 synchronized */
                        String json = uploadPic
                                (
                                        url,
                                        "" + picIndex + ".jpg", /** 我自己情况的上传 */
                                        bitmaps[picIndex]       /** 对应的图片流 */
                                );
                        if(json!=null){
                            /** 服务器上传成功返回的标示, 自己修改吧,我这里是我的情况 */
                            if(json.trim().equals("yes")){
                                /** UpLoadFinish 是每次传完一张发信息的信息标示 */
                                handler.sendEmptyMessage(UpLoadFinish);
                            }
                        }
                        Log.d(TAG,"pic "+picIndex+" upLoad json ---> "+json);
                    }
                });
            }
        }

        /** 若有依赖全局变量必须加 synchronized */
        /** 此函数采用 tcp 数据包传输 */
        public static String uploadPic(String uploadUrl,String filename,Bitmap bit){
            String end = " "; /** 结束符 */
            String twoHyphens = "--";
            String boundary = "******"; /** 数据包头,设置格式没强性要求 */
            int compress=100; /** 压缩初始值 */
            try{
                HttpURLConnection httpURLConnection
                        = (HttpURLConnection) new URL(uploadUrl).openConnection();
                /** 设置每次传输的流大小,可以有效防止手机因为内存不足崩溃 */
                /** 此方法用于在预先不知道内容长度时启用没有进行内部缓冲的 HTTP 请求正文的流。*/
                httpURLConnection.setChunkedStreamingMode(256 * 1024);// 256K

                httpURLConnection.setConnectTimeout(10*1000);
                httpURLConnection.setDoInput(true);
                httpURLConnection.setDoOutput(true);
                httpURLConnection.setUseCaches(false);

                httpURLConnection.setRequestMethod("POST");
                /** tcp链接,防止丢包,需要进行长链接设置 */
                httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
                httpURLConnection.setRequestProperty("Charset", "UTF-8");
                httpURLConnection.setRequestProperty("Content-Type","multipart/form-data;boundary=" + boundary);

                /** 发送报头操作,dos 也是流发送体 */
                DataOutputStream dos = new DataOutputStream(httpURLConnection.getOutputStream());
                dos.writeBytes(twoHyphens + boundary + end);
                /** uploadedfile 是接口文件的接受流的键,client 和 server 要同步 */
                dos.writeBytes("Content-Disposition: form-data; name="uploadedfile"; filename=""
                        + filename.substring(filename.lastIndexOf("/") + 1)
                        + """
                        + end);
                dos.writeBytes(end);

                /** 下面是压缩操作 */
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                bit.compress(Bitmap.CompressFormat.JPEG, compress, baos);
                while (baos.toByteArray().length / 1024 > 500) {
                    Log.d(TAG,"compress time ");
                    baos.reset();
                    compress -= 10;
                    if(compress==0){
                        bit.compress(Bitmap.CompressFormat.JPEG, compress, baos);
                        break;
                    }
                    bit.compress(Bitmap.CompressFormat.JPEG, compress, baos);
                }

                /** 发送比特流 */
                InputStream fis = new ByteArrayInputStream(baos.toByteArray());
                byte[] buffer = new byte[10*1024]; // 8k+2k
                int count = 0;
                while ((count = fis.read(buffer)) != -1) {
                    dos.write(buffer, 0, count);
                }
                fis.close();
                dos.writeBytes(end);
                dos.writeBytes(twoHyphens + boundary + twoHyphens + end);
                dos.flush();

                /** 获取返回值 */
                InputStream is = httpURLConnection.getInputStream();
                InputStreamReader isr = new InputStreamReader(is, "utf-8");
                BufferedReader br = new BufferedReader(isr);
                String result = br.readLine();

                Log.d(TAG, "send pic result "+result);
                dos.close();
                is.close();
                return result;
            } catch (Exception e){
                e.printStackTrace();
                Log.d(TAG, e.toString());
                return null;
            }
        }
    }
    复制代码
      1 package cn.share.bananacloud.post.send;
      2 
      3 import android.graphics.Bitmap;
      4 import android.os.Handler;
      5 import android.util.Log;
      6 
      7 import java.io.BufferedReader;
      8 import java.io.ByteArrayInputStream;
      9 import java.io.ByteArrayOutputStream;
     10 import java.io.DataOutputStream;
     11 import java.io.InputStream;
     12 import java.io.InputStreamReader;
     13 import java.lang.ref.SoftReference;
     14 import java.net.HttpURLConnection;
     15 import java.net.URL;
     16 import java.util.concurrent.ExecutorService;
     17 import java.util.concurrent.Executors;
     18 import java.util.concurrent.ThreadFactory;
     19 
     20 /**
     21  *  Created by 林冠宏 on 2016/4/30.
     22  *
     23  *  1,线程池批量上传图片类,选用 newFixedThreadPool
     24  *  2,以 Bitmap 数组为例子
     25  *  3,自定义一个 图片上传 函数
     26  *
     27  */
     28 
     29 public class PicUpLoadExecutor {
     30 
     31     private static final String TAG = "PicUpLoadHelper";
     32     public static final int UpLoadFinish = 0x321;
     33 
     34     /** 如果你不想内存不足是它们被gc掉,请换为强引用 */
     35     private SoftReference<ExecutorService> fixedThreadPool = null;
     36 
     37     /** 并发数>0 --1 ~ 128,用 short 足以 */
     38     private short poolSize = 1;
     39     private Handler handler = null;
     40     private ExecListenter ExecListenter;
     41     private String url = null;
     42 
     43     public PicUpLoadExecutor(short poolSize){
     44         fixedThreadPool = new SoftReference<ExecutorService>(Executors.newFixedThreadPool(poolSize));
     45     }
     46 
     47     public PicUpLoadExecutor(short poolSize,ThreadFactory threadFactory){
     48         fixedThreadPool = new SoftReference<ExecutorService>(Executors.newFixedThreadPool(poolSize,threadFactory));
     49     }
     50 
     51     /** 设置并发数 */
     52     /*public PicUpLoadExecutor withPoolSize(short poolSize){
     53         this.poolSize = poolSize;
     54         return this;
     55     }*/
     56 
     57     /** 设置图片总数,已直接换为图片数目 */
     58     /*public PicUpLoadHelper withPicSize(short poolSize){
     59         this.picSize = picSize;
     60         return this;
     61     }*/
     62 
     63     /** 设置图片上传路径 */
     64     public PicUpLoadExecutor withUpLoadUrl(String url){
     65         this.url = url;
     66         return this;
     67     }
     68 
     69     /** 设置handler */
     70     public PicUpLoadExecutor withHandler(Handler handler){
     71         this.handler = handler;
     72         return this;
     73     }
     74 
     75     /** 设置自定义 run 函数接口 */
     76     /*public PicUpLoadHelper withExecRunnableListenter(ExecRunnableListenter ExecRunnableListenter){
     77         this.ExecRunnableListenter = ExecRunnableListenter;
     78         return this;
     79     }*/
     80 
     81     /** 设置开始前接口 */
     82     public PicUpLoadExecutor withBeforeExecListenter(ExecListenter ExecListenter){
     83         this.ExecListenter = ExecListenter;
     84         return this;
     85     }
     86 
     87 
     88     public ExecutorService getFixedThreadPool(){
     89         return fixedThreadPool.get();
     90     }
     91 
     92     /** 开发原则--接口分离 */
     93 
     94     /** 自定义run接口 */
     95     public interface ExecRunnableListenter{
     96         void onRun(int i);
     97     }
     98 
     99     /** 开始任务前接口,没用到,可自行设置 */
    100     public interface ExecListenter{
    101         void onBeforeExec();
    102     }
    103 
    104     /** 为减少 程序计数器 每次在循环时花费在 if else 的时间,这里还是 重载一次 好 */
    105 
    106     public void exec(final Bitmap[] bitmaps,final ExecRunnableListenter ExecRunnableListenter){
    107         if(bitmaps==null){
    108             return;
    109         }
    110         if(ExecRunnableListenter!=null){
    111             int picNums = bitmaps.length;
    112             for(int i=0;i<picNums;i++){
    113                 /** 自定义执行上传任务 */
    114                 final int picIndex = i;
    115                 fixedThreadPool.get().execute(new Runnable() {
    116                     @Override
    117                     public void run() {
    118                         ExecRunnableListenter.onRun(picIndex);
    119                     }
    120                 });
    121             }
    122         }
    123     }
    124 
    125     public void exec(final Bitmap[] bitmaps){
    126         if(bitmaps==null){
    127             return;
    128         }
    129         int picNums = bitmaps.length;
    130         for(int i=0;i<picNums;i++){
    131             /** 默认执行上传任务 */
    132             final int picIndex = i;
    133             fixedThreadPool.get().execute(new Runnable() {
    134                 @Override
    135                 public void run() {
    136                     /** 批量 上传 图片,此静态函数若有使用全局变量,必须要 加 synchronized */
    137                     String json = uploadPic
    138                             (
    139                                     url,
    140                                     "" + picIndex + ".jpg", /** 我自己情况的上传 */
    141                                     bitmaps[picIndex]       /** 对应的图片流 */
    142                             );
    143                     if(json!=null){
    144                         /** 服务器上传成功返回的标示, 自己修改吧,我这里是我的情况 */
    145                         if(json.trim().equals("yes")){
    146                             /** UpLoadFinish 是每次传完一张发信息的信息标示 */
    147                             handler.sendEmptyMessage(UpLoadFinish);
    148                         }
    149                     }
    150                     Log.d(TAG,"pic "+picIndex+" upLoad json ---> "+json);
    151                 }
    152             });
    153         }
    154     }
    155 
    156     /** 若有依赖全局变量必须加 synchronized */
    157     /** 此函数采用 tcp 数据包传输 */
    158     public static String uploadPic(String uploadUrl,String filename,Bitmap bit){
    159         String end = "
    "; /** 结束符 */
    160         String twoHyphens = "--";
    161         String boundary = "******"; /** 数据包头,设置格式没强性要求 */
    162         int compress=100; /** 压缩初始值 */
    163         try{
    164             HttpURLConnection httpURLConnection
    165                     = (HttpURLConnection) new URL(uploadUrl).openConnection();
    166             /** 设置每次传输的流大小,可以有效防止手机因为内存不足崩溃 */
    167             /** 此方法用于在预先不知道内容长度时启用没有进行内部缓冲的 HTTP 请求正文的流。*/
    168             httpURLConnection.setChunkedStreamingMode(256 * 1024);// 256K
    169 
    170             httpURLConnection.setConnectTimeout(10*1000);
    171             httpURLConnection.setDoInput(true);
    172             httpURLConnection.setDoOutput(true);
    173             httpURLConnection.setUseCaches(false);
    174 
    175             httpURLConnection.setRequestMethod("POST");
    176             /** tcp链接,防止丢包,需要进行长链接设置 */
    177             httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
    178             httpURLConnection.setRequestProperty("Charset", "UTF-8");
    179             httpURLConnection.setRequestProperty("Content-Type","multipart/form-data;boundary=" + boundary);
    180 
    181             /** 发送报头操作,dos 也是流发送体 */
    182             DataOutputStream dos = new DataOutputStream(httpURLConnection.getOutputStream());
    183             dos.writeBytes(twoHyphens + boundary + end);
    184             /** uploadedfile 是接口文件的接受流的键,client 和 server 要同步 */
    185             dos.writeBytes("Content-Disposition: form-data; name="uploadedfile"; filename=""
    186                     + filename.substring(filename.lastIndexOf("/") + 1)
    187                     + """
    188                     + end);
    189             dos.writeBytes(end);
    190 
    191             /** 下面是压缩操作 */
    192             ByteArrayOutputStream baos = new ByteArrayOutputStream();
    193             bit.compress(Bitmap.CompressFormat.JPEG, compress, baos);
    194             while (baos.toByteArray().length / 1024 > 500) {
    195                 Log.d(TAG,"compress time ");
    196                 baos.reset();
    197                 compress -= 10;
    198                 if(compress==0){
    199                     bit.compress(Bitmap.CompressFormat.JPEG, compress, baos);
    200                     break;
    201                 }
    202                 bit.compress(Bitmap.CompressFormat.JPEG, compress, baos);
    203             }
    204 
    205             /** 发送比特流 */
    206             InputStream fis = new ByteArrayInputStream(baos.toByteArray());
    207             byte[] buffer = new byte[10*1024]; // 8k+2k
    208             int count = 0;
    209             while ((count = fis.read(buffer)) != -1) {
    210                 dos.write(buffer, 0, count);
    211             }
    212             fis.close();
    213             dos.writeBytes(end);
    214             dos.writeBytes(twoHyphens + boundary + twoHyphens + end);
    215             dos.flush();
    216 
    217             /** 获取返回值 */
    218             InputStream is = httpURLConnection.getInputStream();
    219             InputStreamReader isr = new InputStreamReader(is, "utf-8");
    220             BufferedReader br = new BufferedReader(isr);
    221             String result = br.readLine();
    222 
    223             Log.d(TAG, "send pic result "+result);
    224             dos.close();
    225             is.close();
    226             return result;
    227         } catch (Exception e){
    228             e.printStackTrace();
    229             Log.d(TAG, e.toString());
    230             return null;
    231         }
    232     }
    233 }
    复制代码

    5,server端接受代码 php

     
     1 <?php
     2 /**
     3  * Created by PhpStorm.
     4  * User: Administrator
     5  * Date: 2016/4/30
     6  * Time: 15:37
     7  */
     8 
     9 // $_FILES['uploadedfile']['name'] 是传过来的图片名称
    10 
    11 $target_path = "要保存到的路径";
    12 
    13 if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
    14     echo "yes";
    15 }  else{
    16     echo "no";
    17 }
    18 
    19 
    20 ?>
     




  • 相关阅读:
    【Android Developers Training】 85. 不要有冗余的下载
    【Android Developers Training】 84. 将定期更新的影响最小化
    【Android Developers Training】 83. 实现高效网络访问来优化下载
    【Android Developers Training】 82. 序言:传输数据时减少对电池寿命的影响
    【Android Developers Training】 81. 解析XML数据
    Linux下C程序进程地址空间布局[转]
    GNOME keyring [(null)] 的密码:
    Advanced Memory Allocation 内存分配进阶[转]
    Linux下进程信息的深入分析[转]
    安装juicer
  • 原文地址:https://www.cnblogs.com/android-blogs/p/5454663.html
Copyright © 2011-2022 走看看