android網絡編程之HttpUrlConnection的講解--實現文件的斷點上傳


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM