我正在尝试使用进度条下载listview中的多个文件。我取得的成就是,我可以开始特定下载,使用AsyncTask暂停/恢复它并更新进度条(对于单个文件),这部分效果很好
我的问题是我无法同时下载多个文件,当我将listview留到另一个屏幕时,虽然我的下载是在后台进行但进度没有更新,进度条显示0进度,好像它没有下载但它一直在后台下载。
答案 0 :(得分:4)
最后我发现答案比我想象的要简单得多,这里的内容如下
service
Asynctask
用于下载和hashtable
值(url,Asynctask)adapter
中的进度,我运行了一个迭代hashtable
的线程,并使用BroadcastListener
传递值。broadcast
并取决于ListItem
可见更新进度PS:如果有人需要一些代码,我可以提供上述说明的基本代码
public class DownloadingService extends Service {
public static String PROGRESS_UPDATE_ACTION = DownloadingService.class.getName() + ".progress";
private static final long INTERVAL_BROADCAST = 800;
private long mLastUpdate = 0;
private Hashtable<String, DownloadFile> downloadTable;
private LocalBroadcastManager broadcastManager;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
MessageEntity entityRecieved = (MessageEntity) intent.getSerializableExtra("ENTITY");
queueDownload(entityRecieved);
return super.onStartCommand(intent, flags, startId);
}
private void queueDownload(MessageEntity entityRecieved){
if (downloadTable.containsKey(entityRecieved.getPacketID())) {
DownloadFile downloadFile = downloadTable.get(entityRecieved.getPacketID());
if (downloadFile.isCancelled()) {
downloadFile = new DownloadFile(entityRecieved);
downloadTable.put(entityRecieved.getPacketID(), downloadFile);
startDownloadFileTask(downloadFile);
} else {
downloadFile.cancel(true);
downloadTable.remove(entityRecieved.getPacketID());
}
} else {
DownloadFile downloadFile = new DownloadFile(entityRecieved);
downloadTable.put(entityRecieved.getPacketID(), downloadFile);
startDownloadFileTask(downloadFile);
}
}
@Override
public void onCreate() {
super.onCreate();
downloadTable = new Hashtable<String, DownloadFile>();
broadcastManager = LocalBroadcastManager.getInstance(this);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
void startDownloadFileTask(DownloadFile asyncTask) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
asyncTask.execute();
}
private void publishCurrentProgressOneShot(boolean forced) {
if (forced || System.currentTimeMillis() - mLastUpdate > INTERVAL_BROADCAST) {
mLastUpdate = System.currentTimeMillis();
int[] progresses = new int[downloadTable.size()];
String[] packetIds = new String[downloadTable.size()];
int index = 0;
Enumeration<String> enumKey = downloadTable.keys();
while (enumKey.hasMoreElements()) {
String key = enumKey.nextElement();
int val = downloadTable.get(key).progress;
progresses[index] = val;
packetIds[index++] = key;
}
Intent i = new Intent();
i.setAction(PROGRESS_UPDATE_ACTION);
i.putExtra("packetIds", packetIds);
i.putExtra("progress", progresses);
mBroadcastManager.sendBroadcast(i);
}
class DownloadFile extends AsyncTask<Void, Integer, Void> {
private MessageEntity entity;
private File file;
private int progress;
public DownloadFile(MessageEntity entity) {
this.entity = entity;
}
@Override
protected Void doInBackground(Void... arg0) {
String filename = entity.getMediaURL().substring(entity.getMediaURL().lastIndexOf('/') + 1);
file = new File(FileUtil.getAppStorageDir().getPath(), filename);
downloadFile(entity.getMediaURL(), file);
return null;
}
public String downloadFile(String download_file_path, File file) {
int downloadedSize = 0;
int totalSize = 0;
try {
// download the file here
while ((bufferLength = inputStream.read(buffer)) > 0 && !isCancelled()) {
progress = percentage;
publishCurrentProgressOneShot(true);
}
} catch (final Exception e) {
return null;
}
return file.getPath();
}
}
答案 1 :(得分:1)
关于AsynchTask的一个大问题是当你完成它的活动时,AsynchTask会用你的UI失去它的轨道。之后,当您返回到该活动时,即使下载进度仍在后台运行,progressBar也不会更新。实际上,AsynchTask不属于您发布的新Activity,因此新Activity中的新进度条实例不会更新。 为了解决这个问题,我建议你:
1-在onResume()中运行带有timerTask的线程,该线程使用从AsyncTask运行后台更新的值更新你的进度条。像这样:
private void updateProgressBar(){
Runnable runnable = new updateProgress();
background = new Thread(runnable);
background.start();
}
public class updateProgress implements Runnable {
public void run() {
while(Thread.currentThread()==background)
try {
Thread.sleep(1000);
Message msg = new Message();
progress = getProgressPercentage();
handler.sendMessage(msg);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
}
}
}
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
progress.setProgress(msg.what);
}
};
当您的活动不可见时,您必须销毁该主题:
private void destroyRunningThreads()
{
if(background!=null)
{
background.interrupt();
background=null;
}
}
2-定义全局静态布尔变量。在onPreExecute中设置为true,在onPostExecute中将其设置为false。它显示您是否正在下载,因此您可以检查变量是否等于true,显示上一个进度条对话框。(您可以使用整数值或整数数组执行此类操作 - 以显示更新每个下载进度的百分比)。
3-我个人使用的最后一种方式是在通知栏中显示下载进度,在我的列表视图中,我只是表明它现在正在下载。(使用带有布尔值的第二种方法)。这样,即使您完成了活动,通知栏仍会随着下载进度进行更新。
答案 2 :(得分:0)
当你离开你的活动时,asynctask显示进度条的活动被杀死,因此当你回到新活动时,progressBar不再显示,因为asynctask不知道你的新活动。 一般解决方案,适用于任何情况,例如当您的用户关闭您的应用并再次打开它并想要知道progressBar完全分离您的演示文稿时。这意味着您可以创建sharedPreferences或数据库表,并在下载asynctask时将文件的状态放入其中。例如,每500毫秒更新sharedPreferences或数据库表,从总文件大小下载多少。然后,当用户回到您的新活动时,您会从DB或sharedPreferences中读取以显示progressBar并每次更新它,例如1000毫秒。通过这种方式,即使用户关闭应用程序并再次打开它,您的用户也会知道progressBar。我知道这需要更多的工作,但它肯定会让你的用户感到高兴。
要以固定费率阅读和更新,您可以使用scheduleAtFixedRate