您的位置:首页 > 移动开发 > Android开发

android多任务下载的状态更新

2014-04-03 17:25 351 查看
对于下载任务,通常需要实时的更新任务进度

一般而言,最直接的方式是使用AsyncTask对进度进行实时更新

但对于多个任务并且界面切换后,AsyncTask并不能满足要求

此时需要使用service,进行独立的下载操作,而进度的更新可以通过不断的广播来更新需要展示的进度

代码片段

package com.exam;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;

import com.exam.utils.FileUtils;

public class DownloadService extends Service {

private boolean stop;
public static final String ACTION_DOWNLOAD = "com.exam.downloadservice";
private static ThreadPoolExecutor sExecutorService = (ThreadPoolExecutor) Executors
.newFixedThreadPool(3);
private String sAppId;
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
int what = msg.what;
if (stop) {
return;
}
if (what == 0) {
if (msg.obj != null && msg.obj instanceof Intent) {
Intent intent = (Intent) msg.obj;
DownloadService.this.sendBroadcast(intent);
}
} else if (what == 2) {
try {
Intent instIntent = new Intent(Intent.ACTION_VIEW);
instIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
instIntent.setDataAndType(
Uri.fromFile(new File(msg.obj.toString())),
"application/vnd.android.package-archive");
startActivity(instIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
};

private class DownloadTask implements Runnable {
private String mLocalPath = FileUtils.SDCARD_BACKUP_APP;
private String mAppId;
private String mDownloadUrl;
private String mLocalName = "tmp.apk";
private String mFileSize;
/**
* -2等待-1失败,0执行前, 1执行中 ,2成功
*/
// private int flag = -2;

private long mTotalSize;
private long mDownloadedSize;
private long mDownloadedSpeed;
private int mProgress;

public DownloadTask(String appId, String appName, String downloadUrl,
long size) {
this.mAppId = appId;
this.mLocalName = appName + ".apk";
this.mDownloadUrl = downloadUrl;
this.mFileSize = FileUtils.getFormatSize(size);
}

protected void onPreExecute(int flag) {
mTotalSize = 0;
mDownloadedSize = 0;
mDownloadedSpeed = 1;
mProgress = 0;
publishProgress(flag);
}

protected void onPostExecute(int flag) {
publishProgress(flag);
}

private void publishProgress(int flag) {
if (mProgress > 100) {
mProgress = 100;
}
if (mProgress < 0) {
mProgress = 0;
}

StringBuffer bufferState = new StringBuffer();
bufferState.append(FileUtils.getFormatSize(mDownloadedSize))
.append("/").append(mFileSize);

StringBuffer bufferSpeed = new StringBuffer();
bufferSpeed.append(FileUtils.getFormatSize(mDownloadedSpeed))
.append("/s");

Intent intent = new Intent(ACTION_DOWNLOAD);
intent.putExtra("appId", mAppId);
intent.putExtra("state", bufferState.toString());
intent.putExtra("speed", bufferSpeed.toString());
intent.putExtra("progress", this.mProgress);
// -2等待-1失败,0执行前, 1执行中 ,2成功
intent.putExtra("flag", flag);
mHandler.sendMessage(mHandler.obtainMessage(0, intent));
if (flag == 2) {
String path = FileUtils.SDCARD_BACKUP_APP + mLocalName;
mHandler.sendMessage(mHandler.obtainMessage(2, path));
}
}

public void execute() {
int flag = 0;
onPreExecute(flag);
flag = 1;
boolean result = downloadFile(flag);
if (result) {
flag = 2;
} else {
flag = -1;
}
onPostExecute(flag);
}

private boolean downloadFile(int flag) {
InputStream inputStream = null;
RandomAccessFile raf = null;
try {
// 检查文件夹是否存在,如果不存在就创建
File dir = new File(mLocalPath);
if (!dir.exists()) {
dir.mkdirs();
}

File file = new File(mLocalPath, mLocalName);
if (file.exists()) {
// downloadedSize = file.length();
// raf.seek(downloadedSize);
file.delete();
}
raf = new RandomAccessFile(file, "rw");

URL url = new URL(mDownloadUrl);
HttpURLConnection urlConnection = (HttpURLConnection) url
.openConnection();
urlConnection.setRequestMethod("GET");
// urlConnection
// .setRequestProperty("RANGE", "bytes=" + downloadedSize);
urlConnection.setDoOutput(true);
urlConnection.connect();
inputStream = urlConnection.getInputStream();
mTotalSize = urlConnection.getContentLength();
byte[] buffer = new byte[1024];
int bufferLength = 0;

// kb
long beginTime = System.currentTimeMillis();
long endTime = beginTime;
long size = 0;
while ((bufferLength = inputStream.read(buffer)) > 0) {
if (mAppId.equals(sAppId) || stop) {
inputStream.close();
inputStream = null;
sAppId = null;
return false;
}
raf.write(buffer, 0, bufferLength);
mDownloadedSize += bufferLength;

size += bufferLength;
endTime = System.currentTimeMillis();
if (endTime - beginTime >= 1000) {
// kb
mDownloadedSpeed = size;
mProgress = (int) (100 * mDownloadedSize / mTotalSize);
publishProgress(flag);

beginTime = endTime;
size = 0;
}

}
raf.close();
raf = null;
inputStream.close();
inputStream = null;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
try {
if (raf != null) {
raf.close();
raf = null;
}
if (inputStream != null) {
inputStream.close();
inputStream = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}

return true;
}

@Override
public void run() {
execute();
}
}

private void execute(Runnable runnable) {
sExecutorService.execute(runnable);
}

@Override
public void onCreate() {
super.onCreate();
stop = false;

}

@Override
public void onDestroy() {
super.onDestroy();
stop = true;
mHandler.removeMessages(0);
new Thread() {
@Override
public void run() {
FileUtils.deleteFiles(new File(FileUtils.SDCARD_BACKUP_APP));
}
}.start();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("DownloadService", "onStartCommand.intent=" + intent);
if (intent != null) {
String appId = intent.getStringExtra("appId");
String appName = intent.getStringExtra("appName");
String downloadUrl = intent.getStringExtra("downloadUrl");
long fileSize = intent.getLongExtra("fileSize", 0);
boolean stop = intent.getBooleanExtra("stop", false);
if (!TextUtils.isEmpty(appId)) {
if (stop) {
sAppId = appId;
} else {
if (sExecutorService.getActiveCount() == 3) {
// 超出最大线程池数,提示稍后下载
Intent intent2 = new Intent(ACTION_DOWNLOAD);
intent2.putExtra("appId", appId);
intent2.putExtra("state", "");
intent2.putExtra("speed", "");
intent2.putExtra("progress", 0);
// -2等待-1失败,0执行前, 1执行中 ,2成功
intent2.putExtra("flag", -2);
mHandler.sendMessage(mHandler.obtainMessage(0, intent2));
} else {
DownloadTask task = new DownloadTask(appId, appName,
downloadUrl, fileSize);
execute(task);
}
}
}
}
return super.onStartCommand(intent, flags, startId);
}

@Override
public IBinder onBind(Intent intent) {
return null;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: