(出处: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类
注释已经很丰富,不懂请留言
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 ?>