編輯:關於Android編程
文件上傳是常見功能,然而android網上大多數的文件上傳都使用httpclient,而且需要添加一個httpmine-jar,其實HttpURLConnection也可以實現文件上傳,但是它在移動端有個弊端,就是不能上傳大文件,所以這次說的方式,只能上傳一些較小的文件。
文件上傳,並且帶上一些參數,這需要我們了解http請求的構造方式,也就是它的格式。
HttpURLConnection需要我們自己構造請求頭部,也就是我們要拼接出一個正確完整的請求。
下面來看一個典型的例子
POST /api/feed/ HTTP/1.1 Accept-Encoding: gzip Content-Length: 225873 Content-Type: multipart/form-data; boundary=OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp Host: www.myhost.com Connection: Keep-Alive --OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp Content-Disposition: form-data; name=param1 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 888 --OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp Content-Disposition: form-data; name=param2 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nihao --OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp Content-Disposition: form-data; name=images; filename=/storage/emulated/0/Camera/jdimage/1xh0e3yyfmpr2e35tdowbavrx.jpg Content-Type: application/octet-stream Content-Transfer-Encoding: binary 這裡是圖片的二進制數據 --OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp--
POST /api/feed/ HTTP/1.1 Accept-Encoding: gzip Content-Length: 225873 Content-Type: multipart/form-data; boundary=OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp Host: www.myhost.com Connection: Keep-Alive第一行:為POST方式,要請求的子路徑為/api/feed/,例如我們的服務器地址為www.myhost.com,然後我們的這個請求的完整路徑就是www.myhost.com/api/feed/,最後說明了HTTP協議的版本號為1.1
第二行:數據壓縮方式
第三行:數據長度
第四行:multipart/form-data;是指上傳的數據類型,這裡是指文件形式。boundary是我們必須指定的一個分界符,不同參數之間要用這個分界符隔開。而OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp就是具體的分界符,這個參數我們可以自己隨機生成的。
第五行:主機地址
第六行:持久連接,Keep-Alive功能避免了建立或者重新建立連接
第七行:換行,這個換行是必須的,我們使用 來進行換行
然後就是參數內容部分了,先來看
--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp Content-Disposition: form-data; name=param1 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 888我們把上面的看成一個整體
第一行:我要先用分隔符來聲明一個參數的開始。注意,分隔符前面還加了兩橫“--”,這個也是必須加上的!
第二行:name=param1,其實param1就是傳遞的參數的鍵值,例如在get方式中,我們這樣寫http://www.baidu.com?param1=888
第三行:同樣是內容格式,不過這次是指定傳文本,所以是text/plain; 另外,指定了編碼方式charset=UTF-8
第四行:描述的是消息請求(request)和響應(response)所附帶的實體對象(entity)的傳輸形式,簡單文本數據我們設置為8bit,文件參數我們設置為binary就行
第五行:換行,這個是必須的!
第六行:參數值,例如http://www.baidu.com?param1=888,就是888
OK,我們看下一個參數,也是同理
--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp Content-Disposition: form-data; name=param2 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nihao
然後下一個參數,就是文件了
雖然指定的內容不一樣,但是格式是一樣的
--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp Content-Disposition: form-data; name=images; filename=/storage/emulated/0/Camera/jdimage/1xh0e3yyfmpr2e35tdowbavrx.jpg Content-Type: application/octet-stream Content-Transfer-Encoding: binary 這裡是圖片的二進制數據 --OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp--
OK,大家仔細看上面的格式,不能出一點差錯,因為格式不對,就上傳不了了。
接下來,我們直接看我寫的一個帶參數文件上傳工具類
/** * Created by kaiyi.cky on 2015/8/16. */ public class FileUploader { private static final String TAG = uploadFile; private static final int TIME_OUT = 10*10000000; //超時時間 private static final String CHARSET = utf-8; //設置編碼 private static final String PREFIX = --; private static final String LINE_END = ; public static void upload(String host,File file,Mapparams,FileUploadListener listener){ String BOUNDARY = UUID.randomUUID().toString(); //邊界標識 隨機生成 String PREFIX = -- , LINE_END = ; String CONTENT_TYPE = multipart/form-data; //內容類型 try { URL url = new URL(host); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(TIME_OUT); conn.setConnectTimeout(TIME_OUT); conn.setRequestMethod(POST); //請求方式 conn.setRequestProperty(Charset, CHARSET);//設置編碼 conn.setRequestProperty(connection, keep-alive); conn.setRequestProperty(Content-Type, CONTENT_TYPE + ;boundary= + BOUNDARY); conn.setDoInput(true); //允許輸入流 conn.setDoOutput(true); //允許輸出流 conn.setUseCaches(false); //不允許使用緩存 if(file!=null) { /** * 當文件不為空,把文件包裝並且上傳 */ OutputStream outputSteam=conn.getOutputStream(); DataOutputStream dos = new DataOutputStream(outputSteam); StringBuffer sb = new StringBuffer(); sb.append(LINE_END); if(params!=null){//根據格式,開始拼接文本參數 for(Map.Entry entry:params.entrySet()){ sb.append(PREFIX).append(BOUNDARY).append(LINE_END);//分界符 sb.append(Content-Disposition: form-data; name= + entry.getKey() + + LINE_END); sb.append(Content-Type: text/plain; charset= + CHARSET + LINE_END); sb.append(Content-Transfer-Encoding: 8bit + LINE_END); sb.append(LINE_END); sb.append(entry.getValue()); sb.append(LINE_END);//換行! } } sb.append(PREFIX);//開始拼接文件參數 sb.append(BOUNDARY); sb.append(LINE_END); /** * 這裡重點注意: * name裡面的值為服務器端需要key 只有這個key 才可以得到對應的文件 * filename是文件的名字,包含後綴名的 比如:abc.png */ sb.append(Content-Disposition: form-data; name=img; filename=+file.getName()++LINE_END); sb.append(Content-Type: application/octet-stream; charset=+CHARSET+LINE_END); sb.append(LINE_END); //寫入文件數據 dos.write(sb.toString().getBytes()); InputStream is = new FileInputStream(file); byte[] bytes = new byte[1024]; long totalbytes = file.length(); long curbytes = 0; Log.i(cky,total=+totalbytes); int len = 0; while((len=is.read(bytes))!=-1){ curbytes += len; dos.write(bytes, 0, len); listener.onProgress(curbytes,1.0d*curbytes/totalbytes); } is.close(); dos.write(LINE_END.getBytes());\一定還有換行 byte[] end_data = (PREFIX+BOUNDARY+PREFIX+LINE_END).getBytes(); dos.write(end_data); dos.flush(); /** * 獲取響應碼 200=成功 * 當響應成功,獲取響應的流 */ int code = conn.getResponseCode(); sb.setLength(0); BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while((line=br.readLine())!=null){ sb.append(line); } listener.onFinish(code,sb.toString(),conn.getHeaderFields()); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public interface FileUploadListener{ public void onProgress(long pro,double precent); public void onFinish(int code,String res,Map > headers); } }
public class MainActivity extends FragmentActivity { File sdDir; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sdDir = null; boolean sdCardExist = Environment.getExternalStorageState() .equals(Environment.MEDIA_MOUNTED); //判斷sd卡是否存在 if(sdCardExist) { sdDir = Environment.getExternalStorageDirectory();//獲取跟目錄 } final HashMapmap = new HashMap (); map.put(aa,bb); new Thread(){ @Override public void run() { FileUploader.upload(上傳地址, new File(sdDir.getPath() + /文件名), map, new FileUploader.FileUploadListener() { @Override public void onProgress(long pro, double precent) { Log.i(cky, precent+); } @Override public void onFinish(int code, String res, Map > headers) { Log.i(cky, res); } }); } }.start(); } }
一、JNI概述 JNI 是Java Native Interface的縮寫,中文翻譯為“Java本地調用”,JNI 是本地編程接口。它使得在 Java 虛擬機 (VM)
接上一篇《Android開發性能優化總結(一)》 一、安卓UI性能檢測與優化UI是安卓應用程序與用戶打交道的最直接途徑,UI設計的好不好,直接影響到用戶的體驗,
API 21中將原來的camera API棄用轉而推薦使用新增的camera2 API,這是一個大的動作,因為新API換了架構,讓開發者用起來更難了。先來看看camera
先看 SwipeLayout的效果圖圖太多了,我這只上傳一張,想看 listview和GridView效果的,和想看源碼的 —> GitHub怎麼實現後