2

I have created a small app that downloads a file using the download manager.
All ok so far.
I thought to add a small Toast and show the user the current status of the download.
So I did something like the following:

Thread t = new Thread(new Runnable() {
    @Override
    public void run() {
         int status = -1;
         while ( (status = checkDownloadStatus()) != -1 && status != DownloadManager.STATUS_FAILED && status != DownloadManager.STATUS_SUCCESSFUL) {
                    try {
                        Log.d("MyApp", "Sleeping for 500 while polling for status [ " + status + " ]");
                        TimeUnit.MILLISECONDS.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        Log.e("MyApp", e.getLocalizedMessage());
                    }
                }
                Log.d("MyApp", "Stop sleeping!");
            }
 });
 t.start();

Inside the checkDownloadStatus I show a Toast to the user about the status of the download: e.g. STARTED/PENDING/FINISHED

I see that the download is in progress and I see the Toast during the download and in the logs I see:

Sleeping for 500 while polling for status [ 2 ]  
Sleeping for 500 while polling for status [ 2 ]  
Sleeping for 500 while polling for status [ 2 ]  
Sleeping for 500 while polling for status [ 2 ]  
…..

Then when the download is complete I see in the log:

Stop sleeping!

But the Toast with the last msg is still displayed.

What am I doing wrong? Is there a better way to achieve what I need

UPDATE:

private int checkDownloadStatus() {

        final Cursor c= dm.query(new DownloadManager.Query().setFilterById(downloadId));
        if (c == null) {
            showUserStatus(getActivity().getString(R.string.download_not_found), Toast.LENGTH_LONG);
        }
        else {
            c.moveToFirst();
            final int status = showStatusMessage(c);
            c.close();
            return status;
        }
        return -1;
    }


private int showStatusMessage(Cursor c) {
        String msg="???";
        int downloadStatus = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
        switch (downloadStatus) {
            case DownloadManager.STATUS_FAILED:
                msg= getActivity().getString(R.string.download_failed);
                break;

            case DownloadManager.STATUS_PAUSED:
                msg= getActivity().getString(R.string.download_paused);
                break;

            case DownloadManager.STATUS_PENDING:
                msg= getActivity().getString(R.string.download_pending);
                break;

            case DownloadManager.STATUS_RUNNING:
                msg= getActivity().getString(R.string.download_in_progress);
                break;

            case DownloadManager.STATUS_SUCCESSFUL:
                msg= getActivity().getString(R.string.download_complete);
                break;

            default:
                msg= getActivity().getString(R.string.download_is_nowhere_in_sight);
                break;
        }
        showUserStatus(msg, Toast.LENGTH_LONG);
        return downloadStatus;
    }


private void showUserStatus(final String msg, final int length) {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getActivity(), msg, length).show();
            }
        });
    }
Jim
  • 18,826
  • 34
  • 135
  • 254

3 Answers3

1

Toast are queued. If you call showText with the same text n times, you will see a toast with the same text for n * length time. Keep a reference to the current Toast and call Toast.cancel() before showing the next one.

E.g.

Toast mToast; 

private void showUserStatus(final String msg, final int length) {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (mToast != null) {
                    mToast.cancel();
                }
                mToast = Toast.makeText(getActivity(), msg, length);
                mToast.show();
            }
        });
    }
Blackbelt
  • 156,034
  • 29
  • 297
  • 305
  • This solved it thank you but I am not clear on the behaviour. What do you mean by `Toast are queued.`? – Jim Apr 22 '15 at 10:43
  • they are literally put in a internal queue and showing one after the other. Cancel remove the current one immediately – Blackbelt Apr 22 '15 at 10:59
1

Dont use while loop for this, use Timer instead

        Timer mtimer = new Timer ();
        mtimer.schedule (new TimerTask () {
            @Override
            public void run () {
                if( (status = checkDownloadStatus()) != -1 && status != DownloadManager.STATUS_FAILED && status != DownloadManager.STATUS_SUCCESSFUL){
                    try {
                        Log.d("MyApp", "Sleeping for 500 while polling for status [ " + status + " ]");
                        TimeUnit.MILLISECONDS.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        Log.e("MyApp", e.getLocalizedMessage());
                    }
                }

            }
        }, 0, 1000);

This will be run after every 1 sec

Murtaza Khursheed Hussain
  • 15,176
  • 7
  • 58
  • 83
0

See, You are calling checkDownloadStatus() method in the while loop condition, so it will be called again and again untill condition will not satisfy. that is the reason toast is showing again and again. Toast will show again before hide the last shown, so it looks like showing for long time.(sorry for bad english)

Rahul Sharma
  • 5,949
  • 5
  • 36
  • 46
  • The condition does satisfy once the download is complete that is why I reach `Log.d("MyApp", "Stop sleeping!");` **outside** of the loop – Jim Apr 22 '15 at 09:40