Android Multiple download pause resumes list view with progress update

I am trying to upload multiple files to listview using progressbar. What I have achieved, I can start a specific download, pause / resume it with AsyncTask and update the progress bar (for one file), this part works well

My problem is that I can’t upload multiple files at the same time, and when I leave the list on another screen, although my download is in the background, but the progress is not updating, the progress bar shows 0 progress, as if it weren’t loading but downloading it in the background.

+6
source share
3 answers

Finally, I found an answer that was much simpler than I thought, so it looks like this

  • Create a service with Asynctask to load and hashtable values ​​(url, Asynctask)
  • Pass the value (url, Asynctask) when you click on a list item and check if this hash table already contains a value, if yes cancels this Asynctask task, if you do not add it to the hash table and run Asynctask
  • Now, to update the progress in my adapter I started a thread that iterates through a hashtable and passes the value using the BroadcastListener .
  • And in the operation, intercept broadcast and depending on the visible ListItem update ListItem progress

PS: If someone needs some kind of code, I can provide the basic code for the description described above.

 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(); } } 
+3
source

In case of a big problem with AsynchTask, when you finish your activity, AsynchTask loses its track with your user interface. After that, when you return to this activity, the progressBar is not updated, even if the download progress is still running in the background. In fact, AsynchTask does not belong to the new activity that you started, so the new instance of the progress bar in the new Activity will not be updated. To fix this problem, I suggest you:

1- Run the thread with the Task timer in onResume (), which updates the ur progress bar with values ​​updated from the AsyncTask background. Something like that:

 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); } }; 

and when your activity is not visible, you must destroy the thread:

 private void destroyRunningThreads() { if(background!=null) { background.interrupt(); background=null; } } 

2- Define a global static boolean variable. Set true to onPreExecute and set to false onPostExecute. It shows what you are loading or not, so you can check if this variable is true, display the previous dialog of the progress bar. (You can do something like this with an integer or an array of integers to show the update percentage for each download process).

3- The last method that I personally used was to show the download process in the notification panel, and in my list view, just show that it is loading right now or not. (using the 2nd method with boolean values). Thus, even if you finish the work, the notification panel is still updated with the progress of the download.

+1
source

when you leave your activity, an activity in which asynctask shows that the progress bar is dead, and therefore the progressBar dose is no longer displayed when you return to a new activity because the asynchronous dose is not aware of your new activity. A general solution that will work in any case, for example, when a user closes your application and opens it again and wants to know that progressBar completely shares your presentation. this means that you can create sharedPreferences or a database table and place your state in your file while your asynthesis is loading. for example, every 500 milliseconds, the sharedPreferences table or database is updated as much as the total file size is downloaded. then when the user returns to your new action, you read from DB or sharedPreferences to show the progressBar and update it each, for example 1000 milisecond. This way, your user will know the ProgressBar even if he closes the application and reopens it. I know this requires a bit more work, but it certainly makes your users happy.

to read and update at a fixed speed, you can use scheduleAtFixedRate

0
source

Source: https://habr.com/ru/post/978234/


All Articles