麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 系統(tǒng) > Android > 正文

Android實現(xiàn)斷點多線程下載

2019-10-21 21:31:24
字體:
供稿:網(wǎng)友

斷點多線程下載的幾個關(guān)鍵點:①:得到要下載的文件大小后,均分給幾個線程。②:使用RandomAccessFile類進(jìn)行讀寫,可以指定開始寫入的位置。③:數(shù)據(jù)庫保存下載信息,下一次繼續(xù)下載的時候從數(shù)據(jù)庫取出數(shù)據(jù),然后從上次下載結(jié)束的地方開始。

這里我使用了FinalDb的數(shù)據(jù)庫框架,同時在內(nèi)存中存儲了一份所有線程的下載信息,負(fù)責(zé)時時更新和查詢下載進(jìn)度。我測試用的是百度云網(wǎng)盤,文件大小50M左右。注意,線程中指定了開始結(jié)束下載位置的網(wǎng)絡(luò)請求成功的返回碼是206,并不是200。

效果圖:

Android,斷點,多線程

線程類:線程類負(fù)責(zé)具體的下載,線程的下載信息被存儲到了數(shù)據(jù)庫。線程開始下載時,根據(jù)線程ID查詢自己的存儲信息,然后開始從指定的位置下載和寫入文件。完畢后根據(jù)自己的當(dāng)前下載結(jié)果設(shè)置自己當(dāng)前的下載狀態(tài)。時時的下載進(jìn)度存儲只存儲到了內(nèi)存,只在本次下載結(jié)束才存儲到數(shù)據(jù)庫。

 

public class DownloadThread extends Thread {   /**   * 數(shù)據(jù)庫操作工具   */  private FinalDb finalDb;   /**   * 下載狀態(tài):未開始   */  public static final int STATE_READY = 1;   /**   * 下載狀態(tài):下載中   */  public static final int STATE_LOADING = 2;   /**   * 下載狀態(tài):下載暫停中   */  public static final int STATE_PAUSING = 3;   /**   * 下載狀態(tài):下載完成   */  public static final int STATE_FINISH = 4;   /**   * 下載狀態(tài)   */  public int downloadState;   /**   * 線程ID   */  private int threadID;   /**   * 要下載的URL路徑   */  private String url;   /**   * 本線程要下載的文件   */  public RandomAccessFile file;   /**   * 構(gòu)造器   */  public DownloadThread(Context context, int threadID, String downloadUrl, RandomAccessFile randomAccessFile) {    this.threadID = threadID;    this.url = downloadUrl;    this.file = randomAccessFile;    finalDb = DBUtil.getFinalDb(context);  }   @Override  public void run() {    //數(shù)據(jù)庫查詢本線程下載進(jìn)度    List<ThreadDownloadInfoBean> list = finalDb.findAllByWhere(ThreadDownloadInfoBean.class, "threadID='" + threadID + "'");    //下載信息存放到內(nèi)存    if (list.get(0) != null) {      MapUtil.map.put(threadID, list.get(0));    }    //取出實體類    ThreadDownloadInfoBean bean = MapUtil.map.get(threadID);    Utils.Print("bean:" + bean.toString());    InputStream is;    HttpURLConnection conn;    try {      Utils.Print("線程" + threadID + "開始連接");      conn = (HttpURLConnection) new URL(url).openConnection();      conn.setConnectTimeout(5000);      conn.setReadTimeout(5000);      conn.setRequestMethod("GET");      //設(shè)置下載開始和結(jié)束的位置      conn.setRequestProperty("Range", "bytes=" + (bean.startDownloadPosition + bean.downloadedSize) + "-" + bean.endDownloadPosition);      conn.connect();      if (conn.getResponseCode() == 206) {        //更改下載狀態(tài)        downloadState = STATE_LOADING;        bean.downloadState = STATE_LOADING;        Utils.Print("線程" + threadID + "連接成功");        is = conn.getInputStream();        // 1K的數(shù)據(jù)緩沖        byte[] bs = new byte[1024];        // 讀取到的數(shù)據(jù)長度        int len;        //從指定的位置開始下載        file.seek(bean.startDownloadPosition);        // 循環(huán)讀取,當(dāng)已經(jīng)下載的大小達(dá)到了指定的本線程負(fù)責(zé)的大小時跳出循環(huán),線程之間負(fù)責(zé)的文件首尾有重合的話沒有影響,因為寫入的內(nèi)容時相同的        while ((len = is.read(bs)) != -1) {          //不用在這個循環(huán)里面更新數(shù)據(jù)庫          file.write(bs, 0, len);          //時時更新內(nèi)存中的已下載大小信息          bean.downloadedSize += len;          //如果調(diào)用者暫停下載,則跳出結(jié)束方法          if (downloadState == STATE_PAUSING) {            Utils.Print("線程" + threadID + "暫停下載");            break;          }        }        is.close();        file.close();      } else {        Utils.Print("線程" + threadID + "連接失敗");      }      conn.disconnect();      //如果這個線程已經(jīng)下載完了自己負(fù)責(zé)的部分就修改下載狀態(tài)      if (bean.downloadedSize >= bean.downloadTotalSize) {        bean.downloadState = STATE_FINISH;      } else {        bean.downloadState = STATE_PAUSING;      }      //內(nèi)存中信息更新至數(shù)據(jù)庫      finalDb.update(bean, "threadID='" + bean.threadID + "'");    } catch (IOException e) {      Utils.Print("線程" + threadID + "IO異常");      e.printStackTrace();    }  }}

線程信息的封裝類:負(fù)責(zé)存儲每個線程的ID,開始下載的位置,結(jié)束下載的位置,已經(jīng)下載的大小,下載狀態(tài)等;這個類用FinalDb數(shù)據(jù)庫存儲到數(shù)據(jù)庫,一定要寫get,set方法和空參構(gòu)造器

@Table(name = "ThreadInfo")public class ThreadDownloadInfoBean {   /**   * id   */  public int id;   /**   * 線程ID   */  public int threadID;   /**   * 本線程時時下載開始的位置   */  public long startDownloadPosition;   /**   * 本線程時時下載結(jié)束的位置   */  public long endDownloadPosition;   /**   * 本線程負(fù)責(zé)下載的文件大小   */  public long downloadTotalSize;   /**   * 已經(jīng)下載了的文件大小   */  public long downloadedSize;   /**   * 本線程的下載狀態(tài)   */  public int downloadState;   public ThreadDownloadInfoBean() {   }   public ThreadDownloadInfoBean(int downloadState, long downloadedSize, long downloadTotalSize, long endDownloadPosition, long startDownloadPosition, int threadID) {    this.downloadState = downloadState;    this.downloadedSize = downloadedSize;    this.downloadTotalSize = downloadTotalSize;    this.endDownloadPosition = endDownloadPosition;    this.startDownloadPosition = startDownloadPosition;    this.threadID = threadID;  }   public int getId() {    return id;  }   public void setId(int id) {    this.id = id;  }   public int getThreadID() {    return threadID;  }   public void setThreadID(int threadID) {    this.threadID = threadID;  }   public long getStartDownloadPosition() {    return startDownloadPosition;  }   public void setStartDownloadPosition(long startDownloadPosition) {    this.startDownloadPosition = startDownloadPosition;  }   public long getEndDownloadPosition() {    return endDownloadPosition;  }   public void setEndDownloadPosition(long endDownloadPosition) {    this.endDownloadPosition = endDownloadPosition;  }   public long getDownloadTotalSize() {    return downloadTotalSize;  }   public void setDownloadTotalSize(long downloadTotalSize) {    this.downloadTotalSize = downloadTotalSize;  }   public long getDownloadedSize() {    return downloadedSize;  }   public void setDownloadedSize(long downloadedSize) {    this.downloadedSize = downloadedSize;  }   public int getDownloadState() {    return downloadState;  }   public void setDownloadState(int downloadState) {    this.downloadState = downloadState;  }   @Override  public String toString() {    return "ThreadDownloadInfoBean{" +        "id=" + id +        ", threadID=" + threadID +        ", startDownloadPosition=" + startDownloadPosition +        ", endDownloadPosition=" + endDownloadPosition +        ", downloadTotalSize=" + downloadTotalSize +        ", downloadedSize=" + downloadedSize +        ", downloadState=" + downloadState +        '}';  }}

下載工具類:這個類負(fù)責(zé)得到下載文件大小,分配線程下載大小,管理下載線程

 

public class DownUtil {   /**   * 數(shù)據(jù)庫操作工具   */  public FinalDb finalDb;   /**   * 下載狀態(tài):準(zhǔn)備好   */  public static final int STATE_READY = 1;   /**   * 下載狀態(tài):下載中   */  public static final int STATE_LOADING = 2;   /**   * 下載狀態(tài):暫停中   */  public static final int STATE_PAUSING = 3;   /**   * 下載狀態(tài):下載完成   */  public static final int STATE_FINISH = 4;   /**   * 下載狀態(tài)   */  public int downloadState;   /**   * context   */  private Context context;   /**   * 要下載文件的大小   */  public long fileSize;   /**   * 線程集合   */  private ArrayList<DownloadThread> threadList = new ArrayList<>();   /**   * 構(gòu)造器   */  public DownUtil(Context context) {    this.context = context;    finalDb = DBUtil.getFinalDb(context);    judgeDownState();  }   /**   * 初始化時判斷下載狀態(tài)   */  public void judgeDownState() {    //取出數(shù)據(jù)庫中的下載信息,存儲到內(nèi)存中    List<ThreadDownloadInfoBean> list = finalDb.findAll(ThreadDownloadInfoBean.class);    if (list != null && list.size() == DownloadActivity.threadNum) {      for (int i = 0; i < list.size(); i++) {        MapUtil.map.put(i, list.get(i));      }    }    //查詢SP中是否存儲過要下載的文件大小    Long spFileSize = SPUtil.getInstance(context).getLong(DownloadActivity.fileName, 0L);    long downloadedSize = getFinishedSize();    //SP中或者數(shù)據(jù)庫中沒有查詢到說明從沒有進(jìn)行過下載    if (spFileSize == 0 || downloadedSize == 0) {      downloadState = STATE_READY;    } else if (downloadedSize >= spFileSize) {      downloadState = STATE_FINISH;    } else {      downloadState = STATE_PAUSING;      fileSize = spFileSize;    }  }   /**   * 點擊了開始按鈕   */  public void clickDownloadBtn() {    if (downloadState == STATE_READY) {      startDownload();    } else if (downloadState == STATE_PAUSING) {      continueDownload();    }  }   /**   * 進(jìn)入應(yīng)用第一次開始下載   */  private void startDownload() {    //開啟新線程,得到要下載的文件大小    new Thread() {      @Override      public void run() {        try {          HttpURLConnection conn;          conn = (HttpURLConnection) new URL(DownloadActivity.url).openConnection();          conn.setConnectTimeout(5000);          conn.setReadTimeout(5000);          conn.setRequestMethod("GET");          conn.connect();          if (conn.getResponseCode() == 200) {            Utils.Print("DownUtil連接成功");            //得到要下載的文件大小            fileSize = conn.getContentLength();            //得到文件名后綴名            String contentDisposition = new String(conn.getHeaderField("Content-Disposition").getBytes("ISO-8859-1"), "UTF-8");            String fileName = "下載測試" + contentDisposition.substring(contentDisposition.lastIndexOf("."), contentDisposition.lastIndexOf("/""));            //得到存儲路徑            String sdCardPath = context.getExternalFilesDir(null).getPath();            DownloadActivity.fileName = sdCardPath + "/" + fileName;            SPUtil.getInstance(context).saveString(DownloadActivity.FILE_NAME, DownloadActivity.fileName);            SPUtil.getInstance(context).saveLong(DownloadActivity.fileName, fileSize);            /*             * 計算一下每個線程需要分擔(dān)的下載文件大小 比如 總下載量為100 一共有三個線程             * 那么 線程1負(fù)責(zé)0-32,線程2負(fù)責(zé)33-65,線程3負(fù)責(zé)66-99和100,             * 也就是說下載總量除以線程數(shù)如果有余數(shù),那么最后一個線程多下載一個余數(shù)部分             */            //每個線程均分的大小            long threadDownSize = fileSize / DownloadActivity.threadNum;            //線程均分完畢剩余的大小            long leftDownSize = fileSize % DownloadActivity.threadNum;            //創(chuàng)建要寫入的文件            RandomAccessFile file = new RandomAccessFile(DownloadActivity.fileName, "rw");            //設(shè)置文件大小            file.setLength(fileSize);            //關(guān)閉            file.close();            for (int i = 0; i < DownloadActivity.threadNum; i++) {              Utils.Print("開啟線程" + i);              //指定每個線程開始下載的位置              long startPosition = i * threadDownSize;              //指定每個線程負(fù)責(zé)下載的大小,當(dāng)現(xiàn)場是集合里面最后一個線程的時候,它要增加leftDownSize的大小              threadDownSize = i == DownloadActivity.threadNum - 1 ? threadDownSize + leftDownSize : threadDownSize;              //存儲線程信息              ThreadDownloadInfoBean bean = new ThreadDownloadInfoBean(DownloadThread.STATE_READY, 0, threadDownSize, startPosition + threadDownSize, startPosition, i);              finalDb.save(bean);              RandomAccessFile threadFile = new RandomAccessFile(DownloadActivity.fileName, "rw");              threadList.add(new DownloadThread(context, i, DownloadActivity.url, threadFile));              threadList.get(i).start();            }            downloadState = STATE_LOADING;            downloadInfoListener.connectSuccess();          } else {            Utils.Print("DownUtil-連接失敗");            downloadInfoListener.connectFail();          }          conn.disconnect();        } catch (IOException e) {          Utils.Print("DownUtil-IO異常");          downloadInfoListener.IOException();          e.printStackTrace();        }      }    }.start();  }   /**   * 繼續(xù)下載   */  private void continueDownload() {    List<ThreadDownloadInfoBean> list = finalDb.findAll(ThreadDownloadInfoBean.class);    for (int i = 0; i < DownloadActivity.threadNum; i++) {      //當(dāng)前線程已經(jīng)下載完了就不再開啟      if (list.get(i).downloadState != DownloadThread.STATE_FINISH) {        Utils.Print("重新開啟線程" + i);        RandomAccessFile threadFile = null;        try {          threadFile = new RandomAccessFile(DownloadActivity.fileName, "rw");        } catch (FileNotFoundException e) {          e.printStackTrace();        }        DownloadThread downloadThread = new DownloadThread(context, i, DownloadActivity.url, threadFile);        threadList.add(downloadThread);        downloadThread.start();      }    }    downloadState = STATE_LOADING;    downloadInfoListener.connectSuccess();  }   /**   * 點擊了暫停的按鈕   */  public void clickPauseBtn() {    if (downloadState == STATE_LOADING) {      stopDownload();    }  }   /**   * 暫停下載   */  private void stopDownload() {    for (int i = 0; i < threadList.size(); i++) {      if (threadList.get(i).downloadState == DownloadThread.STATE_LOADING) {        threadList.get(i).downloadState = DownloadThread.STATE_PAUSING;      }    }    downloadState = STATE_PAUSING;    threadList.clear();  }   /**   * 返回此刻所有線程完成的下載大小   */  public long getFinishedSize() {    long totalSize = 0;    for (int i = 0; i < DownloadActivity.threadNum; i++) {      ThreadDownloadInfoBean bean = MapUtil.map.get(i);      if (bean != null) {        //如果該線程已經(jīng)下載的部分大于分配給它的部分多余部分不予計算        long addSize = bean.downloadedSize > bean.downloadTotalSize ? bean.downloadTotalSize : bean.downloadedSize;        totalSize += addSize;      }    }    return totalSize;  }   /**   * 下載信息監(jiān)聽器   */  private DownloadInfoListener downloadInfoListener;   /**   * 下載信息監(jiān)聽器   */  public interface DownloadInfoListener {     void connectSuccess();     void connectFail();     void IOException();  }   /**   * 設(shè)置下載信息監(jiān)聽器   */  public void setDownloadInfoListener(DownloadInfoListener downloadInfoListener) {    this.downloadInfoListener = downloadInfoListener;  } }

頁面Activity:負(fù)責(zé)展示下載進(jìn)度等信息,提供操作頁面

public class DownloadActivity extends BaseActivity {   /**   * 下載地址輸入框   */  private EditText et_download_url;   /**   * 確定輸入地址的按鈕   */  private Button btn_download_geturl;   /**   * 進(jìn)度條   */  private NumberProgressView np_download;   /**   * 開始下載的按鈕   */  private Button btn_download_start;   /**   * 暫停下載的按鈕   */  private Button btn_download_pause;   /**   * 取消下載的按鈕   */  private Button btn_download_cancel;   /**   * 文件信息顯示   */  private TextView tv_download_file_info;   /**   * 下載速度顯示   */  private TextView tv_download_speed;   /**   * 顯示下載信息   */  private TextView tv_download_speed_info;   /**   * 每隔一段時間刷新下載進(jìn)度顯示   */  private final static int WHAT_INCREACE = 1;   /**   * 得到了文件名稱   */  private final static int WHAT_GET_FILENAME = 2;   /**   * downUtil連接失敗   */  private final static int WHAI_CONNECT_FAIL = 3;   /**   * downUtilIO異常   */  private final static int WHAT_IO_EXCEPTION = 4;   /**   * 下載工具   */  private DownUtil downUtil;   /**   * 需要開啟的線程數(shù)量   */  public static final int threadNum = 5;   /**   * 存放文件路徑名稱的SP鍵名   */  public static final String FILE_NAME = "fileName";   /**   * 要下載的文件的url地址   */  public static String url = "";    /**   * 文件下載路徑和文件名稱   */  public static String fileName;   /**   * 上次統(tǒng)計已經(jīng)完成下載的文件大小   */  private long lastFinishedSize;   private Handler handler = new Handler() {    @Override    public void handleMessage(Message msg) {      super.handleMessage(msg);      switch (msg.what) {        case WHAT_INCREACE:          updateView();          break;        case WHAT_GET_FILENAME:          tv_download_file_info.setText("下載路徑:" + fileName);          break;        case WHAI_CONNECT_FAIL:          tv_download_file_info.setText("連接失敗");          break;        case WHAT_IO_EXCEPTION:          tv_download_file_info.setText("IO異常");          break;      }    }  };   /**   * 更新視圖   */  private void updateView() {    //當(dāng)前已經(jīng)完成下載的文件大小    long currentFinishedSize = downUtil.getFinishedSize();    //要顯示的下載信息的文字    StringBuilder downloadInfo = new StringBuilder();    tv_download_speed.setText("當(dāng)前下載速度:" + formateSize(currentFinishedSize - lastFinishedSize) + "/s");    //本次統(tǒng)計比上次統(tǒng)計增加了,更新視圖,本次統(tǒng)計較上次統(tǒng)計沒有變化,不做視圖更新    if (currentFinishedSize > lastFinishedSize) {      lastFinishedSize = currentFinishedSize;      downloadInfo.append("下載進(jìn)度:" + formateSize(currentFinishedSize) + "/" + formateSize(downUtil.fileSize) + "/n");      for (int i = 0; i < threadNum; i++) {        ThreadDownloadInfoBean bean = MapUtil.map.get(i);        if (bean.downloadTotalSize != 0) {          downloadInfo.append("線程" + i + "下載進(jìn)度:" + bean.downloadedSize * 100 / bean.downloadTotalSize + "%  " + formateSize(bean.downloadedSize) + "/" + formateSize(bean.downloadTotalSize) + "/n");        }      }      np_download.setProgress((int) (currentFinishedSize * 100 / downUtil.fileSize));      tv_download_speed_info.setText(downloadInfo);      //下載完成后      if (currentFinishedSize >= downUtil.fileSize) {        tv_download_speed.setText("下載完畢");        handler.removeMessages(WHAT_INCREACE);        return;      }    }    handler.sendEmptyMessageDelayed(WHAT_INCREACE, 1000);  }   /**   * 返回子類要顯示的布局 R.layout......   */  @Override  protected int childView() {    return R.layout.activity_download;  }   /**   * 強制子類實現(xiàn)該抽象方法,初始化各自的View   */  @Override  protected void findChildView() {    et_download_url = (EditText) findViewById(R.id.et_download_url);    btn_download_geturl = (Button) findViewById(R.id.btn_download_geturl);    np_download = (NumberProgressView) findViewById(R.id.np_download);    btn_download_start = (Button) findViewById(R.id.btn_download_start);    btn_download_pause = (Button) findViewById(R.id.btn_download_pause);    btn_download_cancel = (Button) findViewById(R.id.btn_download_cancel);    tv_download_file_info = (TextView) findViewById(R.id.tv_download_file_info);    tv_download_speed = (TextView) findViewById(R.id.tv_download_speed);    tv_download_speed_info = (TextView) findViewById(R.id.tv_download_speed_info);  }   /**   * 強制子類實現(xiàn)該抽象方法,初始化各自數(shù)據(jù)   */  @Override  protected void initChildData() {    downUtil = new DownUtil(this);    lastFinishedSize = downUtil.getFinishedSize();    StringBuilder downloadInfo = new StringBuilder();    fileName = SPUtil.getInstance(this).getString(FILE_NAME, null);    if (fileName != null) {      downloadInfo.append("下載路徑:" + fileName);      if (downUtil.downloadState == DownUtil.STATE_FINISH) {        np_download.setProgress(100);      } else if (downUtil.downloadState == DownUtil.STATE_PAUSING) {        np_download.setProgress((int) (downUtil.getFinishedSize() * 100 / downUtil.fileSize));      }      tv_download_file_info.setText(downloadInfo);    }  }   /**   * 強制子類實現(xiàn)該抽象方法,設(shè)置自己的監(jiān)聽器   */  @Override  protected View[] setChildListener() {    downUtil.setDownloadInfoListener(new DownUtil.DownloadInfoListener() {       @Override      public void connectSuccess() {        //不能在此更新,需要到主線程刷新UI        handler.sendEmptyMessage(WHAT_GET_FILENAME);        handler.sendEmptyMessage(WHAT_INCREACE);      }       @Override      public void connectFail() {        handler.sendEmptyMessage(WHAI_CONNECT_FAIL);      }       @Override      public void IOException() {        handler.sendEmptyMessage(WHAT_IO_EXCEPTION);      }    });    return new View[]{btn_download_start, btn_download_pause, btn_download_geturl, btn_download_cancel};  }   /**   * 子類在這個方法里面實現(xiàn)自己View的點擊監(jiān)聽事件的相應(yīng)   *   * @param v 父類傳遞到子類的點擊的View   */  @Override  protected void clickChildView(View v) {    switch (v.getId()) {       case R.id.btn_download_start:        downUtil.clickDownloadBtn();        break;       case R.id.btn_download_pause:        downUtil.clickPauseBtn();        handler.removeMessages(WHAT_INCREACE);        break;       case R.id.btn_download_cancel:        //停止發(fā)送消息        handler.removeMessages(WHAT_INCREACE);        //暫停下載        downUtil.clickPauseBtn();        //重置狀態(tài)        downUtil.downloadState = DownUtil.STATE_READY;        //統(tǒng)計下載的大小歸零        lastFinishedSize = 0;        //重置文本信息        tv_download_speed.setText("");        tv_download_file_info.setText("");        tv_download_speed_info.setText("");        //進(jìn)度條歸零        np_download.setProgress(0);        //清空內(nèi)存數(shù)據(jù)        MapUtil.map.clear();        //sp清理        SPUtil.getInstance(this).removeAll();        //清空數(shù)據(jù)庫        downUtil.finalDb.deleteAll(ThreadDownloadInfoBean.class);        //刪除文件        if (fileName != null) {          File file = new File(fileName);          if (file.exists()) {            boolean delete = file.delete();            if (delete) {              Utils.ToastS(this, "刪除" + fileName + "成功");            } else {              Utils.ToastS(this, "刪除失敗");            }          } else {            Utils.ToastS(this, "文件不存在");          }        } else {          Utils.ToastS(this, "文件不存在");        }        break;       case R.id.btn_download_geturl:        String editTextUrl = et_download_url.getText().toString();        if (editTextUrl.trim().equals("")) {          Utils.ToastS(this, "請輸入地址");        } else {          url = editTextUrl;        }        break;    }  }   @Override  protected void onDestroy() {    handler.removeCallbacksAndMessages(null);    downUtil.clickPauseBtn();    super.onDestroy();  }   /**   * 格式化數(shù)據(jù)大小   */  private String formateSize(long size) {    return Formatter.formatFileSize(this, size);  } }

布局

<?xml version="1.0" encoding="utf-8"?><LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:tools="http://schemas.android.com/tools"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical"  tools:context="com.example.testdemo.activity.DownloadActivity">   <LinearLayout    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal">     <EditText      android:id="@+id/et_download_url"      android:layout_width="0dp"      android:layout_height="wrap_content"      android:layout_weight="1"      android:hint="輸入下載地址"/>     <Button      android:id="@+id/btn_download_geturl"      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:text="確定"/>   </LinearLayout>   <com.example.testdemo.view.NumberProgressView    android:id="@+id/np_download"    android:layout_width="match_parent"    android:layout_height="100dp">  </com.example.testdemo.view.NumberProgressView>   <LinearLayout    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal">     <Button      android:id="@+id/btn_download_start"      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:text="開始下載"/>     <Button      android:id="@+id/btn_download_pause"      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:text="暫停下載"/>     <Button      android:id="@+id/btn_download_cancel"      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:text="取消下載"/>   </LinearLayout>   <TextView    android:id="@+id/tv_download_file_info"    android:layout_width="match_parent"    android:layout_height="wrap_content"/>   <TextView    android:id="@+id/tv_download_speed"    android:layout_width="match_parent"    android:layout_height="wrap_content"/>   <TextView    android:id="@+id/tv_download_speed_info"    android:layout_width="match_parent"    android:layout_height="wrap_content"/> </LinearLayout>

下載Activity的父類

public abstract class BaseActivity extends Activity {   /**   * 點擊監(jiān)聽器,子類也可以使用   */  protected BaseOnClickListener onClickListener = new BaseOnClickListener();   /**   * 在onCreate方法里面,找到視圖,初始化數(shù)據(jù),設(shè)置點擊監(jiān)聽器   */  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(childView());    findView();    initData();    setListener();  }   /**   * 返回子類要顯示的布局 R.layout......   */  protected abstract int childView();   /**   * 找到需要的視圖---網(wǎng)址:https://www.buzzingandroid.com/tools/android-layout-finder/   */  private void findView() {    findChildView();  }   /**   * 初始化數(shù)據(jù)   */  private void initData() {    // 初始化子類的數(shù)據(jù)    initChildData();  }   /**   * 對需要設(shè)置監(jiān)聽 的視圖設(shè)置監(jiān)聽   */  private void setListener() {    // 子類實現(xiàn)setChildListene()方法,返回一個View數(shù)組,里面包含所有需要設(shè)置點擊監(jiān)聽的View,然后進(jìn)行For循環(huán),對里面所有View設(shè)置監(jiān)聽器    if (setChildListener() == null || setChildListener().length == 0) {      return;    }    View[] viewArray = setChildListener();    for (View view : viewArray) {      view.setOnClickListener(onClickListener);    }  }   /**   * 自定義的點擊監(jiān)聽類   */  protected class BaseOnClickListener implements View.OnClickListener {    @Override    public void onClick(View v) {      clickChildView(v);    }  }   /**   * 強制子類實現(xiàn)該抽象方法,初始化各自的View   */  protected abstract void findChildView();   /**   * 強制子類實現(xiàn)該抽象方法,初始化各自數(shù)據(jù)   */  protected abstract void initChildData();   /**   * 強制子類實現(xiàn)該抽象方法,設(shè)置自己的監(jiān)聽器   */  protected abstract View[] setChildListener();   /**   * 子類在這個方法里面實現(xiàn)自己View的點擊監(jiān)聽事件的相應(yīng)   *   * @param v 父類傳遞到子類的點擊的View   */   protected abstract void clickChildView(View v); }

得到數(shù)據(jù)庫的操作類

public class DBUtil {   public static FinalDb getFinalDb(final Context context) {     FinalDb finalDb = FinalDb.create(context, "REMUXING.db", false, 1, new FinalDb.DbUpdateListener() {      @Override      public void onUpgrade(SQLiteDatabase db, int oldVirsion, int newVirsion) {       }    });    return finalDb;  }}

內(nèi)存中存儲下載信息的類

public class MapUtil {  public static HashMap<Integer, ThreadDownloadInfoBean> map = new HashMap<>();}

SP存儲的工具類

public enum SPUtil {   SPUTIL;   public static final String NOTIFICATIONBAR_HEIGHT = "notificationbar_height";   private static SharedPreferences sp;   public static SPUtil getInstance(Context context) {     if (sp == null) {      sp = context.getSharedPreferences("REMUXING", Context.MODE_PRIVATE);    }    return SPUTIL;  }   public void saveLong(String key, Long value) {    sp.edit().putLong(key, value).apply();  }   public Long getLong(String key, Long defValue) {    return sp.getLong(key, defValue);  }   public void saveString(String key, String value) {    sp.edit().putString(key, value).apply();  }   public String getString(String key, String defValue) {    return sp.getString(key, defValue);  }   public void removeAll() {    sp.edit().clear().apply();  } }

工具類

public class Utils {   /**   * 打印   */  public static void Print(String message) {    Log.e("TAG", "-----   " + message + "   ------") ;  }   /**   * 短吐司   */  public static void ToastS(Context context, String message) {    Toast.makeText(context, message, Toast.LENGTH_SHORT).show();  }}

進(jìn)度條:這個可以忽略,用安卓原生的,代碼看我的另一篇博客:Android自定義View實現(xiàn)水平帶數(shù)字百分比進(jìn)度條

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 草草在线视频 | 日本韩国欧美一级片 | 在线a毛片| 成人免费入口 | 亚洲精品欧美二区三区中文字幕 | 国产亚洲精品网站 | 精品爱爱 | 免费观看9x视频网站在线观看 | 国产1区2区3区中文字幕 | 日本欧美中文字幕 | 欧美日本亚洲视频 | av免费在线播放网址 | 久久精品一区二区三区不卡牛牛 | 欧美三级一级 | 羞羞网站 | 91成人在线免费 | 97超级碰碰人国产在线观看 | 黄色影院网站 | 一本色道久久久888 香蕉视频99 | 欧美十区 | 农村寡妇偷毛片一级 | 成人免费看视频 | 无遮挡一级毛片视频 | 香蕉视频h| 九九热在线精品视频 | 亚洲最大中文字幕 | 91九色视频观看 | 成人啪啪色婷婷久 | 欧美人xxx| 久久国产免费视频 | 国产正在播放 | 国产资源在线观看视频 | 成人性视频在线 | 久精品久久 | 手机视频在线播放 | 日韩黄色免费观看 | 国产精品色综合 | 在线成人免费网站 | 一区二区三区欧美在线观看 | 国产精品亚洲一区二区三区久久 | 中文字幕 亚洲一区 |