Get AsyncTask status when re-opening application

Viewed 55

Currently I have a AsyncTask that gets called within my RecyclerView.Adapter, in it I'm downloading a file from a url and the progress is being displayed within my ViewHolder here is how my AsyncTask looks:

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

    int positionnumber;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

    }

    @Override
    protected String doInBackground(String... f_url) {
        int count;
        String pathreference = f_url[0] + ",";

        positionnumber = Integer.parseInt(f_url[0]);
        isDownloading.set(positionnumber, true);
        try {
            URL url = new URL(f_url[1]);
            URLConnection conection = url.openConnection();
            conection.connect();

            // this will be useful so that you can show a tipical 0-100%
            // progress bar
            int lenghtOfFile = conection.getContentLength();

            // download the file
            InputStream input = new BufferedInputStream(url.openStream(),
                    8192);
            if (isCancelled()) {
                return null;
            }

            if (a.equals("one")) {
                // Output stream
                OutputStream output = new FileOutputStream(Environment
                        .getExternalStorageDirectory().toString()
                        + "/" + setDownloadedName + ".mp4");


                byte data[] = new byte[1024];

                long total = 0;

                while ((count = input.read(data)) != -1) {
                    total += count;
                    // publishing the progress....
                    // After this onProgressUpdate will be called
                    if (isCancelled()) {
                        input.close();
                        return null;
                    }
                    publishProgress("" + (int) ((total * 100) / lenghtOfFile));

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

                // flushing output
                output.flush();
                pathreference = pathreference + Environment.getExternalStorageDirectory().toString() + "/" + setDownloadedName + ".mp4";
                // closing streams
                output.close();
                input.close();


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

        return pathreference;
    }


    protected void onProgressUpdate(String... progress) {

        prog = progress[0];

        Log.d("Progress", progress[0]);
        bars.get(positionnumber).setProgress_(Float.parseFloat(progress[0]));
        float p = bars.get(positionnumber).getProgress_();
        if (p % 1 == 0)
            notifyItemChanged(positionnumber);

    }

    @Override
    protected void onPostExecute(String file_url) {

        String[] split = file_url.split(",");
        int index1 = Integer.parseInt(split[0]);

        try {

            videoHolderClass.get(index1).setImage(imgres[0]);
            bars.get(index1).setProgress_(0);
            manager.insertVideoPath(index1 + "", split[1]);
            RecyclerVideoAdapter.this.notifyItemChanged(index1);
            isDownloading.set(index1, false);
            Log.d("done", "filesaved");

        } catch (Exception e) {

            Log.e("Error: ", e.getMessage());
            Toast.makeText(c, "Network Error..", Toast.LENGTH_SHORT).show();

            prog = "";
            networkFailed = "yes";
            videoHolderClass.get(index1).setImage(imgres[1]);
            bars.get(index1).setProgress_(0);
            RecyclerVideoAdapter.this.notifyItemChanged(index1);
            isDownloading.set(index1, false);

        }
    }
}

The RecyclerView is within a fragment and the fragment is populated in a Activity - ViewPager.

Now, whenever I close the Activity or go to a new Activity and return, the progress is not shown anymore.

I have seen that people do the following:

if(mtask.getStatus() == AsyncTask.Status.FINISHED){
    // My AsyncTask is done and onPostExecute was called
}

but the problem is that the AsyncTask is in my Adapter, so I can't reference to it in my fragment.


My question:

Can someone please explain to me what the correct way is to see if AsyncTask is running and update the progress when Activity is re-created?

1 Answers

I KNOW THIS IS NOT THE "CORRECT" WAY OF DOING IT, but I have managed to figure out a work-around and it works for what I want to achieve.


I decided to use SharedPreferences to check if the file is being downloaded or not. In my onPreExecute I did the following:

@Override
    protected void onPreExecute() {
        super.onPreExecute();
        SharedPreferences sharePrefss = c.getSharedPreferences("busyDownloading", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharePrefss.edit();
        editor.putString("isItBusy", "yes");
        editor.apply();
    }

Above I store a String called "isItBusy" and I set it to yes.

Then in onPostExecute I change SharedPreferences to:

SharedPreferences sharePrefss = c.getSharedPreferences("busyDownloading", Context.MODE_PRIVATE);
            SharedPreferences.Editor editor = sharePrefss.edit();
            editor.putString("isItBusy", "no");
            editor.apply();

In my Activity I do the following when the user press the back button:

@Override
public void onBackPressed() {
    SharedPreferences sharePrefs = getSharedPreferences("busyDownloading", Context.MODE_PRIVATE);
    String getSharedUser = sharePrefs.getString("isItBusy", "");
    if (getSharedUser.equals("yes")){
        // AsyncTask - onPostExecute was not called = moveTaskToBack
        moveTaskToBack(true);
    }else {
        //AsyncTask - onPostExecute was called and application can be destroyed
        finish();
    }
}

By doing the above I now know if the file is still busy downloading or not and handle the back button accordingly.


The next issue was to handle rotation of the device, because when the device is rotated the Activity is destroyed and created again.

To fix this the first thing I did is to retain the fragment state by adding setRetainInstance(true); to my fragments onCreateView. Then in my manifest I added android:configChanges="orientation|screenSize" to my Activity.

Doing this solved the rotation issue.


The last issue that @vsatkh mentioned was to queue the downloads. The files that I'm downloading is not that big (about 2-5MB at most). So I decided to only enable one download at a time, by also checking the SharedPreferences as shown below:

holder.setItemClickListener(new ItemClickListener() {

        @Override
        public void onItemClick(View v, int pos) {

            SharedPreferences sharePrefs = c.getSharedPreferences("busyDownloading", Context.MODE_PRIVATE);
            String getSharedUser = sharePrefs.getString("isItBusy", "");
            if (getSharedUser.equals("yes")){
                Toast.makeText(c, "You can only download one file at a time...", Toast.LENGTH_SHORT).show();

            }else {
             DownloadFileFromURL p = new DownloadFileFromURL();
             p.execute(pos + "", downloadLink);

            }

        }
    });

Not all the method I used (like checking if files already exist) are included above, only the ones relevant to the question I asked.

Related