1

I'm implementing a simple download manager. The main activity is like this:

enter image description here

For every download button pressed I run a service who have an asynctask for download files and update a progress bar in the notification bar. This is the code of the asynctask:

class DownloadFileFromURL extends AsyncTask<String, Integer, String> {

    NotificationManager manager;
    NotificationCompat.Builder notificationBuilder;
    String title="";
    int counter = 0;
    String url="";
    String videoId="";
    int totalSize=0;

    public DownloadFileFromURL(String title,String videoId){

        this.title = title;
        this.videoId = videoId;
    }

    /**
     * Before starting background thread
     * Show Progress Bar Dialog
     * */



    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        showNotification();
        ItemDownloaded itemDownloaded = new ItemDownloaded(title+".mp3", videoId, String.valueOf(totalSize));
        id = db.addDownloadedItem(itemDownloaded);


    }

    private void showNotification(){

        manager = (NotificationManager) getApplicationContext()
                .getSystemService(android.content.Context.NOTIFICATION_SERVICE);


        /*build the notification*/
        notificationBuilder = new NotificationCompat.Builder(
                getApplicationContext())
        .setWhen(System.currentTimeMillis())
        .setContentText("Download in progress")
        .setContentTitle(title)
        .setAutoCancel(false)
        .setOngoing(true)
        .setSmallIcon(R.drawable.ic_launcher);

        notificationBuilder.setProgress(100, 0, false);
        Notification notification = notificationBuilder.build();

        manager.notify(title.hashCode() , notification);
    }

    /**
     * Downloading file in background thread
     * */
    @Override
    protected String doInBackground(String... f_url) {
        this.url = f_url[0];
        int count;
        try {
            URL url = new URL(f_url[0]);
            URLConnection conection = url.openConnection();
            conection.connect();
            // getting file length
            int lenghtOfFile = conection.getContentLength();
            totalSize = lenghtOfFile;

            db.updateTotalSize((int)id, String.valueOf(totalSize));


            // input stream to read file - with 8k buffer
            InputStream input = new BufferedInputStream(url.openStream(), 8192);

            // Output stream to write file
            OutputStream output = new FileOutputStream(Environment.getExternalStorageDirectory()
                    + "/download/provefile/"+title+".mp3");

            byte data[] = new byte[1024];

            long total = 0;

            while ((count = input.read(data)) != -1) {
                total += count;
                //actualSize = total;
                // publishing the progress....
                // After this onProgressUpdate will be called
                if((counter == 0) || (counter >21)){
                    publishProgress((int)((total*100)/lenghtOfFile));
                    if(counter == 0)
                        counter++;
                    else
                        counter = 0;
                }else
                    counter++;

                // writing data to file
                output.write(data, 0, count);
            }

            // flushing output
            output.flush();

            // closing streams
            output.close();
            input.close();

        } catch (Exception e) {
            Log.e("Error: ", e.getMessage());
            return "ko";
        }

        return "ok";
    }

    /**
     * Updating progress bar
     * */
    protected void onProgressUpdate(Integer... progress) {
        // setting progress percentage
        //progressBar.setProgress(progress[0]);
        //totalLength.setText("/"+humanReadableByteCount(totalSize, true));
        //actualLength.setText(humanReadableByteCount(actualSize, true));

        notificationBuilder.setProgress(100, progress[0], false);

        Notification notification = notificationBuilder.build();
        //new Random(System.currentTimeMillis()).nextInt()
        manager.notify(title.hashCode() , notification);
    }

    /**
     * After completing background task
     * Dismiss the progress dialog
     * **/
    @Override
    protected void onPostExecute(String result) {
        // dismiss the dialog after the file was downloaded

        notificationBuilder.setProgress(0,0,false);


        Notification notification = notificationBuilder.build();
        //new Random(System.currentTimeMillis()).nextInt()
        manager.notify(title.hashCode() , notification);

        if(result.compareTo("ok")==0)
            downloadSuccesfullComplete(title);
        else
            downloadError(title,url);

        stopSelf();

        /*notificationBuilder.setContentText("Download complete")
        .setProgress(0,0,false);


        Notification notification = notificationBuilder.build();
        //new Random(System.currentTimeMillis()).nextInt()
        manager.notify(title.hashCode() , notification);*/
    }

}

And this is the notification bar: enter image description here

Now I want to show , when users press the show button, in another activity inside a ListView all the files in download (so all the running asynctask) and show a progress for every file with the download progress, like this: enter image description here

How I can do?? I try with a database: in progressUpdate of asynctask I update a column of the table with the actual progress and then in ListView adapter I create an asynctask who execute every second a select sql instruction and update the progress of the progress bar. But I think this isn't a good solution. What do you think??

There is a way to save a reference af all the running asynctask and then in an activity get its and get the progressUpdate?? I thinked to use a subclass of android.Application like a singleton and save in it all the reference to the running asynctask.

Hope I explain all right?? Thank you so much

user1437101
  • 117
  • 1
  • 5
  • 13
  • Not sure I understand your problem, but if I do then [see this answer about using an interface](http://stackoverflow.com/questions/18517400/inner-class-can-access-but-not-update-values-asynctask). This uses a callback in `onPostExecute()` but you should be able to use it in `onProgressUpdate()` – codeMagic Dec 28 '13 at 16:36

1 Answers1

2

You can use an interface to send the status to the listview. You can use an algorithm like this:

    • create an interface in the asynctask class, lets say it has an method called update with the argument you want to send.
    • implement it in the listview class.
    • create a constructor in the asynctask class with argument the interface. For example asyncTaskClassConstructor(myInterface reference)
    • Then when you going to create an instance of the asynctask class you give the reference to the constructor like this: new asyncTaskClassConstructor(this) etc..
    • And then in the onProgressUpdate method of asynctask there you should call the interface method we declared update() and pass the argument there.
    • And then in your listview class you use it as you want, for example updating the listview with notifyDataSetChanged()

Edited answer -1

If you want to know the progress of Asynctask you declare an interface with arguments (int progress), and when you want to notify the progress just call publishProgress() method of Asynctask and inside of that method you call the interface method and the classes that implement that interface will be notified.

Edited answer -2

If you want to update the progress of the file, an efective way of doing it (as i said before) is using an interface, and then you implement that interface in the listview class and update the bar there with the value (argument values let's say you put a int value as method ). And everytime you want to publish the progress to others just call the interface in the onPublishProgress() method with the arguments you want to pass.

Example

In your asyncTask class you create an interface let's say asyncTaskEvents with a method progress(int value) and then make an instance variable with the interface:

 private asyncTaskEvents events;

 public interface asyncTaskEvents { 
   public void progress(int value);
 }

Make an instance variable with the interface, and then add an argument to your constructor to put a reference to the class that is waiting for the progress:

public DownloadFileFromURL(String title,String videoId,asyncTaskEvents event){
    this.title = title;
    this.videoId = videoId;
    this.events = event.
}

Then in your onProgressUpdate method from AsyncTask, you can call the interface to pass the current progress to the classes that implement it ( in this case the listview class):

protected void onProgressUpdate(Integer... progress) {
    //Etc...
    events.progress(progress);
}

Then implement it in your listviewclass, And in the method implemented progress(int value) there you update the progress to the progressBar for example:

public void progress(int value){
  //update progress, show message or whatever you want to do here :-)
}

You can change the arguments as you want. :)

Luis Pena
  • 4,132
  • 2
  • 15
  • 23
  • Ok it is so good but I want the listview must have number of items as number of running asynctask. How can I know the number of running asynctasks? – user1437101 Dec 28 '13 at 23:01
  • You can't run the same asynctask instance multiple times, just one time. If you want to download multiple downloads and add more download later, i think the best idea would be to use a service because with a service running you download the files and if later you want to download more files you just call the service running and then download the new files. – Luis Pena Dec 29 '13 at 13:36
  • Yes I can run multiple asynctask, I use executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR). I yet use a service, infact, my asynctask is inside a service. My problem is how I can know the progress of my multiple asynctask in another activity. – user1437101 Dec 29 '13 at 14:03
  • Ok but what I dont understand is: if the activity with the listview is not running and the asynctask progressUpdate notify the progress to it what happen?? – user1437101 Dec 29 '13 at 15:05
  • You can show a Toast dialog, saying that 1 file has been downloaded.And when the user open the downloader manager then refresh the list with notifyDataSetChanges(); – Luis Pena Dec 29 '13 at 15:33
  • I have editet my question because I think I not explain my problem good. Thank you – user1437101 Dec 29 '13 at 16:59
  • Let me know if you want an example of what i'm saying. – Luis Pena Dec 30 '13 at 04:07
  • Yes please give me an example. Thank you – user1437101 Dec 30 '13 at 08:08