1、網絡開發不要忘記在配置文件中添加訪問網絡的權限
<uses-permission android:name="android.permission.INTERNET"/>
2、網絡請求、處理不能在主線程中進行,一定要在子線程中進行。因為網絡請求一般有1~3秒左右的延時,在主線程中進行造成主線程的停頓,對用戶體驗來說是致命的。(主線程應該只進行UI繪制,像網絡請求、資源下載、各種耗時操作都應該放到子線程中)。
3、Android端程序
public class MoreUploadActivity extends Activity { private TextView mTvMsg; private String result = ""; private long start = 0; // 開始讀取的位置 private long stop = 1024 * 1024; // 結束讀取的位置 private int times = 0; //讀取次數 private long fileSize = 0; //文件大小 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_times_upload); initView(); } private void initView(){ mTvMsg = (TextView) findViewById(R.id.tv_upload); try { FileInputStream file = new FileInputStream(Environment.getExternalStorageDirectory().getPath() + "/aaaaa/baidu_map.apk"); fileSize = file.available(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } new Thread(uploadThread).start(); } private Thread uploadThread = new Thread(){ public void run() { HttpURLConnection connection = null; try { URL url = new URL("http://192.168.23.1:8080/TestProject/MoreUploadTest"); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setChunkedStreamingMode(51200); connection.setUseCaches(false); // 設置允許輸出 connection.setDoOutput(true); // 設置斷點開始,結束位置 connection.setRequestProperty("Range", "bytes=" + start + "-" + stop); String path = Environment.getExternalStorageDirectory().getPath() + "/aaaaa/baidu_map.apk"; RandomAccessFile file = new RandomAccessFile(path, "rw"); file.seek(start); byte[] buffer = new byte[1024]; int count = 0; OutputStream os = connection.getOutputStream(); if(fileSize > 1024*1024){ for(int i=0; i<1024 && count!=-1; i++){ count = file.read(buffer); os.write(buffer, 0, count); } }else{ for(int i=0; i<(fileSize/1024)+1 && count!=-1; i++){ count = file.read(buffer); os.write(buffer, 0, count); } } os.flush(); os.close(); Log.e("ABC", connection.getResponseCode() + ""); if(connection.getResponseCode() == 200){ result += StringStreamUtil.inputStreamToString(connection.getInputStream()) + "\n"; } start = stop + 1; stop += 1024*1024; fileSize -= 1024*1024; Message msg = Message.obtain(); msg.what = 0; uploadHandler.sendMessage(msg); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(connection != null){ connection.disconnect(); } } }; }; private Handler uploadHandler = new Handler(){ public void handleMessage(android.os.Message msg) { if(msg.what == 0){ if(times >= 8){ mTvMsg.setText(result); }else{ times += 1; new Thread(uploadThread).start(); mTvMsg.setText(result); } } }; }; }
4、服務器端使用Servlet開發,這里只給出doPost()方法
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String range = request.getHeader("Range"); int start = Integer.parseInt(range.substring(6, range.indexOf("-"))); int stop = Integer.parseInt(range.substring(range.indexOf("-")+1, range.length())); RandomAccessFile file = new RandomAccessFile("F:/JavaWeb/TestProject/WebRoot/files/baidu.apk", "rw"); file.seek(start); InputStream is = request.getInputStream(); byte[] buffer = new byte[1024]; int count = 0; while((count=is.read(buffer)) != -1){ file.write(buffer, 0, count); } if(is != null){ is.close(); } if(file != null){ file.close(); } response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); out.println("文件上傳成功" + start + "-" + stop); out.flush(); out.close(); }
5、最主要的就是一:設置斷點setRequestProperty("Range", "bytes=0-1024"),獲取斷點request.getHeader("Range")
二:通過RandomAccessFile來讀寫文件
6、對於輸出流的三個方法的對比:
os.write(byte[] buffer); 可能出現錯誤,因為你每次讀取的數據小於等於1024,但你每次寫入的數據仍然是1024, 對圖片有一定影響,對安裝包絕對是致命的影響。
os.write(int oneByte); 效率低
os.write(byte[] buffer, int byteOffset, int byteCount); 效率高,和第二個方法相比有一個數量級的差別(主觀上看,有興趣的可以測幾下)。
7、參考博文:http://blog.sina.com.cn/s/blog_413580c20100wmr8.html