837
技術社區[雲棲]
Android實現單線程異步多文件下載的代碼
現在有一個需求,需要下載的文件有很多個,放在一個開放端口(URL)的目錄下,這個目錄下的文件會變動,就是文件名不定。現在需要把這個目錄下的文件下載到Android設備上。我找了很多資料,發現不能把一個URL目錄下的全部文件以文件名的方式列出來(?)。那麼,把需要下載的多個文件打包成一個.zip文件放到URL上,下載下來後再通過代碼解壓,解壓時如果有中文名的文件,不能正常解壓(這個在另一篇文章中記載)。走另一條道路:需要下載的文件關聯到一個點菜係統的菜單的全部圖片,文件名就是菜單的圖片名。點菜係統的菜單可以從服務器的數據庫中查詢到。這樣就把菜單全部遍曆一遍,每個菜單的圖片名(如果有的話)和URL目錄拚成文件下載路徑(經理提出的方法),使用循環遍曆下載。
/**
* 準備下載菜譜圖片,檢查SDcard是否可用,設置下載更新地址,下載後保存位置信息。
*/
private void downloadMenuImageCheck() {
String status = Environment.getExternalStorageState();
if (!Environment.MEDIA_MOUNTED.equals(status)) {
ToastUtils.showFailure(getApplicationContext(),
"SDcard cannot use!");
return;
}
RequestFileInfo requestFileInfo = new RequestFileInfo();
requestFileInfo.fileParentUrl = "https://192.168.1.103:8181/menupic";
requestFileInfo.saveFilePath = Environment
.getExternalStorageDirectory().getAbsolutePath()
+ "/waitab/menupic";
showDialog(DialogUtil.DIALOG_DOWNLAOD_IMAGE_PROGRESS);
new DownlaodUpdateTask().execute(requestFileInfo);
}
/**
* 找出所有菜品數據
* @return List<menux>
*/
private List<menux> updateMenux() {
return mdb.findAll();
}
/**
* 找出所有菜品數據
* 下載菜品圖片類
* 遍曆菜品數據List,根據每一個菜品圖片名字拚出下載路徑
* 多文件循環遍曆單線程下載
*
* @author modify by ZX
*
*/
private class DownlaodUpdateTask extends
AsyncTask<requestfileinfo progressvalue="" basiccallresult=""> {
@Override
protected BasicCallResult doInBackground(RequestFileInfo... params) {
Log.d(TAG, "start doInBackground!");
final RequestFileInfo req = params[0];
ProgressValue progressValue = new ProgressValue(0, getString(R.string.msg_fetching_menu));
publishProgress(progressValue);
List<menux> menuxs ;
menuxs = updateMenux();
if (menuxs == null) {
dismissDialog(DialogUtil.DIALOG_DOWNLAOD_IMAGE_PROGRESS);
return new BasicCallResult(
"Can not get menu data! ", false);
}
// 根據文件路徑創建目錄
File basePath = new File(req.saveFilePath);
if (!basePath.exists())
basePath.mkdirs();
int needDownloadImageCount = 0;//記錄需要下載的圖片數
int finishDownloadImageCount = 0;//記錄完成下載的圖片數
long startTime;
long endTime;
int length = 0;
double totalLength = 0;
int count = 0;
class ImageInfo{
public String imageName;
public String imageMenuTypeGroupx;
public HttpURLConnection conn;
}
List<imageinfo> imageInfos = new ArrayList<imageinfo>();
//遍曆菜品,取得需要下載的圖片文件的總數量和能連接上的圖片文件的總大小和信息
for (Menux menux : menuxs) {
try {
String imageName = menux.getPicname();// 菜品圖片名
if (StringUtils.isNotEmpty(imageName)) {
needDownloadImageCount += 1;
URL url = new URL(req.fileParentUrl+ File.separator
+ java.net.URLEncoder.encode(imageName,
"UTF-8")); // 如果菜品名是中文,為了解決亂碼問題,改變編碼方式
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();// throws IOException
Log.i(TAG, "response code:" + conn.getResponseCode());
if (HttpURLConnection.HTTP_OK == conn.getResponseCode()) {
length += conn.getContentLength();
String imageMenuTypeGroupx = menux.getMenutype() + menux.getGroupx();// 菜品分類
ImageInfo imageInfo = new ImageInfo();
imageInfo.imageName = imageName;
imageInfo.imageMenuTypeGroupx = imageMenuTypeGroupx;
imageInfo.conn = conn;
imageInfos.add(imageInfo);
}
}
}catch(IOException e){
e.printStackTrace();
}
}
if(imageInfos.size() == 0){
return new BasicCallResult("No image need download! ", false);
}
totalLength = StringUtils.bytes2M(length);
progressValue = new ProgressValue(0, getString(R.string.msg_start_download_menuimage));
publishProgress(progressValue);
startTime = System.currentTimeMillis();
// 遍曆能夠連接上的圖片信息下載
for (ImageInfo imageInfo : imageInfos) {
try {
/*
String imageName = menux.getPicname();// 菜品圖片名
if (StringUtils.isNotEmpty(imageName)) {
String imageMenuTypeGroupx = menux.getMenutype()
+ menux.getGroupx();// 菜品分類
URL url = new URL(req.fileParentUrl+ File.separator
+ java.net.URLEncoder.encode(imageName,
"UTF-8")); // 如果菜品名是中文,為了解決亂碼問題,改變編碼方式
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();// throws IOException
Log.i(TAG, "response code:" + conn.getResponseCode());
if (HttpURLConnection.HTTP_OK == conn.getResponseCode()) {
*/
String imageMenuTypeGroupx = imageInfo.imageMenuTypeGroupx;
String imageName = imageInfo.imageName;
InputStream is = imageInfo.conn.getInputStream();
/*
* 用這幾種方式打開 is 都可以,用上麵一種方式測試是否連接上,若連接上了,再做下載處理
*
InputStream is = conn.getURL().openStream();
InputStream is = url.openStream();
*/
// 根據菜品分類創建下一級目錄
File path;
if (StringUtils.isNotEmpty(imageMenuTypeGroupx)) {
path = new File(req.saveFilePath
+ File.separator + imageMenuTypeGroupx);
if (!path.exists())
path.mkdir();
} else {
path = new File(req.saveFilePath);
}
File imageFile = new File(path, imageName);
FileOutputStream fos = new FileOutputStream(
imageFile);
//progressValue = new ProgressValue(0, " downloading:");
byte buffer[] = new byte[1024];
Log.d(TAG, "preper buffer!");
finishDownloadImageCount += 1;
do {
int numread = is.read(buffer);
if (numread <= 0) {
// publish end
break;
}
count += numread;
fos.write(buffer, 0, numread);
Log.d(TAG, "start fos.write!");
endTime = System.currentTimeMillis();
double currentLength = StringUtils.bytes2M(count);
double kbPerSecond = count * 1f / (endTime - startTime);//即時下載速度因精確到毫秒級的時間,
//時間單位太大,會出現 endTime - startTime = 0 的情況,使得
// kbPerSecond無限大,改為計算平均下載速度。完整表達式應為
//(count / 1000f) / ((endTime - startTime) / 1000f),
// b/ms = Kb/S (b=byte)
double downloadTotalTime = (endTime - startTime) / 1000f;
progressValue.message = String.format(
"%d/%d\t\t%.2f M/%.2f M\t\t%.2fKb/S\t\t\t%.1f S ", finishDownloadImageCount, needDownloadImageCount,
currentLength, totalLength, kbPerSecond, downloadTotalTime);
progressValue.progress = (int) ((((float) count) / length) * DialogUtil.LONG_PROGRESS_MAX);
publishProgress(progressValue);
} while (true);
fos.flush();
fos.close();
is.close();
//}
} catch (MalformedURLException e) {
e.printStackTrace();
return new BasicCallResult("Wrong url! ", false);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return new BasicCallResult("Error: "
+ e.getLocalizedMessage(), false);
}
}
BasicCallResult callResult = new BasicCallResult(
"download finish!", true);
callResult.data = needDownloadImageCount + "";//int轉String
callResult.data2 = String.valueOf(finishDownloadImageCount);
return callResult;
}
@Override
protected void onPostExecute(BasicCallResult result) {
if (result.ok) {
Log.d(TAG, "download menu image success!");
mProgressDialog.setMessage(getString(R.string.msg_download_image_success));
//ToastUtils.showSuccess(getApplicationContext(), "congratulation! download success!");
if(Integer.parseInt(result.data) > Integer.parseInt(result.data2)){
ToastUtils.showLong(getApplicationContext(),"needDownload:" + result.data + " "
+ "finishDownload:" + result.data2 + " "
+ "you should put all menu images to server");
}
} else {
Log.d(TAG, "download menu image failed!");
ToastUtils.showFailure(getApplicationContext(), "5"
+ result.message);
}
DiSettings.putBoolean(getApplicationContext(),
DiSettings.KEY_DOWNLOAD_MENU_IMAGE, false);
dismissDialog(DialogUtil.DIALOG_DOWNLAOD_IMAGE_PROGRESS);
}
@Override
protected void onProgressUpdate(ProgressValue... values) {
Log.d(TAG,values[0].toString());
mProgressDialog.setProgress(values[0].progress);
mProgressDialog.setMessage(values[0].message);
}
}
</imageinfo></imageinfo></menux></requestfileinfo></menux></menux>
最後更新:2017-04-03 22:15:27