(出处:https://cloud.tencent.com/developer/user/1148436/activities)
目录:
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类
注释已经很丰富,不懂请留言
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 = "\r\n"; /** 结束符 */
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 ?>