3

I'm using android build-in DownloadManager to download files from internet. Problem is once i enqueued a download, it tries to download the file forever!! is there any way to set a timeout for downloads?

Alireza Ahmadi
  • 5,122
  • 7
  • 40
  • 67

2 Answers2

3

@Sofien Rahmouni Virtuel and @flegare solutions are good ideas but I'll try to give a full workable example. I was trying to solve this for more hours, so it can save somewone's 'googling' time. The main idea is to retry downloading process if failed or timeout occurred for small and large files - tested on 6-7MB. First remove download with that id and recall download method. For STATUS_RUNNING I call manageDownloadProcess(urlLink, pathUri, fileName, downloadId); method recursivley to be sure that downloading is finishing with succes.

The only problem is that I got STATUS_PENDING always on first check, even if it must be STATUS_RUNNING, and I implemented a workaround to evitate this case.

import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.util.Log;

/**
 * Created by Android Developer on 29.10.2015. Copyright ©
 */
public class DownloadFile {

    private static Context mContext = App.getUniversalContext();//here just get aplication context - I have a static method in App class
    private static DownloadManager downloadManager = (DownloadManager) App.getUniversalContext().getSystemService(Context.DOWNLOAD_SERVICE);
    private static int RETRIES_MAX_NUMBER = 3; //nr of retries
    private static int alreadyRetried;
    private static boolean isEntered = false; 

    public static void downloadFile(String urlLink, String pathUri, String fileName) {
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(urlLink));
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
        request.setDestinationInExternalPublicDir(pathUri, fileName);
        request.setDescription("System download");
        request.setTitle("ADMINISTRATOR");
        request.setVisibleInDownloadsUi(false);
        request.setNotificationVisibility(2)

        final long downloadId = downloadManager.enqueue(request);
        manageDownloadProcess(urlLink, pathUri, fileName, downloadId);

        App.getUniversalContext().registerReceiver(new BroadcastReceiver() {
            public void onReceive(Context ctxt, Intent intent) {
                if (downloadId == intent.getExtras().getLong(DownloadManager.EXTRA_DOWNLOAD_ID)) {
                    mContext.unregisterReceiver(this);
                    //done use your file
                }
            }
        }, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }

    /*check for timeout / errors and retry logic*/
    private static void manageDownloadProcess(final String urlLink, final String pathUri, final String fileName, final long downloadId) {
        DownloadManager.Query query = new DownloadManager.Query();
        query.setFilterByStatus(DownloadManager.STATUS_PENDING | DownloadManager.STATUS_SUCCESSFUL | DownloadManager.STATUS_PAUSED | DownloadManager.STATUS_RUNNING | DownloadManager.STATUS_FAILED);

        final Cursor cursor = downloadManager.query(query.setFilterById(downloadId));
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (cursor.moveToFirst()) {
                    int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
                    switch (status) {

                        /*I introdused 'isEntered' param to eliminate first response from this method
                          * I don't know why but I get STATUS_PENDING always on first run, so this is an ugly workaround*/
                        case DownloadManager.STATUS_PENDING: {
                         Log.d("status", "STATUS_PENDING - timeout");
                            if (isEntered) {
                                if (alreadyRetried < RETRIES_MAX_NUMBER) {
                                    alreadyRetried++;
                                    downloadManager.remove(downloadId);
                                    downloadFile(urlLink, pathUri, fileName);
                                    manageDownloadProcess(urlLink, pathUri, fileName, downloadId);

                                }
                            } else {
                                isEntered = true;
                                manageDownloadProcess(urlLink, pathUri, fileName, downloadId);
                            }
                            break;
                        }

                        case DownloadManager.STATUS_PAUSED: {
                            Log.d("status", "STATUS_PAUSED - error");
                            if (alreadyRetried < RETRIES_MAX_NUMBER) {
                                alreadyRetried++;
                                downloadManager.remove(downloadId);
                                downloadFile(urlLink, pathUri, fileName);
                            }
                            break;
                        }

                        case DownloadManager.STATUS_RUNNING: {
                            Log.d("status", "STATUS_RUNNING - good");
                            manageDownloadProcess(urlLink, pathUri, fileName, downloadId);
                            break;
                        }

                        case DownloadManager.STATUS_SUCCESSFUL: {
                            Log.d("status", "STATUS_SUCCESSFUL - done");
                            break;
                        }

                        case DownloadManager.STATUS_FAILED: {
                            Log.d("status", "STATUS_FAILED - error");
                            if (alreadyRetried < RETRIES_MAX_NUMBER) {
                                alreadyRetried++;
                                downloadManager.remove(downloadId);
                                downloadFile(urlLink, pathUri, fileName);
                            }
                            break;
                        }
                    }
                }
            }
        }, 5000);//do this after 5 sec
    }

}
Community
  • 1
  • 1
Choletski
  • 7,074
  • 6
  • 43
  • 64
  • For me sometimes the download is in state RUNNING even for a invalid url... I solved by changing the logic for check how many time stay without download any byte – Gilian Sep 21 '16 at 02:30
1

Unfortunately Android dosen't puropose a solution to set timeout in DownloadManager But in fact You can set a TIMEOUT ClockWake when you are in case of state of pending : DownloadManager.STATUS_PENDING

DownloadManager.Query query = null;
    Cursor c = null;
    DownloadManager downloadManager = null;
    downloadManager = (DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE);
    query = new DownloadManager.Query();
     if(query!=null) {
                query.setFilterByStatus(DownloadManager.STATUS_FAILED|DownloadManager.STATUS_PAUSED|DownloadManager.STATUS_SUCCESSFUL|
                        DownloadManager.STATUS_RUNNING|DownloadManager.STATUS_PENDING);
            } else {
                return;
            }
    c = downloadManager.query(query);
    if(c.moveToFirst()) { 
    int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)); 
    switch(status) { 
    case DownloadManager.STATUS_PAUSED: 
    break; 
    case DownloadManager.STATUS_PENDING: 
    //here you can set your TIMEOUT solution
    break; 
    case DownloadManager.STATUS_RUNNING: 
    break; 
    case DownloadManager.STATUS_SUCCESSFUL: 
    break; 
    case DownloadManager.STATUS_FAILED: 
    break; 
    }
Sofien Rahmouni
  • 4,354
  • 1
  • 21
  • 22
  • It seems Download Manager works only for happy path scenarios. There is not timeout case handled and many more issues. So probably it's better to create custom Download file logic with Retrofit and handle all cases. – Kostadin Georgiev Jul 25 '22 at 11:07