Android類FileDownloadList分析
先上代碼,再來(lái)分析
public class FileDownloadList { /**上下文*/ private Context mContext; /**請(qǐng)求對(duì)象*/ private BaseRequestLims fileRequest = null; /**進(jìn)度條對(duì)話框*/ private AlertDialog progressDialog = null; /**進(jìn)度條控件變量*/ private ProgressBar mProgress; /**百分比顯示控件*/ private TextView mProgressPercent; private File localFile = null; /**接收HttpHelper中獲取到文件大小后發(fā)送的廣播,確定文件大小*/ private DownLoadReceiver receiver; /**文件大小*/ private long fileLength = -1L; /**是否已注冊(cè)廣播標(biāo)志*/ private boolean castFlag = false; /**是否顯示進(jìn)度條標(biāo)志*/ private boolean showDialog = false; /**文件下載完的回調(diào)接口*/ private Runnable mCallback = null; private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); int tempSize = (int)localFile.length(); if(tempSize < fileLength){ //文件下載中 if(showDialog){ //顯示了進(jìn)度條的情況下,更新進(jìn)度條 int progress = (int)((Double.valueOf(tempSize) / Double.valueOf(fileLength)) * 100); mProgress.setProgress(tempSize); mProgressPercent.setText(progress + "%"); } }else{ //下載文件完畢 if(castFlag){//如已注冊(cè)廣播,注銷廣播 mContext.unregisterReceiver(receiver); castFlag = false; } if(showDialog){ mProgress.setProgress((int)fileLength); mProgressPercent.setText("100%"); progressDialog.dismiss(); } if(mCallback != null){ try{ Thread.sleep(500); mCallback.run(); }catch (Exception e) { e.printStackTrace(); } } } } }; /** * 構(gòu)造器 * @param activity */ /** * 構(gòu)造器 * @param activity * @param showDialog 顯示進(jìn)度條標(biāo)志 */ public FileDownloadList(Context context, boolean showDialog){ mContext = context; this.showDialog = showDialog; fileRequest = new BaseRequestLims(context,ClientServiceType.FILE_DOWN); fileRequest.setMethodType(BaseRequestLims.METHOD_TYPE_POST); fileRequest.setContext(mContext); } public BaseRequestLims getFileRequest(){ return fileRequest; } /** * 通過(guò)關(guān)聯(lián)類型來(lái)下載文件 * @param fileName 文件名稱或文件在服務(wù)器上的相對(duì)路徑加名稱 * @param saveDir 保存在本地的文件目錄 * @param saveName 保存在本地的文件名稱 * @param gllx 關(guān)聯(lián)類型 * @param callback 下載后的處理線程 */ public void downloadFile(String fileName, String saveDir, String saveName, Runnable callback){ if(callback != null){ mCallback = callback; } File saveDirFile = new File(saveDir); //judge the save dir path exist or not if(!saveDirFile.exists()){ saveDirFile.mkdirs(); } localFile = new File(saveDir,saveName); if(localFile.isDirectory()){ new AlertDialog.Builder(mContext).setTitle("提示").setMessage("the save file is directory").show(); return; } if(fileRequest.getServiceType()==null){ fileRequest.setServiceType(ClientServiceType.FILE_DOWN); } fileRequest.addParameter("fpath", fileName); fileRequest.addParameter("fname", saveName); fileRequest.setStreamPath(localFile.getAbsolutePath()); fileRequest.setStream(true); if(localFile.exists()){ if(localFile.length() == 0){ invokeFile(fileRequest); }else{ //文件存在直接打開(kāi) if(showDialog) buildProgressDialog().show(); mHandler.sendMessage(mHandler.obtainMessage()); } }else{ invokeFile(fileRequest); } } /** * 進(jìn)入文件下載子線程 * @param request */ private void invokeFile(final BaseRequestLims request){ try{ if(showDialog){ buildProgressDialog().show(); } receiver = new DownLoadReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction("SAVE_DOWNLOAD_FILE"); mContext.registerReceiver(receiver, filter); castFlag = true; //下載的子線程 new Thread(){ @Override public void run() { super.run(); HttpHelper.invoke(request); } }.start(); }catch (Exception e) { e.printStackTrace(); } } /** * 創(chuàng)建進(jìn)度對(duì)話框 * @return */ private AlertDialog buildProgressDialog(){ AlertDialog.Builder builder = new Builder(mContext); builder.setTitle("正在下載文件,請(qǐng)稍候..."); RelativeLayout container = new RelativeLayout(mContext); mProgress = new ProgressBar(mContext); mProgress.setId("progress".hashCode()); BeanUtils.setFieldValue(mProgress, "mOnlyIndeterminate", Boolean.valueOf(false)); mProgress.setIndeterminate(false); LayerDrawable layerDrawable = (LayerDrawable)mContext.getResources().getDrawable(android.R.drawable.progress_horizontal); ClipDrawable clipDrawable = (ClipDrawable)layerDrawable.getDrawable(2); clipDrawable.setColorFilter(Color.parseColor("#32B5E5"), Mode.SRC_IN); mProgress.setProgressDrawable(layerDrawable); mProgress.setPadding(0, 0, 0, 0); mProgress.setIndeterminateDrawable( mContext.getResources().getDrawable(android.R.drawable.progress_indeterminate_horizontal)); mProgressPercent = new TextView(mContext); mProgressPercent.setId("percent".hashCode()); mProgressPercent.setText("0%"); mProgressPercent.setTextSize(18); int containerPadding = DimensionUtils.dip2Px(mContext, 10); container.setPadding(containerPadding, containerPadding, containerPadding, containerPadding); LayoutParams progressLayoutParams = new LayoutParams( LayoutParams.MATCH_PARENT, DimensionUtils.dip2Px(mContext, 4)); progressLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL); progressLayoutParams.addRule(RelativeLayout.LEFT_OF, mProgressPercent.getId()); mProgress.setLayoutParams(progressLayoutParams); LayoutParams percentLayoutParams = new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); percentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); percentLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL); mProgressPercent.setLayoutParams(percentLayoutParams); container.addView(mProgressPercent); container.addView(mProgress); builder.setView(container); builder.setNegativeButton("取消", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); progressDialog = builder.create(); return progressDialog; } class DownLoadReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { //顯示進(jìn)度條 fileLength = intent.getLongExtra("FILE_LENGTH", -1); if(showDialog){ mProgress.setMax((int)fileLength); } //更新進(jìn)度條的線程 new Thread(){ @Override public void run() { super.run(); while(true){ try{ Thread.sleep(500); }catch (Exception e) { e.printStackTrace(); } mHandler.sendMessage(mHandler.obtainMessage()); //獲取下載文件的大小 int loadedSize = (int)localFile.length(); if(loadedSize >= fileLength){ break; } } } }.start(); } } public DownLoadReceiver getReciver() { return receiver; } }
它的邏輯:
創(chuàng)建一個(gè)FileDownloadList對(duì)象后,就可以直接使用該下述方法來(lái)實(shí)現(xiàn)下載功能。
downloadFile(String fileName, String saveDir, String saveName, Runnable callback)
在實(shí)現(xiàn)上是這么個(gè)意思:
1.在當(dāng)前上下文,開(kāi)啟下載線程。當(dāng)獲取到要下載的文件的大小時(shí),發(fā)送一個(gè)廣播過(guò)來(lái)(這部分沒(méi)有展示在上述代碼中)。
2.在當(dāng)前上下文中,注冊(cè)一個(gè)廣播監(jiān)聽(tīng)器,監(jiān)聽(tīng)廣播標(biāo)識(shí)為SAVE_DOWNLOAD_FILE的廣播。首次監(jiān)聽(tīng)到發(fā)出來(lái)的廣播后,首次發(fā)送過(guò)來(lái)的廣播,包含了要下載的文件的大小信息,然后就每隔5毫秒檢測(cè)本地文件的大小,直到本地文件的大小(loadedSize)大于等于要下載的文件(fileLength)大小時(shí),退出該循環(huán)。
在不斷檢測(cè)的過(guò)程中,通過(guò)mHandler.sendMessage(mHandler.obtainMessage()); ,讓UI線程更新進(jìn)度條。
下載線程,會(huì)不斷將服務(wù)器返回的數(shù)據(jù)流,寫到本地文件中,所以,本地文件的大小會(huì)不斷變化,直到,它的大小跟要下載的文件的大小相等時(shí),就退出這個(gè)不斷檢測(cè)本地文件大小的線程。
其它沒(méi)有在上述代碼中表現(xiàn)出來(lái)的內(nèi)容(在其它部分的代碼中):
1.在invokeFile( final BaseRequestLims request)方法中,開(kāi)了一個(gè)如下的下載線程.該下載線程,會(huì)將服務(wù)器返回的文件流,寫到本地文件(localFile)中;然后,它還會(huì)發(fā)送一個(gè)標(biāo)識(shí)為SAVE_DOWNLOAD廣播,包含的信息有要下載文件的文件大小fileLength。
//下載的子線程 new Thread(){ @Override public void run() { super.run(); HttpHelper.invoke(request); } }.start();
上述代碼存在的問(wèn)題:
1.上下文,使用的是某個(gè)Activity,如果發(fā)生系統(tǒng)調(diào)用了該Activity的onDestroy()時(shí),下載線程還沒(méi)有完成,也就意味著,loadedSize的大小還是小于fileLength。從而,那個(gè)不斷檢測(cè)本地文件大小的線程就一直在執(zhí)行著。
即是檢測(cè)本地文件大小的線程和下載線程還在執(zhí)行著:
檢測(cè)本地文件大小的線程:
new Thread(){ @Override public void run() { super.run(); while(true){ try{ Thread.sleep(500); }catch (Exception e) { e.printStackTrace(); } mHandler.sendMessage(mHandler.obtainMessage()); //獲取下載文件的大小 int loadedSize = (int)localFile.length(); if(loadedSize >= fileLength){ break; } } } }.start();
下載線程:
new Thread(){ @Override public void run() { super.run(); HttpHelper.invoke(request); } }.start();
那么,會(huì)出現(xiàn)什么問(wèn)題呢?
1).我可以確定的就是,mContext會(huì)出現(xiàn)泄漏。
2). DownLoadReceiver不能正常被取消注冊(cè)。
分析,待續(xù)。
- Android學(xué)習(xí)筆記-保存文件(Saving Files)
- android實(shí)現(xiàn)Uri獲取真實(shí)路徑轉(zhuǎn)換成File的方法
- android開(kāi)發(fā)教程之獲取power_profile.xml文件的方法(android運(yùn)行時(shí)能耗值)
- Android編程中FileOutputStream與openFileOutput()的區(qū)別分析
- Android 數(shù)據(jù)存儲(chǔ)之 FileInputStream 工具類及FileInputStream類的使用
- Android采用File形式保存與讀取數(shù)據(jù)的方法
- Android編程實(shí)現(xiàn)文件瀏覽功能的方法【類似于FileDialog的功能】
- Android數(shù)據(jù)持久化之Preferences機(jī)制詳解
- 詳解Android開(kāi)發(fā)數(shù)據(jù)持久化之文件存儲(chǔ)(附源碼)
- Android仿QQ好友列表分組實(shí)現(xiàn)增刪改及持久化
- Android持久化技術(shù)之SharedPreferences存儲(chǔ)實(shí)例詳解
- Android持久化技術(shù)之文件的讀取與寫入實(shí)例詳解
- Android數(shù)據(jù)持久化之File機(jī)制分析
相關(guān)文章
Android 消息機(jī)制以及handler的內(nèi)存泄露
這篇文章主要介紹了Android 消息機(jī)制以及handler的內(nèi)存泄露的相關(guān)資料,需要的朋友可以參考下2016-09-09android教程之使用popupwindow創(chuàng)建菜單示例
這篇文章主要介紹了android使用popupwindow創(chuàng)建菜單的示例,需要的朋友可以參考下2014-02-02Android實(shí)時(shí)獲取攝像頭畫(huà)面?zhèn)鬏斨罰C端思路詳解
這篇文章主要介紹了Android實(shí)時(shí)獲取攝像頭畫(huà)面?zhèn)鬏斨罰C端思路詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07Android studio listview實(shí)現(xiàn)列表數(shù)據(jù)顯示 數(shù)據(jù)循環(huán)顯示效果
這篇文章主要介紹了Android studio listview實(shí)現(xiàn)列表數(shù)據(jù)顯示 數(shù)據(jù)循環(huán)顯示功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04android?原生安全音量配置邏輯設(shè)計(jì)詳解
這篇文章主要為大家介紹了android?原生安全音量配置邏輯設(shè)計(jì)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Android開(kāi)發(fā)實(shí)現(xiàn)SubMenu選項(xiàng)菜單和子菜單示例
這篇文章主要介紹了Android開(kāi)發(fā)實(shí)現(xiàn)SubMenu選項(xiàng)菜單和子菜單,結(jié)合實(shí)例形式分析了Android開(kāi)發(fā)中SubMenu選項(xiàng)菜單和子菜單的功能、配置、布局等相關(guān)操作技巧,需要的朋友可以參考下2019-03-03Android數(shù)據(jù)庫(kù)SD卡創(chuàng)建和圖片存取操作
這篇文章主要介紹了Android數(shù)據(jù)庫(kù)SD卡創(chuàng)建和圖片存取操作的相關(guān)資料,需要的朋友可以參考下2017-04-04android ItemTouchHelper實(shí)現(xiàn)可拖拽和側(cè)滑的列表的示例代碼
本篇文章主要介紹了ItemTouchHelper實(shí)現(xiàn)可拖拽和側(cè)滑的列表的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02快速解決Android7.0下沉浸式狀態(tài)欄變灰的問(wèn)題
下面小編就為大家分享一篇快速解決Android7.0下沉浸式狀態(tài)欄變灰的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01