欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android編程開發(fā)實(shí)現(xiàn)多線程斷點(diǎn)續(xù)傳下載器實(shí)例

 更新時間:2016年01月04日 10:19:26   作者:傅榮康  
這篇文章主要介紹了Android編程開發(fā)實(shí)現(xiàn)多線程斷點(diǎn)續(xù)傳下載器,涉及Android多線程,文件傳輸及斷點(diǎn)續(xù)傳的相關(guān)技巧,需要的朋友可以參考下

本文實(shí)例講述了Android編程開發(fā)實(shí)現(xiàn)多線程斷點(diǎn)續(xù)傳下載器。分享給大家供大家參考,具體如下:

使用多線程斷點(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

復(fù)制代碼 代碼如下:
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

<?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

<?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

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

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:

public class DBOpenHelper extends SQLiteOpenHelper {
  public DBOpenHelper(Context context) {
    super(context, "download.db", null, 1);
  }
  @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:

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;
  }
}

希望本文所述對大家Android程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • Android TextView實(shí)現(xiàn)帶鏈接文字事件監(jiān)聽的三種常用方式示例

    Android TextView實(shí)現(xiàn)帶鏈接文字事件監(jiān)聽的三種常用方式示例

    這篇文章主要介紹了Android TextView實(shí)現(xiàn)帶鏈接文字事件監(jiān)聽的方法,結(jié)合實(shí)例形式分析了鏈接跳轉(zhuǎn)、setMovementMethod及布局屬性設(shè)置三種常用的實(shí)現(xiàn)方式,需要的朋友可以參考下
    2017-08-08
  • Android創(chuàng)建服務(wù)之started service詳細(xì)介紹

    Android創(chuàng)建服務(wù)之started service詳細(xì)介紹

    這篇文章主要介紹了Android創(chuàng)建服務(wù)之started service,需要的朋友可以參考下
    2014-02-02
  • 用xutils3.0進(jìn)行下載項(xiàng)目更新

    用xutils3.0進(jìn)行下載項(xiàng)目更新

    這篇文章主要介紹了用xutils3.0進(jìn)行下載項(xiàng)目更新的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-08-08
  • Android NDK開發(fā)(C語言基本數(shù)據(jù)類型)

    Android NDK開發(fā)(C語言基本數(shù)據(jù)類型)

    這篇文章主要介紹了Android NDK開發(fā)中,C語言基本數(shù)據(jù)類型,主要以C語言包含的數(shù)據(jù)類型及基本類型展開相關(guān)資料,需要的朋友可以參考一下
    2021-12-12
  • 簡單談?wù)勎业腁ndroid屏幕適配之路

    簡單談?wù)勎业腁ndroid屏幕適配之路

    我相信Android碎片化問題是讓所有的Android開發(fā)者都比較頭疼的問題.尤其是屏幕適配這一塊兒.想要自己的app在不同的設(shè)備上面都有一個比較好的顯示效果.就必須做好相應(yīng)的屏幕適配.
    2017-11-11
  • Android自定義PopWindow帶動畫向下彈出效果

    Android自定義PopWindow帶動畫向下彈出效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義PopWindow帶動畫向下彈出效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-11-11
  • 淺談Android Dialog窗口機(jī)制

    淺談Android Dialog窗口機(jī)制

    本文主要介紹了Android Dialog窗口機(jī)制,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • android動態(tài)加載布局文件示例

    android動態(tài)加載布局文件示例

    這篇文章主要介紹了android動態(tài)加載布局文件示例,需要的朋友可以參考下
    2014-03-03
  • Android中Dialog對話框的使用小結(jié)

    Android中Dialog對話框的使用小結(jié)

    這篇文章主要給大家總結(jié)了一些關(guān)于Android中Dialog對話框的使用方法,這其中包括普通對話框、確定取消對話框、多按鈕對話框、列表對話框、帶Adapter的對話框、單選對話框以及多選對話框等,需要的朋友可以參考學(xué)習(xí),下面來一起看看詳細(xì)的介紹吧。
    2017-04-04
  • Android夜間模式最佳實(shí)踐

    Android夜間模式最佳實(shí)踐

    這篇文章主要介紹了Android夜間模式最佳實(shí)踐,在Android應(yīng)用普遍支持夜間模式的今天,如何優(yōu)雅地實(shí)現(xiàn)夜間模式?感興趣的小伙伴們可以參考一下
    2016-02-02

最新評論