• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            life02

              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              197 隨筆 :: 3 文章 :: 37 評論 :: 0 Trackbacks
            http://blog.csdn.net/furongkang/article/details/6838521


            111
            Android開發(fā)多線程斷點(diǎn)續(xù)傳下載器
            分類: Android 
            2011-10-01 23:14 931人閱讀 評論(8) 收藏 舉報

            使用多線程斷點(diǎn)續(xù)傳下載器在下載的時候多個線程并發(fā)可以占用服務(wù)器端更多資源,從而加快下載速度,在下載過程中記錄每個線程已拷貝數(shù)據(jù)的數(shù)量,如果下載中斷,比如無信號斷線、電量不足等情況下,這就需要使用到斷點(diǎn)續(xù)傳功能,下次啟動時從記錄位置繼續(xù)下載,可避免重復(fù)部分的下載。這里采用數(shù)據(jù)庫來記錄下載的進(jìn)度。

            效果圖

                   

             

            斷點(diǎn)續(xù)傳

            1.斷點(diǎn)續(xù)傳需要在下載過程中記錄每條線程的下載進(jìn)度

            2.每次下載開始之前先讀取數(shù)據(jù)庫,查詢是否有未完成的記錄,有就繼續(xù)下載,沒有則創(chuàng)建新記錄插入數(shù)據(jù)庫

            3.在每次向文件中寫入數(shù)據(jù)之后,在數(shù)據(jù)庫中更新下載進(jìn)度

            4.下載完成之后刪除數(shù)據(jù)庫中下載記錄

            Handler傳輸數(shù)據(jù)

            這個主要用來記錄百分比,每下載一部分?jǐn)?shù)據(jù)就通知主線程來記錄時間

            1.主線程中創(chuàng)建的View只能在主線程中修改,其他線程只能通過和主線程通信,在主線程中改變View數(shù)據(jù)

            2.我們使用Handler可以處理這種需求

               主線程中創(chuàng)建Handler,重寫handleMessage()方法

               新線程中使用Handler發(fā)送消息,主線程即可收到消息,并且執(zhí)行handleMessage()方法

            動態(tài)生成新View

            可實(shí)現(xiàn)多任務(wù)下載

            1.創(chuàng)建XML文件,將要生成的View配置好

            2.獲取系統(tǒng)服務(wù)LayoutInflater,用來生成新的View

               LayoutInflater inflater 
            = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);

            3.使用inflate(int resource, ViewGroup root)方法生成新的View

            4.調(diào)用當(dāng)前頁面中某個容器的addView,將新創(chuàng)建的View添加進(jìn)來

            示例

            進(jìn)度條樣式 download.xml
            [html] view plaincopy

                
            <?xml version="1.0" encoding="utf-8"?>  
                
            <LinearLayout   
                    xmlns:android
            ="http://schemas.android.com/apk/res/android"  
                    android:layout_width
            ="fill_parent"  
                    android:layout_height
            ="wrap_content"  
                    
            >  
                    
            <LinearLayout   
                        android:orientation
            ="vertical"  
                        android:layout_width
            ="fill_parent"  
                        android:layout_height
            ="wrap_content"  
                        android:layout_weight
            ="1"  
                        
            >  
                        
            <!--進(jìn)度條樣式默認(rèn)為圓形進(jìn)度條,水平進(jìn)度條需要配置style屬性,  
                        
            ?android:attr/progressBarStyleHorizontal -->  
                        
            <ProgressBar  
                            android:layout_width
            ="fill_parent"   
                            android:layout_height
            ="20dp"  
                            style
            ="?android:attr/progressBarStyleHorizontal"  
                            
            />  
                        
            <TextView  
                            android:layout_width
            ="wrap_content"   
                            android:layout_height
            ="wrap_content"  
                            android:layout_gravity
            ="center"  
                            android:text
            ="0%"  
                            
            />  
                    
            </LinearLayout>  
                    
            <Button  
                        android:layout_width
            ="40dp"  
                        android:layout_height
            ="40dp"  
                        android:onClick
            ="pause"  
                        android:text
            ="||"  
                        
            />  
                
            </LinearLayout>  

            頂部樣式 main.xml
            [html] view plaincopy

                
            <?xml version="1.0" encoding="utf-8"?>  
                
            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
                    android:orientation
            ="vertical"  
                    android:layout_width
            ="fill_parent"  
                    android:layout_height
            ="fill_parent"  
                    android:id
            ="@+id/root"  
                    
            >  
                    
            <TextView    
                        android:layout_width
            ="fill_parent"   
                        android:layout_height
            ="wrap_content"   
                        android:text
            ="請輸入下載路徑"  
                        
            />  
                    
            <LinearLayout   
                        android:layout_width
            ="fill_parent"  
                        android:layout_height
            ="wrap_content"  
                        android:layout_marginBottom
            ="30dp"  
                        
            >  
                        
            <EditText  
                            android:id
            ="@+id/path"  
                            android:layout_width
            ="fill_parent"   
                            android:layout_height
            ="wrap_content"   
                            android:singleLine
            ="true"  
                            android:layout_weight
            ="1"  
                            
            />  
                        
            <Button  
                            android:layout_width
            ="wrap_content"   
                            android:layout_height
            ="wrap_content"   
                            android:text
            ="下載"  
                            android:onClick
            ="download"  
                            
            />  
                    
            </LinearLayout>  
                
            </LinearLayout>  
                   

            MainActivity.java
            [java] view plaincopy

                
            public class MainActivity extends Activity {  
                    
            private LayoutInflater inflater;  
                    
            private LinearLayout rootLinearLayout;  
                    
            private EditText pathEditText;  
                  
                    @Override  
                    
            public void onCreate(Bundle savedInstanceState) {  
                        
            super.onCreate(savedInstanceState);  
                        setContentView(R.layout.main);  
                  
                        
            //動態(tài)生成新View,獲取系統(tǒng)服務(wù)LayoutInflater,用來生成新的View  
                        inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);  
                        rootLinearLayout 
            = (LinearLayout) findViewById(R.id.root);  
                        pathEditText 
            = (EditText) findViewById(R.id.path);  
                  
                        
            // 窗體創(chuàng)建之后, 查詢數(shù)據(jù)庫是否有未完成任務(wù), 如果有, 創(chuàng)建進(jìn)度條等組件, 繼續(xù)下載  
                        List<String> list = new InfoDao(this).queryUndone();  
                        
            for (String path : list)  
                            createDownload(path);  
                    }  
                  
                    
            /** 
                     * 下載按鈕 
                     * 
            @param view 
                     
            */  
                    
            public void download(View view) {  
                        String path 
            = "http://192.168.1.199:8080/14_Web/" + pathEditText.getText().toString();  
                        createDownload(path);  
                    }  
                  
                    
            /** 
                     * 動態(tài)生成新View 
                     * 初始化表單數(shù)據(jù) 
                     * 
            @param path 
                     
            */  
                    
            private void createDownload(String path) {  
                        
            //獲取系統(tǒng)服務(wù)LayoutInflater,用來生成新的View  
                        LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);  
                        LinearLayout linearLayout 
            = (LinearLayout) inflater.inflate(R.layout.download, null);  
                          
                        LinearLayout childLinearLayout 
            = (LinearLayout) linearLayout.getChildAt(0);  
                        ProgressBar progressBar 
            = (ProgressBar) childLinearLayout.getChildAt(0);  
                        TextView textView 
            = (TextView) childLinearLayout.getChildAt(1);  
                        Button button 
            = (Button) linearLayout.getChildAt(1);  
                  
                        
            try {  
                            button.setOnClickListener(
            new MyListener(progressBar, textView, path));  
                            
            //調(diào)用當(dāng)前頁面中某個容器的addView,將新創(chuàng)建的View添加進(jìn)來  
                            rootLinearLayout.addView(linearLayout);  
                        } 
            catch (Exception e) {  
                            e.printStackTrace();  
                        }  
                    }  
                  
                    
            private final class MyListener implements OnClickListener {  
                        
            private ProgressBar progressBar;  
                        
            private TextView textView;  
                        
            private int fileLen;  
                        
            private Downloader downloader;  
                        
            private String name;  
                          
                        
            /** 
                         * 執(zhí)行下載 
                         * 
            @param progressBar //進(jìn)度條 
                         * 
            @param textView //百分比 
                         * 
            @param path  //下載文件路徑 
                         
            */  
                        
            public MyListener(ProgressBar progressBar, TextView textView, String path) {  
                            
            this.progressBar = progressBar;  
                            
            this.textView = textView;  
                            name 
            = path.substring(path.lastIndexOf("/"+ 1);  
                  
                            downloader 
            = new Downloader(getApplicationContext(), handler);  
                            
            try {  
                                downloader.download(path, 
            3);  
                            } 
            catch (Exception e) {  
                                e.printStackTrace();  
                                Toast.makeText(getApplicationContext(), 
            "下載過程中出現(xiàn)異常"0).show();  
                                
            throw new RuntimeException(e);  
                            }  
                        }  
                          
                        
            //Handler傳輸數(shù)據(jù)  
                        private Handler handler = new Handler() {  
                            @Override  
                            
            public void handleMessage(Message msg) {  
                                
            switch (msg.what) {  
                                    
            case 0:  
                                        
            //獲取文件的大小  
                                        fileLen = msg.getData().getInt("fileLen");  
                                        
            //設(shè)置進(jìn)度條最大刻度:setMax()  
                                        progressBar.setMax(fileLen);  
                                        
            break;  
                                    
            case 1:  
                                        
            //獲取當(dāng)前下載的總量  
                                        int done = msg.getData().getInt("done");  
                                        
            //當(dāng)前進(jìn)度的百分比  
                                        textView.setText(name + "\t" + done * 100 / fileLen + "%");  
                                        
            //進(jìn)度條設(shè)置當(dāng)前進(jìn)度:setProgress()  
                                        progressBar.setProgress(done);  
                                        
            if (done == fileLen) {  
                                            Toast.makeText(getApplicationContext(), name 
            + " 下載完成"0).show();  
                                            
            //下載完成后退出進(jìn)度條  
                                            rootLinearLayout.removeView((View) progressBar.getParent().getParent());  
                                        }  
                                        
            break;  
                                }  
                            }  
                        };  
                  
                        
            /** 
                         * 暫停和繼續(xù)下載 
                         
            */  
                        
            public void onClick(View v) {  
                            Button pauseButton 
            = (Button) v;  
                            
            if ("||".equals(pauseButton.getText())) {  
                                downloader.pause();  
                                pauseButton.setText(
            "");  
                            } 
            else {  
                                downloader.resume();  
                                pauseButton.setText(
            "||");  
                            }  
                        }  
                    }  
                }  



            Downloader.java
            [java] view plaincopy

                
            public class Downloader {  
                  
                    
            private int done;  
                    
            private InfoDao dao;  
                    
            private int fileLen;  
                    
            private Handler handler;  
                    
            private boolean isPause;  
                  
                    
            public Downloader(Context context, Handler handler) {  
                        dao 
            = new InfoDao(context);  
                        
            this.handler = handler;  
                    }  
                    
            /** 
                     * 多線程下載 
                     * 
            @param path 下載路徑 
                     * 
            @param thCount 需要開啟多少個線程 
                     * 
            @throws Exception 
                     
            */  
                    
            public void download(String path, int thCount) throws Exception {  
                        URL url 
            = new URL(path);  
                        HttpURLConnection conn 
            = (HttpURLConnection) url.openConnection();  
                        
            //設(shè)置超時時間  
                        conn.setConnectTimeout(3000);  
                        
            if (conn.getResponseCode() == 200) {  
                            fileLen 
            = conn.getContentLength();  
                            String name 
            = path.substring(path.lastIndexOf("/"+ 1);  
                            File file 
            = new File(Environment.getExternalStorageDirectory(), name);  
                            RandomAccessFile raf 
            = new RandomAccessFile(file, "rws");  
                            raf.setLength(fileLen);  
                            raf.close();  
                              
                            
            //Handler發(fā)送消息,主線程接收消息,獲取數(shù)據(jù)的長度  
                            Message msg = new Message();  
                            msg.what 
            = 0;  
                            msg.getData().putInt(
            "fileLen", fileLen);  
                            handler.sendMessage(msg);  
                              
                            
            //計(jì)算每個線程下載的字節(jié)數(shù)  
                            int partLen = (fileLen + thCount - 1/ thCount;  
                            
            for (int i = 0; i < thCount; i++)  
                                
            new DownloadThread(url, file, partLen, i).start();  
                        } 
            else {  
                            
            throw new IllegalArgumentException("404 path: " + path);  
                        }  
                    }  
                  
                    
            private final class DownloadThread extends Thread {  
                        
            private URL url;  
                        
            private File file;  
                        
            private int partLen;  
                        
            private int id;  
                  
                        
            public DownloadThread(URL url, File file, int partLen, int id) {  
                            
            this.url = url;  
                            
            this.file = file;  
                            
            this.partLen = partLen;  
                            
            this.id = id;  
                        }  
                  
                        
            /** 
                         * 寫入操作 
                         
            */  
                        
            public void run() {  
                            
            // 判斷上次是否有未完成任務(wù)  
                            Info info = dao.query(url.toString(), id);  
                            
            if (info != null) {  
                                
            // 如果有, 讀取當(dāng)前線程已下載量  
                                done += info.getDone();  
                            } 
            else {  
                                
            // 如果沒有, 則創(chuàng)建一個新記錄存入  
                                info = new Info(url.toString(), id, 0);  
                                dao.insert(info);  
                            }  
                  
                            
            int start = id * partLen + info.getDone(); // 開始位置 += 已下載量  
                            int end = (id + 1* partLen - 1;  
                  
                            
            try {  
                                HttpURLConnection conn 
            = (HttpURLConnection) url.openConnection();  
                                conn.setReadTimeout(
            3000);  
                                
            //獲取指定位置的數(shù)據(jù),Range范圍如果超出服務(wù)器上數(shù)據(jù)范圍, 會以服務(wù)器數(shù)據(jù)末尾為準(zhǔn)  
                                conn.setRequestProperty("Range""bytes=" + start + "-" + end);  
                                RandomAccessFile raf 
            = new RandomAccessFile(file, "rws");  
                                raf.seek(start);  
                                
            //開始讀寫數(shù)據(jù)  
                                InputStream in = conn.getInputStream();  
                                
            byte[] buf = new byte[1024 * 10];  
                                
            int len;  
                                
            while ((len = in.read(buf)) != -1) {  
                                    
            if (isPause) {  
                                        
            //使用線程鎖鎖定該線程  
                                        synchronized (dao) {  
                                            
            try {  
                                                dao.wait();  
                                            } 
            catch (InterruptedException e) {  
                                                e.printStackTrace();  
                                            }  
                                        }  
                                    }  
                                    raf.write(buf, 
            0, len);  
                                    done 
            += len;  
                                    info.setDone(info.getDone() 
            + len);  
                                    
            // 記錄每個線程已下載的數(shù)據(jù)量  
                                    dao.update(info);   
                                    
            //新線程中用Handler發(fā)送消息,主線程接收消息  
                                    Message msg = new Message();  
                                    msg.what 
            = 1;  
                                    msg.getData().putInt(
            "done", done);  
                                    handler.sendMessage(msg);  
                                }  
                                in.close();  
                                raf.close();  
                                
            // 刪除下載記錄  
                                dao.deleteAll(info.getPath(), fileLen);   
                            } 
            catch (IOException e) {  
                                e.printStackTrace();  
                            }  
                        }  
                    }  
                  
                    
            //暫停下載  
                    public void pause() {  
                        isPause 
            = true;  
                    }  
                    
            //繼續(xù)下載  
                    public void resume() {  
                        isPause 
            = false;  
                        
            //恢復(fù)所有線程  
                        synchronized (dao) {  
                            dao.notifyAll();  
                        }  
                    }  
                }  

             

             

            Dao:

             

            DBOpenHelper:
            [java] view plaincopy

                
            public class DBOpenHelper extends SQLiteOpenHelper {  
                  
                    
            public DBOpenHelper(Context context) {  
                        
            super(context, "download.db"null1);  
                    }  
                  
                    @Override  
                    
            public void onCreate(SQLiteDatabase db) {  
                        db.execSQL(
            "CREATE TABLE info(path VARCHAR(1024), thid INTEGER, done INTEGER, PRIMARY KEY(path, thid))");  
                    }  
                  
                    @Override  
                    
            public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
                    }  
                  
                }  


            InfoDao:
            [java] view plaincopy

                
            public class InfoDao {  
                    
            private DBOpenHelper helper;  
                  
                    
            public InfoDao(Context context) {  
                        helper 
            = new DBOpenHelper(context);  
                    }  
                  
                    
            public void insert(Info info) {  
                        SQLiteDatabase db 
            = helper.getWritableDatabase();  
                        db.execSQL(
            "INSERT INTO info(path, thid, done) VALUES(?, ?, ?)"new Object[] { info.getPath(), info.getThid(), info.getDone() });  
                    }  
                  
                    
            public void delete(String path, int thid) {  
                        SQLiteDatabase db 
            = helper.getWritableDatabase();  
                        db.execSQL(
            "DELETE FROM info WHERE path=? AND thid=?"new Object[] { path, thid });  
                    }  
                  
                    
            public void update(Info info) {  
                        SQLiteDatabase db 
            = helper.getWritableDatabase();  
                        db.execSQL(
            "UPDATE info SET done=? WHERE path=? AND thid=?"new Object[] { info.getDone(), info.getPath(), info.getThid() });  
                    }  
                  
                    
            public Info query(String path, int thid) {  
                        SQLiteDatabase db 
            = helper.getWritableDatabase();  
                        Cursor c 
            = db.rawQuery("SELECT path, thid, done FROM info WHERE path=? AND thid=?"new String[] { path, String.valueOf(thid) });  
                        Info info 
            = null;  
                        
            if (c.moveToNext())  
                            info 
            = new Info(c.getString(0), c.getInt(1), c.getInt(2));  
                        c.close();  
                  
                        
            return info;  
                    }  
                  
                    
            public void deleteAll(String path, int len) {  
                        SQLiteDatabase db 
            = helper.getWritableDatabase();  
                        Cursor c 
            = db.rawQuery("SELECT SUM(done) FROM info WHERE path=?"new String[] { path });  
                        
            if (c.moveToNext()) {  
                            
            int result = c.getInt(0);  
                            
            if (result == len)  
                                db.execSQL(
            "DELETE FROM info WHERE path=? "new Object[] { path });  
                        }  
                    }  
                  
                    
            public List<String> queryUndone() {  
                        SQLiteDatabase db 
            = helper.getWritableDatabase();  
                        Cursor c 
            = db.rawQuery("SELECT DISTINCT path FROM info"null);  
                        List
            <String> pathList = new ArrayList<String>();  
                        
            while (c.moveToNext())  
                            pathList.add(c.getString(
            0));  
                        c.close();  
                        
            return pathList;  
                    }  
                  
                }  



            posted on 2012-04-02 14:50 life02 閱讀(1707) 評論(2)  編輯 收藏 引用 所屬分類: Android開發(fā)

            評論

            # re: Android開發(fā)多線程斷點(diǎn)續(xù)傳下載器 (轉(zhuǎn)載) 2012-04-02 14:52 life02
            http://download.csdn.net/download/suijing/3114607  回復(fù)  更多評論
              

            # re: Android開發(fā)多線程斷點(diǎn)續(xù)傳下載器 (轉(zhuǎn)載) 2012-09-13 15:29 25Age
            這個handler是不是只能放在外面?
            還有哪些地方 。  回復(fù)  更多評論
              

            伊人久久大香线蕉无码麻豆| 囯产精品久久久久久久久蜜桃 | 久久无码AV中文出轨人妻| 一级A毛片免费观看久久精品| 国产韩国精品一区二区三区久久| 久久一本综合| 国产精品丝袜久久久久久不卡| 日韩久久久久久中文人妻| 亚洲国产成人精品女人久久久| 亚洲国产成人久久精品动漫| 日韩久久久久久中文人妻 | 欧美亚洲国产精品久久| 国产精品成人久久久久久久| 人妻丰满AV无码久久不卡| 午夜精品久久久久| 久久影院亚洲一区| 国产精品99久久不卡| 99久久精品国产麻豆| 国产亚洲精品久久久久秋霞| 亚洲精品无码久久毛片| 久久国产成人精品国产成人亚洲| 久久91综合国产91久久精品| 久久久免费精品re6| 麻豆AV一区二区三区久久| 亚洲伊人久久精品影院| 亚洲国产小视频精品久久久三级| 国产高潮国产高潮久久久91 | 蜜桃麻豆www久久| 狠狠久久亚洲欧美专区| 国产精品99久久精品| 丁香狠狠色婷婷久久综合| 国产午夜免费高清久久影院| 麻豆成人久久精品二区三区免费| 亚洲国产另类久久久精品小说| 久久天天躁狠狠躁夜夜不卡 | 久久被窝电影亚洲爽爽爽| 午夜精品久久久久久中宇| 性欧美大战久久久久久久久| 无遮挡粉嫩小泬久久久久久久 | 久久久久久久91精品免费观看| 亚洲精品高清一二区久久|