Android 下載模組,使用Xutils3 的下載功能,Activity和services資料互動,listview顯示下載進度
臨近過年,今天將花了兩天時間寫的下載模組貢獻出來,以前我也是天天需要什麼功能,就天天查百度,現在自己也能開源一點東西了,也是非常很開心的,hahaha。
離職前寫了音樂播放器的音樂下載介面,自己封裝了下載執行緒,並使用多執行緒斷點續傳下載音樂,感覺多執行緒下載音樂也並不比單執行緒下載快多少,就一個4M的音樂來說,開3條執行緒下了46s,單執行緒下了60s,如果同時現在3個音樂,那麼多執行緒下載相當於開了9 個執行緒,速度盡然和單執行緒的速度持平,有時候還會慢於3條執行緒,於是我放棄了多執行緒斷點續傳,還是老老實實寫單執行緒的吧(- -!我覺得應該是我的下載執行緒的毛病,哈哈)。。。
於是今天就用了xutils3的網路訪問模組,實現的需求是。
1、APP關閉後(kill),重新開啟時,能記錄當前下載進度,斷點續傳。
2、音樂能增刪,暫停,顯示下載速度和下載進度。
其實都寫好了哈,主要說說編碼思路。
通過Acitivity的bindService,可以呼叫service的bind來傳遞需要下載的檔案資訊到service,service通過呼叫xutils的帶進度的下載模組,來回調下載資訊,同時service通過下載觀察者不斷觀察下載進度,將進度傳遞給Activity,之後setAdapter即可。
裡面最主要的東西就是DownloadService,所有的程式碼邏輯都是這個類處理的。
傳遞下載檔案資訊的類MainActivity
這個類有個問題,
就是檔名的獲取是根據Url倒敘擷取/後面的檔案來命名的,如果你的url不符合規則,請自行定義。
private String getfileName(String url) {//根據下載地址給下載檔案命名
try{
return url.substring(url.lastIndexOf("/") + 1);
}catch (Exception ex){
return mBinder.getCurrentListSize()+"";//返回一個數字
}
}
許可權問題
程式碼中加了6.0的動態許可權判斷,因為要操作SD卡,所以這裡也要注意。
因為我沒有6.0的測試手機,所以這裡雖然都寫了,但是隻是作為提示使用,需要你自己更改邏輯位置,如果是6.0以下的,並沒有問題的 。
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 0:
Toast.makeText(getBaseContext(),"已獲取SD卡許可權",Toast.LENGTH_SHORT).show();
//6.0系統在這裡進行service的初始化
break;
case 1:
Toast.makeText(getBaseContext(),"SD卡許可權未開啟",Toast.LENGTH_SHORT).show();
break;
}
}
};
//判斷許可權方法
private void initCheckSelfPermission() {
//判斷是否有記憶體卡許可權
CheckSelfPermission.getSDCard(this);
}
//動態許可權回撥
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
doNext(requestCode,grantResults);
}
//動態許可權回撥,yes和no點選
private void doNext(int requestCode, int[] grantResults) {
if (requestCode == DownLoadConstant.WRITE_EXTERNAL_STORAGE_REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
LogUtils.d("許可權獲取成功");
handler.sendEmptyMessage(0);
} else {
handler.sendEmptyMessage(1);
}
}
}
最關鍵的是DownloadService ,bind裡有對外提供的增刪改查方法
在下載的過程中,有快取GetFileSharePreance 不斷在儲存下載的urls下載地址列表和檔案下載進度,為APP下次重啟提供斷點,裡面有詳細註釋。
/**
* 作者:朱亮 on 2017/1/17 15:36
* 郵箱:171422696@qq.com
* 下載服務類,執行下載任務,並將進度傳遞到Activity中(這裡用一句話描述這個方法的作用)
*/
public class DownloadService extends Service {
public static final String ACTION_START = "ACTION_START";
public static final String ACTION_STOP = "ACTION_STOP";
public static final String ACTION_DELETE = "ACTION_DELETE";
private List<OnDownLoadBackListener> loadBackListeners = new ArrayList<OnDownLoadBackListener>();//註冊一個下載觀察者
private static final int DOWNLOADSERVICEID = 1;//下載監聽傳遞值
private FileInfo fileInfo;//下載物件
private MyBinder myBinder = new MyBinder();
private ArrayList<FileInfo> mCurretList;//當前服務中的正在下載列表
private ArrayList<FileInfo> mCurretListOut;//輸出的下載列表
private GetFileSharePreance preance;
private HashMap<Integer,DownloanThread> map;//建立動態物件
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}
@Override
public void onCreate() {
mCurretList = new ArrayList<>();
mCurretListOut = new ArrayList<>();
map = new HashMap<Integer,DownloanThread>();
preance = BaseApplication.getFileSharePreance();//獲取快取例項,這裡的快取主要用在APP關閉後,重新進入下載列表後顯示使用
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
// 獲得Activity穿來的引數
fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo");
if (ACTION_START.equals(intent.getAction())) {
startDownLoad(fileInfo);//開始下載
} else if (ACTION_STOP.equals(intent.getAction())) {
stopDownLoad(fileInfo);//停止下載
} else if (ACTION_DELETE.equals(intent.getAction())) {
deleteDownLoad(fileInfo);//刪除下載
}
}
return super.onStartCommand(intent, flags, startId);
}
//開始下載邏輯處理方法
private void startDownLoad(FileInfo fileInfo) {
if (fileInfo != null && !TextUtils.isEmpty(fileInfo.getUrl())) {
preance.setUrlList(mCurretList);//從快取地址集合中移除這一條(儲存最新的地址集合)
map.put(fileInfo.getId(),new DownloanThread());
map.get(fileInfo.getId()).Download(fileInfo);//開始下載
SPUtils.setLong(getApplicationContext(), SPKey.CURRENTLIST_SIZE, fileInfo.getId());//設定下載ID自增
sendHandler();
}
}
//停止下載邏輯處理方法
private void stopDownLoad(FileInfo fileInfo) {
if (fileInfo != null && !TextUtils.isEmpty(fileInfo.getUrl())) {
if (map.get(fileInfo.getId()) != null) {
map.get(fileInfo.getId()).downLoadCancel();//下載執行緒停止
}
sendHandler();
}
}
//刪除下載邏輯處理方法
private void deleteDownLoad(FileInfo fileInfo) {
if (fileInfo != null && !TextUtils.isEmpty(fileInfo.getUrl())) {
for (int x = 0; x < mCurretList.size(); x++) {//如果是正在下載的列表,先暫停下載。
if (mCurretList.get(x).getUrl().equals(fileInfo.getUrl())) {//如果匹配到了
preance.delete(mCurretList.get(x).getUrl());//刪除下載快取
if(map.get(fileInfo.getId()) != null){
map.get(fileInfo.getId()).downLoadCancel();//從下載執行緒停止
}
mCurretList.remove(mCurretList.get(x));//從下載列表移除這條
preance.setUrlList(mCurretList);//從快取地址集合中移除這一條(儲存最新的地址集合)
preance.delete(fileInfo.getUrl());//刪除快取資料
}
}
sendHandler();
}
}
public class MyBinder extends Binder {
//註冊一個下載觀察者
public void registDownLoadListener(OnDownLoadBackListener loadBackListener) {
loadBackListeners.add(loadBackListener);
}
//取消一個觀察者
public void unregistDownLoadListener(OnDownLoadBackListener loadBackListener) {
loadBackListeners.remove(loadBackListener);
}
//設定當前的下載列表(會清空當前的下載列表哦,慎用,如果需要請用 appendToCurrentList())
public void setCurrentList(ArrayList<FileInfo> list) {
mCurretList.clear();
if (list != null) {
mCurretList.addAll(list);
}
}
//獲取當前的正在下載的所有下載資訊列表
public ArrayList<FileInfo> getCurrentList() {
return mCurretList;
}
//從快取中獲取下載資訊
public ArrayList<FileInfo> getCurrentListFShareP(){
ArrayList<FileInfo> infos = new ArrayList<>();
ArrayList<String> list = preance.getUrlList();//先獲取下載url集合
for(int x = 0 ; x < list.size() ; x++){//根據url地址查詢下載的快取資料
infos.add(preance.getFilePre(list.get(x)));
}
setCurrentList(infos);
return infos;
}
//下載次數自增
public int getCurrentListSize() {
long l = SPUtils.getLong(getApplicationContext(), SPKey.CURRENTLIST_SIZE);
return (int) l + 1;
}
//添加當前的下載列表(相同下載地址檔案過濾)
public void appendToCurrentList(FileInfo info) {
if (info != null) {
// 只添加當前下載列表中沒有的
boolean existed = false;
for (int j = 0; j < mCurretList.size(); j++) {
if ((mCurretList.get(j).getUrl()).equals(info.getUrl())) {
existed = true;
}
}
if (!existed) {
mCurretList.add(info);
startDownLoad(info);//開始下載
}
}
}
//停止下載
public void stopDownLoad(FileInfo fileInfo) {
if (fileInfo != null && !TextUtils.isEmpty(fileInfo.getUrl())) {
stopDownLoad(fileInfo);
}
}
//刪除當前的某一個列表
public void deleyeCurrentList(FileInfo fileInfo) {
deleteDownLoad(fileInfo);
}
//刪除所有的下載列表資訊(未編寫)
public void deleteAll(){
}
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DOWNLOADSERVICEID:
for (int x = 0; x < loadBackListeners.size(); x++) {//有多少個介面在觀察下載資料
mCurretListOut.clear();
for(int j = 0 ; j < mCurretList.size() ;j++){//正在下載列表中的資料
if(map.get(mCurretList.get(j).getId()) == null){//假如下載執行緒沒有開啟
mCurretListOut.add(mCurretList.get(j));
}else {//從下載執行緒中取資料
mCurretListOut.add(map.get(mCurretList.get(j).getId()).getFileInfo());
}
}
loadBackListeners.get(x).onDownloadSize(mCurretListOut);//傳遞給不同的觀察者
}
//當下載的時候,延遲不斷執行這句話,讓所有的觀察者不至於失去下載的各種資訊,這裡控制檢視更新頻率
handler.sendEmptyMessageDelayed(
DOWNLOADSERVICEID, 1000);
break;
default:
super.handleMessage(msg);
}
}
};
//傳送hanlde
private void sendHandler(){
if (!handler.hasMessages(DOWNLOADSERVICEID)) {//如果hanlde的觀察者沒有了,重新發送一個
handler.sendEmptyMessage(DOWNLOADSERVICEID);
}
}
}
下載的實際類DownloanThread,名字看起來是個執行緒,其實不是,只是將實際下載類分離出來,呼叫xutils的下載方法和取消下載方法,提供一個獲取下載檔案詳細資訊方法。
//獲取下載中的檔案資訊
public FileInfo getFileInfo(){
return new FileInfo(fileInfo.getId(),fileInfo.getUrl(),fileInfo.getFileName(),length,downlenth,downType);
}
在這裡回撥檔案的下載資訊
cancelable = x.http().get(params, new Callback.ProgressCallback<File>() {
@Override
public void onWaiting() {
LogUtils.e("等待中...");
downType = 0;
}
@Override
public void onStarted() {
LogUtils.e("開始下載。。。");
downType = 1;
}
@Override
public void onLoading(long total, long current, boolean isDownloading) {
LogUtils.e("tital = "+total + " current = "+current + " isDownLoading = "+isDownloading);
length = (int) total;
downlenth = (int) current;
downType = 2;
preance.update(new FileInfo(info.getId(),info.getUrl(),info.getFileName(),(int)total,(int)current,downType));
}
@Override
public void onSuccess(File result) {
LogUtils.e("下載成功");//在這裡下載成功的資料寫進資料庫裡即可(已下載介面的資料從這裡來的,哈哈,那個介面自己寫)
downType = 3;
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
LogUtils.e("下載失敗");
downType = 4;
}
@Override
public void onCancelled(CancelledException cex) {
LogUtils.e("下載取消");
downType = 5;
}
@Override
public void onFinished() {
LogUtils.e("下載完成");
}
});
最後在Adapter可以根據downType來顯示下載過程中的狀態了
已下載的介面沒有寫程式碼,偷個懶,請自己寫哈
原始碼下載
相關推薦
Android 下載模組,使用Xutils3 的下載功能,Activity和services資料互動,listview顯示下載進度
臨近過年,今天將花了兩天時間寫的下載模組貢獻出來,以前我也是天天需要什麼功能,就天天查百度,現在自己也能開源一點東西了,也是非常很開心的,hahaha。 離職前寫了音樂播放器的音樂下載介面,自己封裝了下載執行緒,並使用多執行緒斷點續傳下載音樂,感覺多執行緒
Android實現登入功能,Android與伺服器資料互動,使用tomcat、mysql實現登入的demo程式,web端和android均可實現登入
1.使用到的開發工具為:Eclipse(Java EE),Android Studio,MYSQL 5.7.21;2.首先在MYSQL資料庫建表,我這裡使用的資料庫視覺化操作軟體為:navicat premium:如圖:這裡你可以取自己喜歡的資料庫名字,但是為了方便起見,我建
java利用jcraft實現和遠端伺服器互動,實現上傳下載檔案
git地址:https://github.com/fusugongzi/upLoadAndDownloadFile 第一步:引入maven支援,新增maven依賴 <!-- https://mvnrepository.com/artifact/com.jcraft
Android Activity之間實現資料(物件,物件集合)傳遞
Android Activity之間實現資料傳遞是一項非常重要的技術,今天我就來講一講如何實現資料傳遞: 1.基本資料傳遞 MainActivity.java Intent intent=new Intent(this,ThinkActivity.cla
android 在selector中同時設定button的圓角和點選效果,簡單顏色無需美工
1,如果我們沒有美工來設計我們的圓角圖片,可以採用shape的方式實現: <?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.andr
爬蟲的編譯器的安裝,pycharm第三方庫的安裝和pip的安裝,爬蟲認知篇(5)
python之所以強大並逐漸流行起來,一部分原因要歸功於的Python的強大的第三方庫。這樣使用者就不用瞭解底層的思想,用最少的程式碼寫出最多的功能。  
前後端資料互動,axios和jquery ajax的區別
axios作為Vue生態系統中濃墨重彩的一筆,我學習這個東西也是花了一定的時間的。剛開始的時候,也是遇到了很多問題。 逐漸摸透了它的脾氣。 首先說說FormData和Payload兩種資料格式的區別: 先是提交一個FormData的請求試試看: 然後我們看後端: 然後
輸入兩個數,輸出其最大公約數和最小公倍數,並輸出所有的公約數
輸入兩個數,求其最大公約數和最小公倍數,並輸出所有的公約數 以下分別用三種方法求最大公約數,詳細程式碼如下: #include <iostream> using namespace std; //求最大公約數:求差法 void div1(int m,int n){ i
FLEX與JS資料互動,以及Google外掛IFrame的使用
最近因為專案需要,用到的flex,同時需要與js做資料互動,同時還用到了Google的外掛IFrame,總結一點點自己的使用心得,其中很多資料都是在網上Google到的。 FLEX呼叫
[Django]在資料庫有表,但是沒有model的情況下對資料查詢,修改
文章目錄連線資料庫查詢資料庫更新資料庫 連線資料庫 from django.db import connection sql = "SELECT id,record_time,lose_time
你必須知道的React的知識點:單向資料流,高效能虛擬DOM,元件間的資料互動,事件與資料的雙向繫結,生命週期鉤子,fetch:資料請求等
1、React除錯工具:React Developer Tools 2、React開發工具:Atom 3、React UI庫:Material-UI / Ant Deaign 4、React適用場景:資料不斷變化的大型應用程式 5、前端UI構建方式:資料模型、UI介面
恆生電子公司的一道筆試題,有一個字串由*號和其他字母組成,請提供函式將字串頭部的*號全部移到字串的尾部(***aqer*f轉換成aqer*f***)
現場筆試的時候沒有寫出來,筆試之後想了一下,就編寫了一下,用的方法很簡單,主要用vector實現的。以下貼上自己編的原始碼: #include<iostream> #include<string> #include<vector> u
安卓實現任意控制元件view可拖拽,並監聽拖拽和點選事件,可自動拉回螢幕邊緣
因為專案中有需要實現控制元件可任意拖拽的需求,所以簡單寫了個自定義OnTouchListener,以作拋磚引玉,歡迎大家提議反饋。 完整實現類如下,程式碼中有詳細註釋: 使用者可以決定是否開啟自動拖拽邊緣功能,可以監聽控制元件的拖拽和點選事件 public cl
爬蟲入門,從第一個爬蟲建立起做蟲師的心,爬蟲的編譯器的安裝,pycharm第三方庫的安裝和pip的安裝,爬蟲的認知篇(5)
Python之所以強大並逐漸流行起來,一部分原因要歸功於Python強大的第三方庫。這樣使用者就不用瞭解底層的思想,用最少的程式碼寫出最多的功能。 在PyCharm中安裝
《ServerSuperIO Designer IDE使用教程》-2.與硬體閘道器資料互動,並進行資料級聯轉發,直到雲端。釋出:v4.2.1版本
v4.2.1 更新內容:1.重新定義資料轉發文字協議,使閘道器與ServerSuperIO以及之間能夠相關互動資料。2.擴充套件ServerSuperIO動態資料類的方法,更靈活。3.修復Designer增加轉發任務的一個BUG。4.修改資料轉發客戶端和服務端。5.增加硬體閘道器驅動。 v4.2.1 下
【運維專家大講堂】雲端計算和大資料時代,資料庫運維工程師發展方向在哪?
本次運維專家大講堂精選2014年6月份ITPUB的採訪,訪談物件是楊志洪,網名boypoo,Oracle ACE成員,現擔任上海新炬網路技術有限公司的技術總監。 開場: 一直以來運維工程師的角色被蒙上了各種神祕面紗,平時他們是默默無聞的幕後工作者,很少被人關注。而一旦企業出現技術故障,大家就會立刻呼
製作一個安卓介面,可以進行密碼和賬號的判斷,有用來儲存輸入賬號和密碼的類,用來在其他類中呼叫
首先附上安卓介面圖和完整版下載地址: 下載地址:https://download.csdn.net/download/qq_39343904/10881646 &nb
【問題記錄】JAVA程序啟動大概率卡住6分鐘左右,應用日誌沒有任何WARN ERROR,系統日誌也沒有發現和程序相關日誌,最後定位TOMCAT SHA1PRNG耗時太長
系統是基於springboot開發的系統,java -jar啟動過程中發現經常會卡住6分鐘左右,才能啟動完成,全程沒有發現任何WANR和ERROR級別的日誌(其實早看看DEBUG和INFO日誌,可能問題早就解決了,慣性思維害人啊),再去檢視/var/log/message系統日誌,也沒發現任何和
為什麼執行spark任務會在hadoop歷史伺服器上看到,而在spark8080埠頁面和work資料夾下面看不到?
通過oozie任務排程工具執行一個spark任務:spark程式:oozie任務:程式成功執行了,但在8080埠頁面看不到,在hadoop 19888歷史伺服器頁面可以看到這是怎麼回事?將上面那個spark程式打成jar包使用spark-sumbit --class 主類 .
Android 實現簡單的登陸註冊功能(SharedPreferences和SQLite)
最近剛好做了一個Android的登入註冊介面,將資料利用SharedPreferences或者SQLite繫結到Android程式中,實現簡單的登陸註冊功能,本文未涉及到與伺服器的交流。 首先,對於登陸註冊要有一個明確的邏輯順序,不管是對於SharedPreferences