Загрузите файл с Android и покажите прогресс в ProgressDialog

Я пытаюсь написать простое приложение, которое обновляется. Для этого мне нужна простая функция, которая может загрузить файл и показать текущий прогресс в ProgressDialog. Я знаю, как это сделать ProgressDialog, но я не уверен, как отобразить текущий прогресс и как загрузить файл в первую очередь.


person Tom Leese    schedule 12.06.2010    source источник
comment
Надеюсь, ссылка ниже может вам помочь ... androidhive.info/2012/04/   -  person Ganesh Katikar    schedule 23.01.2014
comment
Для быстрого исправления обратитесь к этому ответу   -  person Richa    schedule 06.04.2015
comment
stackoverflow.com/a/43069239/3879214 проверьте этот ответ   -  person Anu Martin    schedule 15.12.2017


Ответы (15)


Есть много способов скачать файлы. Ниже я опубликую наиболее распространенные способы; Вам решать, какой метод лучше для вашего приложения.

1. Используйте AsyncTask и покажите прогресс загрузки в диалоговом окне.

Этот метод позволит вам одновременно выполнять некоторые фоновые процессы и обновлять пользовательский интерфейс (в этом случае мы обновим индикатор выполнения).

Импорт:

import android.os.PowerManager;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;

Это пример кода:

// declare the dialog as a member field of your activity
ProgressDialog mProgressDialog;

// instantiate it within the onCreate method
mProgressDialog = new ProgressDialog(YourActivity.this);
mProgressDialog.setMessage("A message");
mProgressDialog.setIndeterminate(true);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(true);

// execute this when the downloader must be fired
final DownloadTask downloadTask = new DownloadTask(YourActivity.this);
downloadTask.execute("the url to the file you want to download");

mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {

    @Override
    public void onCancel(DialogInterface dialog) {
        downloadTask.cancel(true); //cancel the task
    }
});

AsyncTask будет выглядеть так:

// usually, subclasses of AsyncTask are declared inside the activity class.
// that way, you can easily modify the UI thread from here
private class DownloadTask extends AsyncTask<String, Integer, String> {

    private Context context;
    private PowerManager.WakeLock mWakeLock;

    public DownloadTask(Context context) {
        this.context = context;
    }

    @Override
    protected String doInBackground(String... sUrl) {
        InputStream input = null;
        OutputStream output = null;
        HttpURLConnection connection = null;
        try {
            URL url = new URL(sUrl[0]);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();

            // expect HTTP 200 OK, so we don't mistakenly save error report
            // instead of the file
            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                return "Server returned HTTP " + connection.getResponseCode()
                        + " " + connection.getResponseMessage();
            }

            // this will be useful to display download percentage
            // might be -1: server did not report the length
            int fileLength = connection.getContentLength();

            // download the file
            input = connection.getInputStream();
            output = new FileOutputStream("/sdcard/file_name.extension");

            byte data[] = new byte[4096];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                // allow canceling with back button
                if (isCancelled()) {
                    input.close();
                    return null;
                }
                total += count;
                // publishing the progress....
                if (fileLength > 0) // only if total length is known
                    publishProgress((int) (total * 100 / fileLength));
                output.write(data, 0, count);
            }
        } catch (Exception e) {
            return e.toString();
        } finally {
            try {
                if (output != null)
                    output.close();
                if (input != null)
                    input.close();
            } catch (IOException ignored) {
            }

            if (connection != null)
                connection.disconnect();
        }
        return null;
    }

Вышеупомянутый метод (doInBackground) всегда выполняется в фоновом потоке. Вы не должны выполнять здесь никаких задач пользовательского интерфейса. С другой стороны, onProgressUpdate и onPreExecute выполняются в потоке пользовательского интерфейса, поэтому вы можете изменить индикатор выполнения:

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // take CPU lock to prevent CPU from going off if the user 
        // presses the power button during download
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
             getClass().getName());
        mWakeLock.acquire();
        mProgressDialog.show();
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        // if we get here, length is known, now set indeterminate to false
        mProgressDialog.setIndeterminate(false);
        mProgressDialog.setMax(100);
        mProgressDialog.setProgress(progress[0]);
    }

    @Override
    protected void onPostExecute(String result) {
        mWakeLock.release();
        mProgressDialog.dismiss();
        if (result != null)
            Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
        else
            Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();
    }

Для этого вам нужно разрешение WAKE_LOCK.

<uses-permission android:name="android.permission.WAKE_LOCK" />

2. Загрузить из службы

Большой вопрос здесь: как мне обновить мои действия из службы?. В следующем примере мы собираемся использовать два класса, о которых вы можете не знать: ResultReceiver и IntentService. ResultReceiver - это тот, который позволит нам обновлять наш поток из службы; IntentService является подклассом Service, который порождает поток для выполнения фоновой работы оттуда (вы должны знать, что Service выполняется фактически в том же потоке вашего приложения; когда вы расширяете Service, вы должны вручную создавать новые потоки для выполнения операций блокировки ЦП) .

Сервис загрузки может выглядеть так:

public class DownloadService extends IntentService {
    public static final int UPDATE_PROGRESS = 8344;

    public DownloadService() {
        super("DownloadService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {

        String urlToDownload = intent.getStringExtra("url");
        ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");
        try {

            //create url and connect
            URL url = new URL(urlToDownload);
            URLConnection connection = url.openConnection();
            connection.connect();

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

            // download the file
            InputStream input = new BufferedInputStream(connection.getInputStream());

            String path = "/sdcard/BarcodeScanner-debug.apk" ;
            OutputStream output = new FileOutputStream(path);

            byte data[] = new byte[1024];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                total += count;

                // publishing the progress....
                Bundle resultData = new Bundle();
                resultData.putInt("progress" ,(int) (total * 100 / fileLength));
                receiver.send(UPDATE_PROGRESS, resultData);
                output.write(data, 0, count);
            }

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

        } catch (IOException e) {
            e.printStackTrace();
        }

        Bundle resultData = new Bundle();
        resultData.putInt("progress" ,100);

        receiver.send(UPDATE_PROGRESS, resultData);
    }
}

Добавьте сервис в свой манифест:

<service android:name=".DownloadService"/>

И активность будет выглядеть так:

// initialize the progress dialog like in the first example

// this is how you fire the downloader
mProgressDialog.show();
Intent intent = new Intent(this, DownloadService.class);
intent.putExtra("url", "url of the file to download");
intent.putExtra("receiver", new DownloadReceiver(new Handler()));
startService(intent);

Вот какие ResultReceiver вступают в игру:

private class DownloadReceiver extends ResultReceiver{

    public DownloadReceiver(Handler handler) {
        super(handler);
    }

    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {

        super.onReceiveResult(resultCode, resultData);

        if (resultCode == DownloadService.UPDATE_PROGRESS) {

            int progress = resultData.getInt("progress"); //get the progress
            dialog.setProgress(progress);

            if (progress == 100) {
                dialog.dismiss();
            }
        }
    }
}

2.1 Использование библиотеки Groundy

Groundy - это библиотека, которая в основном помогает запускать фрагменты кода в фоновой службе. , и он основан на концепции ResultReceiver, показанной выше. В настоящее время эта библиотека устарела. Вот как будет выглядеть весь код:

Действие, в котором вы показываете диалог ...

public class MainActivity extends Activity {

    private ProgressDialog mProgressDialog;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        findViewById(R.id.btn_download).setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                String url = ((EditText) findViewById(R.id.edit_url)).getText().toString().trim();
                Bundle extras = new Bundler().add(DownloadTask.PARAM_URL, url).build();
                Groundy.create(DownloadExample.this, DownloadTask.class)
                        .receiver(mReceiver)
                        .params(extras)
                        .queue();

                mProgressDialog = new ProgressDialog(MainActivity.this);
                mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                mProgressDialog.setCancelable(false);
                mProgressDialog.show();
            }
        });
    }

    private ResultReceiver mReceiver = new ResultReceiver(new Handler()) {
        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            super.onReceiveResult(resultCode, resultData);
            switch (resultCode) {
                case Groundy.STATUS_PROGRESS:
                    mProgressDialog.setProgress(resultData.getInt(Groundy.KEY_PROGRESS));
                    break;
                case Groundy.STATUS_FINISHED:
                    Toast.makeText(DownloadExample.this, R.string.file_downloaded, Toast.LENGTH_LONG);
                    mProgressDialog.dismiss();
                    break;
                case Groundy.STATUS_ERROR:
                    Toast.makeText(DownloadExample.this, resultData.getString(Groundy.KEY_ERROR), Toast.LENGTH_LONG).show();
                    mProgressDialog.dismiss();
                    break;
            }
        }
    };
}

Реализация GroundyTask, используемая Groundy для загрузки файла и отображения прогресса:

public class DownloadTask extends GroundyTask {    
    public static final String PARAM_URL = "com.groundy.sample.param.url";

    @Override
    protected boolean doInBackground() {
        try {
            String url = getParameters().getString(PARAM_URL);
            File dest = new File(getContext().getFilesDir(), new File(url).getName());
            DownloadUtils.downloadFile(getContext(), url, dest, DownloadUtils.getDownloadListenerForTask(this));
            return true;
        } catch (Exception pokemon) {
            return false;
        }
    }
}

И просто добавьте это в манифест:

<service android:name="com.codeslap.groundy.GroundyService"/>

Я думаю, что нет ничего проще. Просто возьмите последнюю версию jar из Github, и все готово. Имейте в виду, что основная цель Groundy - выполнять вызовы внешнего API REST в фоновой службе и легко публиковать результаты в пользовательском интерфейсе. Если вы делаете что-то подобное в своем приложении, это может быть действительно полезно.

2.2 Используйте https://github.com/koush/ion

3. Используйте класс DownloadManager (только GingerBread и новее)

В GingerBread появилась новая функция DownloadManager, которая позволяет легко загружать файлы и делегировать системе тяжелую работу по обработке потоков, потоков и т. Д.

Во-первых, давайте посмотрим на служебный метод:

/**
 * @param context used to check the device version and DownloadManager information
 * @return true if the download manager is available
 */
public static boolean isDownloadManagerAvailable(Context context) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
        return true;
    }
    return false;
}

Название метода все объясняет. Убедившись, что DownloadManager доступен, вы можете сделать что-то вроде этого:

String url = "url you want to download";
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("Some descrition");
request.setTitle("Some title");
// in order for this if to run, you must use the android 3.2 to compile your app
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    request.allowScanningByMediaScanner();
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "name-of-the-file.ext");

// get download service and enqueue file
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);

Ход загрузки будет отображаться на панели уведомлений.

Последние мысли

Первый и второй методы - лишь верхушка айсберга. Если вы хотите, чтобы ваше приложение было надежным, нужно помнить о многих вещах. Вот краткий список:

  • Вы должны проверить, есть ли у пользователя доступ к Интернету.
  • Убедитесь, что у вас есть необходимые разрешения (INTERNET и WRITE_EXTERNAL_STORAGE); также ACCESS_NETWORK_STATE, если вы хотите проверить наличие интернета.
  • Убедитесь, что каталог, в который вы собираетесь загружать файлы, существует и имеет права на запись.
  • Если загрузка слишком велика, вы можете реализовать способ возобновления загрузки, если предыдущие попытки не удались.
  • Пользователи будут благодарны, если вы позволите им прервать загрузку.

Если вам не нужен подробный контроль над процессом загрузки, рассмотрите возможность использования DownloadManager (3), потому что он уже обрабатывает большинство элементов, перечисленных выше.

Но также учтите, что ваши потребности могут измениться. Например, DownloadManager не кэширует ответы. Он будет слепо загружать один и тот же большой файл несколько раз. Нет простого способа исправить это постфактум. Если вы начинаете с базового HttpURLConnection (1, 2), тогда все, что вам нужно, это добавить HttpResponseCache. Таким образом, начальные усилия по изучению основных стандартных инструментов могут быть хорошей инвестицией.

Этот класс объявлен устаревшим на уровне API 26. ProgressDialog - это модальное диалоговое окно, которое не позволяет пользователю взаимодействовать с приложением. Вместо использования этого класса вы должны использовать индикатор выполнения, например ProgressBar, который можно встроить в пользовательский интерфейс вашего приложения. Кроме того, вы можете использовать уведомление, чтобы информировать пользователя о ходе выполнения задачи. Для получения дополнительных сведений Ссылка

person Community    schedule 12.06.2010
comment
Кристиан, я знаю, что это было здесь какое-то время, но мне было интересно, не возражаете ли вы показать мне, как показать индикатор выполнения. Я использовал приведенный вами пример, и он отлично работает (загрузка файлов), но у меня никогда не появляется индикатор выполнения. Благодаря тонну. Майк - person Michael Little; 14.02.2011
comment
Разве в примере нет путаницы между ProgressDialog и ProgressBar? Когда я пробую, компилятор жалуется. - person marlar; 24.06.2011
comment
У меня проблемы с https URL после conexion.connect();. Во время отладки я подтвердил, что в объекте conecion с именем connected есть флаг, установленный на false. Вы знаете, как это решить? Или какие дополнительные шаги нужно сделать для успешной загрузки https? спасибо! - person Felipe Sabino; 06.12.2011
comment
Я только что обнаружил, что это может быть ошибка кода android ‹= 2.2 . google.com/p/android/issues/detail?id=15503 - person Felipe Sabino; 06.12.2011
comment
Я знаю, что это может быть не важно. Все еще учитывая производительность, использование progressDialog.setMax (lenghtOfFile) и publishProgress (total) не было бы более эффективным? Поскольку в (int) много делений и умножений (всего * 100 / lenghtOfFile). Изменить: поскольку я дважды проверяю, что длинный тип данных здесь нарушает правила, так как индикатор выполнения показывает int, но connection.getContentLength () возвращает int, что делает длинный тип данных бесполезным. Я в замешательстве? Да :). Ищите просветления мудрости, мастера ... - person Gökhan Barış Aker; 02.01.2012
comment
Разве не проблема в том, что если DownloadManager недоступен, вам все равно нужно закодировать собственный код загрузки (даже если ваш minSdkLevel составляет ›= ГБ)? - person Mark; 21.08.2012
comment
DownloadManager является частью ОС, а это означает, что он всегда будет доступен в версии GB + и не может быть удален. - person Cristian; 22.08.2012
comment
@Cristian, можно ли обновить макет progressBar активности с помощью DownloadMangaer ?, если возможно, не могли бы вы мне помочь с фрагментом. Спасибо. - person vinaykumar; 15.09.2012
comment
Да, это возможно, просто прочтите документацию DownloadManager. Вам нужно будет запросить эти данные с помощью поставщика контента. - person Cristian; 17.09.2012
comment
@Cristian Я использую Async Task для моего приложения, отображающего контакты, но сталкиваюсь с ошибками, вижу мой вопрос любая идея, воспроизведите меня, пожалуйста stackoverflow.com/questions/12709799/ - person NagarjunaReddy; 04.10.2012
comment
Вперед! Я никогда не видел более подробного ответа на SO. - person Steven Magana-Zook; 26.10.2012
comment
Если DownloadManager является частью ОС (GB +), то не достаточно ли проверить Build.VERSION.SDK_INT? Он точно включен в устройства Kindle Fire? - person Mark; 16.11.2012
comment
В ответе Кристиана есть проблема. Поскольку код в 1. Используйте AsyncTask и покажите прогресс загрузки в диалоговом окне does connection.connect (); тогда InputStream input = new BufferedInputStream (url.openStream ()); код делает 2 подключения к серверу. Мне удалось изменить это поведение, обновив код следующим образом: InputStream input = new BufferedInputStream (connection.getInputStream ()); - person nLL; 16.11.2012
comment
Спасибо за вашу помощь ... не стесняйтесь редактировать ответ, если хотите. - person Cristian; 16.11.2012
comment
спасибо, действительно полезная информация, кто-нибудь знает библиотеку многопоточной загрузки в Android для более быстрой параллельной загрузки для одного файла? - person LOG_TAG; 24.11.2012
comment
Библиотека Groundy позволяет вам это делать. - person Cristian; 26.11.2012
comment
Я бы хотел, чтобы документация по Android была такой лаконичной. - person Lou Morda; 29.11.2012
comment
Рекомендуется close() потоки (input и output) в finally вместо try, иначе, если какое-либо исключение будет выброшено до close(), у вас будут незакрытые потоки. - person Pang; 26.01.2013
comment
Вы правы ... просто хотел, чтобы пример был как можно более ясным. Большое спасибо. - person Cristian; 26.01.2013
comment
не могли бы вы рассказать, как реализовать то же самое для просмотра изображений? /, при нажатии на кнопку установить растровое изображение в просмотре изображений - person Akhil Jain; 03.02.2013
comment
В этом случае вам лучше взглянуть на библиотеку wasp: github.com/casidiablo/wasp - person Cristian; 04.02.2013
comment
Как это сделать внутри SyncAdapter? - person HGPB; 13.02.2013
comment
Разве нет возможности без использования WRITE_EXTERNAL_STORAGE разрешения? объявление. stackoverflow.com/q/16210894/492624 - person Marek Sebera; 27.04.2013
comment
Как лучше всего сообщать о прогрессе (загруженных байтах) и обновлять индикатор выполнения при использовании подхода DownloadManager? - person Alfie Hanssen; 18.06.2013
comment
@Cristian, можно использовать один из этих методов, чтобы загрузить файл с моего собственного ПК и сохранить его позже на SD-карте, используя URL-адрес веб-сервера, например apache tomcat ..? - person nawara; 19.06.2013
comment
@Alfie Я думаю, вы можете использовать DownloadManager Content Provider: stackoverflow.com/questions/5069919/ - person Cristian; 21.06.2013
comment
Менеджер @Dowanload не будет работать в 2.2, тогда как быть иначе? - person CoronaPintu; 07.10.2013
comment
Почему размер байтового буфера 4096 в примере AsyncTask? Это означает, что буфер может хранить до 4096 байт за раз, верно? - person midnightstar; 27.12.2013
comment
@midnightstar взгляните на это: stackoverflow.com/questions/16067199/ есть другие темы, если вы хотите расширить это. - person Cristian; 28.12.2013
comment
Я использовал ваш подход "Загрузить из службы", но mProgressDialog, созданный в процессе, не обновляется. Вызывается обработчик прогресса с правильными параметрами, но прогресс не меняется. В чем может быть проблема? - person Max The Cat; 09.01.2014
comment
№1 работает для меня вроде как. Я переключил его на Style_SPINNER, чтобы не показывать прогресс, но я не могу найти нигде, чтобы разместить onPreExecute () и другие функции в этом разделе. В нем говорится, что он работает в потоке пользовательского интерфейса, но когда я помещаю его туда, я не получаю ничего, кроме сообщений об ошибках. Это работает, но диалоговое окно «Ход загрузки» никогда не исчезает само по себе, и это проблематично. - person Marcel Marino; 20.02.2014
comment
Давно не видел такого сквозного ответа на stackoverflow. палец вверх за услугу Intent с получателем результата - person amIT; 13.03.2014
comment
Не используйте жесткое кодирование / sdcard/ вместо этого Environment.getExternalStorageDirectory(). - person Nima G; 07.04.2014
comment
Как я могу приостановить / остановить процесс загрузки в сервисном методе Intent ?? проверьте мой вопрос, пожалуйста, stackoverflow.com/questions/24480206/ - person Saeed.re; 30.06.2014
comment
Какой подход мне выбрать, если мне нужно загрузить много файлов одновременно? Боюсь, что накладные расходы на многопоточность будут очень тяжелыми. - person Alston; 25.08.2014
comment
@Cristian Если в списке отображается progressbar и пользователь покидает страницу. В это время индикатор выполнения отключает окно, и информация о ходе выполнения теряется. Любое решение проблемы? БЛАГОДАРНОСТЬ! - person Alston; 30.09.2014
comment
@Cristian Спасибо за отличный код. Я реализую ваш второй подход «Загрузить из службы». Не могли бы вы рассказать мне, как реализовать в этом функцию паузы и возобновления? Поскольку я загружаю большие файлы, соединение с Интернетом может прерваться, или пользователь может захотеть приостановить загрузку и возобновить ее позже. - person Nitesh Kumar; 15.10.2014
comment
Я даже не использую этот код, но +1 за то, что приложил усилия, чтобы дать такой хороший ответ !! - person eoinzy; 13.11.2014
comment
Обратите внимание, что при использовании 3-го варианта в библиотеке Java, отделенной от приложения, вам нужно будет передать объект Context функции, которая будет использовать метод getSystemService. Использование одного только этого оператора будет работать только внутри Activity. - person Fabiano; 26.02.2015
comment
Вы потеряете свой контекст, если действие будет убито. - person Romain; 25.03.2015
comment
Для варианта 3 обратите внимание, что некоторые устройства Samsung Galaxy, такие как S5 и S6, возвращают false для вызова isDownloadManagerAvailable (). Я говорю по собственному опыту, лучший способ узнать, доступен ли DownloadManager, - это просто проверить, что версия Android выше или равна Gingerbread. - person icastell; 09.06.2015
comment
Для метода 1, если вы инициализируете индикатор выполнения во фрагменте, сделайте следующее: - person Deb; 14.08.2015
comment
как я могу отправить имя пользователя и пароль авторизации с подключением в методе 2? - person MSepehr; 22.08.2015
comment
Если вы используете AsyncTask, замените Exception на IOException в блоке catch - person zackygaurav; 22.11.2015
comment
Решение 1 не работает. Сначала он загружает данные, а затем обновляет диалоговое окно прогресса, см. stackoverflow.com/questions/34134013/ - person Salmaan; 08.12.2015
comment
привет, спасибо за гида. Можем ли мы использовать DownloadManager и Update Ui одновременно? - person Mahdi; 30.01.2016
comment
@Cristian работал над вашим решением №2. Работает превосходно! Теперь предположим, что я запустил эту DownloadService для файла A, файла B и файла C. Теперь я хочу отменить загрузку файла A. Я прекращаю процесс. Это убивает его. но после этого он также не загружает файлы B и C. Не могли бы вы предложить мне правильный путь. Это действительно важно и срочно для меня. - person GreenROBO; 24.02.2016
comment
@Cristian the Groundy ссылка мертва, то же самое касается некоторых ссылок, указывающих на GitHub в вашем профиле SO. Просто предупреждаю. - person Marko; 21.03.2016
comment
Когда я загружаю на наш сервер, я получаю отрицательное значение (logcat). Если я возьму любую случайную ссылку на файл, чтобы она работала отлично - person Arpit Patel; 07.04.2016
comment
Byte[] data = new byte[4096] Не могли бы вы объяснить функцию массива данных, более конкретно его размер (4096), назначение (что, если я использую 1024) и лучшие практики? - person Muhammad Babar; 01.08.2016
comment
Для больших файлов подкидывает java.io.IOException: unexpected end of stream какие-нибудь идеи? - person Muhammad Babar; 02.08.2016
comment
Я знаю, что это было здесь уже некоторое время, но при выполнении параметра DownloadManager я получаю IllegalArgumentException: Can only download HTTP/HTTPS URIs при попытке запросить ресурс в локальной сети в URL-адресе, кто-нибудь знает, как заставить его работать таким образом? - person user1676874; 11.01.2017
comment
Класс DownloadManager отлично подходит для меня. Большое спасибо..!! - person appy; 25.04.2017
comment
Отличный учебник. Я хочу узнать, как добиться возобновления, паузы и повторной попытки в AsyncTask для загрузки? - person Pratik Saluja; 08.06.2018
comment
Какой из этих подходов продолжит загрузку файла, даже если приложение будет убито или очищено от последних? - person Tamim Attafi; 10.03.2019
comment
Первая версия ответа, может ли кто-нибудь объяснить мне, почему я получаю исключение NullPointerException на connection.connect () ;? Я не понимаю в чем проблема! Пробовал на эмуляторе Android Studio и на моем телефоне, и он не работает! (KitKat, кстати) - person DADi590; 14.04.2019
comment
Этот метод устарел на уровне API 29. Так что это не работает. - person Akash Chaudhary; 10.12.2019
comment
А вот очень удобный ресурс, если вы хотите иметь определенное кольцо / круг индикатора выполнения: youtube. ru / watch? v = hSfN_aYKkzo - person ConcernedHobbit; 19.12.2019
comment
На этом мой поиск многих ответов закончился. Асинхронная задача, скачать файл, объявить разрешения .. Большое спасибо. - person Sriram Nadiminti; 31.10.2020

Не забудьте добавить разрешения к вашему файлу манифеста, если вы собираетесь загружать что-то из Интернета!

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.helloandroid"
    android:versionCode="1"
    android:versionName="1.0">

        <uses-sdk android:minSdkVersion="10" />

        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
        <uses-permission android:name="android.permission.INTERNET"></uses-permission>
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
        <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>

        <application 
            android:icon="@drawable/icon" 
            android:label="@string/app_name" 
            android:debuggable="true">

        </application>

</manifest>
person Mnightmare    schedule 29.08.2011
comment
Я почти уверен, что вам не нужен READ_PHONE_STATE и определенно не нужен WRITE_EXTERNAL_STORAGE; это опасное разрешение, которого можно избежать с помощью Storage Access Framework. - person Reinstate Monica; 17.05.2018

Да, приведенный выше код будет работать. Но если вы обновляете свой progressbar в onProgressUpdate из Asynctask и нажимаете кнопку «Назад» или завершаете свою деятельность, AsyncTask теряет свой след в вашем пользовательском интерфейсе. И когда вы вернетесь к своей деятельности, даже если загрузка выполняется в фон вы не увидите обновлений на индикаторе выполнения. Итак, на OnResume() попробуйте запустить поток, такой как runOnUIThread, с задачей таймера, которая обновляет ur progressbar значениями, обновляющимися из AsyncTask рабочего фона.

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)
            //while (!Thread.currentThread().isInterrupted()) {
            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);
    }
};

Не забудьте удалить цепочку, если ваша активность не отображается.

private void destroyRunningThreads() {
    if (background != null) {
        background.interrupt();
        background=null;
    }
}
person sheetal    schedule 12.06.2012
comment
Это как раз моя проблема. Можете ли вы сказать мне, как выполнить задачу таймера для обновления индикатора выполнения? Как получить обновление значений из запущенной AsyncTask - person user1417127; 10.07.2012
comment
okk возьмите глобальную или статическую переменную, чтобы обновить свои значения из asynctask ... или вы можете вставить ее в базу данных для безопасности ... чтобы закрытие приложения не помешало ... И когда вы перезапустите действие, где вы хотите обновить ur Пользовательский интерфейс запускает поток пользовательского интерфейса ... см. Пример ниже - person sheetal; 10.07.2012
comment
В пользовательском интерфейсе должна быть свежая ссылка .. Как недавно инициализированный ProgressBar в моем случае - person sheetal; 10.07.2012
comment
@sheetal, а без твоего кода работает нормально! Почему?! Мое устройство - Xperia P с Android 4.0.4. Я определил статическую логическую переменную, для которой onPreExecute устанавливает значение true, а onPostExecute - значение false. Он показывает, что мы загружаем или нет, поэтому мы можем проверить, равна ли переменная истине, показать предыдущий диалог индикатора выполнения. - person Behzad; 21.02.2013
comment
@sheetal ваш код немного непонятен, вы можете мне посоветовать? - person iSun; 06.03.2013
comment
@iSun ничего как такового я столкнулся с той же проблемой .. я решил ее таким образом и поделился ею. очевидно, что это может быть сделано лучше, но мнения здесь открыты, как и мое .. спасибо neways - person sheetal; 12.03.2013
comment
@Behzad да, ты сказал, что это правильно, но я работаю с Froyo и gingerbreads, где Asynctasks были убиты без уведомления о проблемах с памятью, поэтому я должен был возобновить загрузку файлов, если это произойдет ... Так что для безопасности у меня был процент загрузок в базе данных - person sheetal; 12.03.2013

Я бы порекомендовал вам использовать мой проект Netroid, он основан на Volley. Я добавил к нему некоторые функции, такие как обратный вызов нескольких событий, управление загрузкой файлов. Это могло бы помочь.

person VinceStyling    schedule 07.05.2014
comment
Поддерживает ли он загрузку нескольких файлов? Я работаю над проектом, который позволяет пользователю загружать по расписанию. В определенное время (например, в 12:00) сервис загрузит все ссылки, выбранные пользователем ранее. Я имею в виду, что нужная мне служба должна иметь возможность ставить в очередь ссылки для скачивания, а затем загружать их все (одну за другой или параллельно, в зависимости от пользователя). Спасибо - person Hoang Trinh; 26.06.2014
comment
@piavgh да, все, что вы хотели, было удовлетворено, вы можете проверить мой образец apk, он включал демонстрацию управления загрузкой файлов. - person VinceStyling; 26.06.2014
comment
Отличная библиотека! Работает хорошо, хотя у меня возникают проблемы с загрузкой контента с URL-адресов HTTPS, поскольку, хотя можно установить свои собственные SSLSocketFactory, добавление HostnameVerifier невозможно, и мне нужен такой верификатор. Поднял проблему по этому поводу. - person DarkCygnus; 23.05.2018
comment
ссылка для Volley. < / b> - ›Не найдено - person Rumit Patel; 24.12.2018

Я изменил класс AsyncTask для обработки создания progressDialog в том же контексте. Я думаю, что следующий код будет более пригодным для повторного использования. (его можно вызвать из любого действия, просто передайте контекст, целевой файл, диалоговое сообщение)

public static class DownloadTask extends AsyncTask<String, Integer, String> {
    private ProgressDialog mPDialog;
    private Context mContext;
    private PowerManager.WakeLock mWakeLock;
    private File mTargetFile;
    //Constructor parameters :
    // @context (current Activity)
    // @targetFile (File object to write,it will be overwritten if exist)
    // @dialogMessage (message of the ProgresDialog)
    public DownloadTask(Context context,File targetFile,String dialogMessage) {
        this.mContext = context;
        this.mTargetFile = targetFile;
        mPDialog = new ProgressDialog(context);

        mPDialog.setMessage(dialogMessage);
        mPDialog.setIndeterminate(true);
        mPDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mPDialog.setCancelable(true);
        // reference to instance to use inside listener
        final DownloadTask me = this;
        mPDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                me.cancel(true);
            }
        });
        Log.i("DownloadTask","Constructor done");
    }

    @Override
    protected String doInBackground(String... sUrl) {
        InputStream input = null;
        OutputStream output = null;
        HttpURLConnection connection = null;
        try {
            URL url = new URL(sUrl[0]);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();

            // expect HTTP 200 OK, so we don't mistakenly save error report
            // instead of the file
            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                return "Server returned HTTP " + connection.getResponseCode()
                        + " " + connection.getResponseMessage();
            }
            Log.i("DownloadTask","Response " + connection.getResponseCode());

            // this will be useful to display download percentage
            // might be -1: server did not report the length
            int fileLength = connection.getContentLength();

            // download the file
            input = connection.getInputStream();
            output = new FileOutputStream(mTargetFile,false);

            byte data[] = new byte[4096];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                // allow canceling with back button
                if (isCancelled()) {
                    Log.i("DownloadTask","Cancelled");
                    input.close();
                    return null;
                }
                total += count;
                // publishing the progress....
                if (fileLength > 0) // only if total length is known
                    publishProgress((int) (total * 100 / fileLength));
                output.write(data, 0, count);
            }
        } catch (Exception e) {
            return e.toString();
        } finally {
            try {
                if (output != null)
                    output.close();
                if (input != null)
                    input.close();
            } catch (IOException ignored) {
            }

            if (connection != null)
                connection.disconnect();
        }
        return null;
    }
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // take CPU lock to prevent CPU from going off if the user
        // presses the power button during download
        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                getClass().getName());
        mWakeLock.acquire();

        mPDialog.show();

    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        // if we get here, length is known, now set indeterminate to false
        mPDialog.setIndeterminate(false);
        mPDialog.setMax(100);
        mPDialog.setProgress(progress[0]);

    }

    @Override
    protected void onPostExecute(String result) {
        Log.i("DownloadTask", "Work Done! PostExecute");
        mWakeLock.release();
        mPDialog.dismiss();
        if (result != null)
            Toast.makeText(mContext,"Download error: "+result, Toast.LENGTH_LONG).show();
        else
            Toast.makeText(mContext,"File Downloaded", Toast.LENGTH_SHORT).show();
    }
}
person The Syrian    schedule 20.05.2015
comment
Не забудьте добавить разрешение Wake Lock ‹uses-permission android: name = android.permission.WAKE_LOCK /› - person Hitesh Sahu; 26.05.2016
comment
откуда берется метод publishProgress? - person gumuruh; 31.01.2021

Не забудьте заменить "/ sdcard ..." на новый файл ("/ mnt / sdcard / ..."), иначе вы получите FileNotFoundException

person ENSATE    schedule 10.02.2014
comment
В части 2 «Загрузка из службы» диалоговое окно «Ход выполнения» не может отображать приращение выполнения. это прямой возврат 100, поэтому, если 100, он напрямую проверяет setprogress 100 и прогресс, как увеличить прогресс? он отображает только 0 прогресс, но на самом деле загрузка выполняется - person Nirav Mehta; 10.04.2014
comment
он отображает только 0% из 100, только остальные работают правильно - person Nirav Mehta; 10.04.2014
comment
Не делай этого! Есть Environment.getExternalStorageDirectory().getAbsolutePath() для получения пути к sdcard. Также не забудьте проверить, смонтировано ли внешнее хранилище - Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) (Mannaz < / а>) - person naXa; 15.04.2014

Я нашел это сообщение в блоге очень полезным. Его использование loopJ для загрузки файла, он имеет только одну простую функцию, которая будет полезна некоторым новичкам в Android.

person chintan adatiya    schedule 01.08.2014

Когда я начинал изучать разработку для Android, я понял, что ProgressDialog - это правильный путь. Существует setProgress метод ProgressDialog, который можно вызвать для обновления уровня выполнения по мере загрузки файла.

Лучшее, что я видел во многих приложениях, - это то, что они настраивают атрибуты этого диалога прогресса, чтобы он выглядел лучше, чем стандартная версия. Хорошо держать пользователя в руках анимацией лягушки, слона или милых кошек / щенков. Любая анимация в диалоговом окне прогресса привлекает пользователей, и они не хотят, чтобы их заставляли долго ждать.

person Piyush-Ask Any Difference    schedule 19.09.2014
comment
Ссылка не работает - ›Показывать индикатор выполнения при загрузке файл в android - person Rumit Patel; 24.12.2018

Мой личный совет - использовать Диалог выполнения и накапливать перед выполнением или начинать с OnPreExecute(), часто публиковать прогресс, если вы используете горизонтальный стиль индикатора выполнения в диалоговом окне прогресса. Осталось оптимизировать алгоритм doInBackground.

person Raju yourPepe    schedule 02.07.2013

Используйте библиотеку Android Query, это действительно здорово. Вы можете изменить ее, чтобы использовать ProgressDialog, как вы видите в других примерах, этот будет отображать представление прогресса из вашего макета и скрывать его после завершения.

File target = new File(new File(Environment.getExternalStorageDirectory(), "ApplicationName"), "tmp.pdf");
new AQuery(this).progress(R.id.progress_view).download(_competition.qualificationScoreCardsPdf(), target, new AjaxCallback<File>() {
    public void callback(String url, File file, AjaxStatus status) {
        if (file != null) {
            // do something with file  
        } 
    }
});
person Renetik    schedule 06.05.2015
comment
Дело в том, что я перестал его использовать, потому что он не поддерживается, поэтому не думайте, что это хороший ответ. - person Renetik; 28.08.2017

Мы можем использовать сопрограмму и менеджер работы для загрузки файлов в котлине.

Добавить зависимость в build.gradle

    implementation "androidx.work:work-runtime-ktx:2.3.0-beta01"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.1"

WorkManager класс

    import android.content.Context
    import android.os.Environment
    import androidx.work.CoroutineWorker
    import androidx.work.WorkerParameters
    import androidx.work.workDataOf
    import com.sa.chat.utils.Const.BASE_URL_IMAGE
    import com.sa.chat.utils.Constants
    import kotlinx.coroutines.delay
    import java.io.BufferedInputStream
    import java.io.File
    import java.io.FileOutputStream
    import java.net.URL

    class DownloadMediaWorkManager(appContext: Context, workerParams: WorkerParameters)
        : CoroutineWorker(appContext, workerParams) {

        companion object {
            const val WORK_TYPE = "WORK_TYPE"
            const val WORK_IN_PROGRESS = "WORK_IN_PROGRESS"
            const val WORK_PROGRESS_VALUE = "WORK_PROGRESS_VALUE"
        }

        override suspend fun doWork(): Result {

            val imageUrl = inputData.getString(Constants.WORK_DATA_MEDIA_URL)
            val imagePath = downloadMediaFromURL(imageUrl)

            return if (!imagePath.isNullOrEmpty()) {
                Result.success(workDataOf(Constants.WORK_DATA_MEDIA_URL to imagePath))
            } else {
                Result.failure()
            }
        }

        private suspend fun downloadMediaFromURL(imageUrl: String?): String? {

            val file = File(
                    getRootFile().path,
                    "IMG_${System.currentTimeMillis()}.jpeg"
            )

            val url = URL(BASE_URL_IMAGE + imageUrl)
            val connection = url.openConnection()
            connection.connect()

            val lengthOfFile = connection.contentLength
            // download the file
            val input = BufferedInputStream(url.openStream(), 8192)
            // Output stream
            val output = FileOutputStream(file)

            val data = ByteArray(1024)
            var total: Long = 0
            var last = 0

            while (true) {

                val count = input.read(data)
                if (count == -1) break
                total += count.toLong()

                val progress = (total * 100 / lengthOfFile).toInt()

                if (progress % 10 == 0) {
                    if (last != progress) {
                        setProgress(workDataOf(WORK_TYPE to WORK_IN_PROGRESS,
                                WORK_PROGRESS_VALUE to progress))
                    }
                    last = progress
                    delay(50)
                }
                output.write(data, 0, count)
            }

            output.flush()
            output.close()
            input.close()

            return file.path

        }

        private fun getRootFile(): File {

            val rootDir = File(Environment.getExternalStorageDirectory().absolutePath + "/AppName")

            if (!rootDir.exists()) {
                rootDir.mkdir()
            }

            val dir = File("$rootDir/${Constants.IMAGE_FOLDER}/")

            if (!dir.exists()) {
                dir.mkdir()
            }
            return File(dir.absolutePath)
        }
    }

Начните загрузку через диспетчер работ в классе активности

 private fun downloadImage(imagePath: String?, id: String) {

            val data = workDataOf(WORK_DATA_MEDIA_URL to imagePath)
            val downloadImageWorkManager = OneTimeWorkRequestBuilder<DownloadMediaWorkManager>()
                    .setInputData(data)
                    .addTag(id)
                    .build()

            WorkManager.getInstance(this).enqueue(downloadImageWorkManager)

            WorkManager.getInstance(this).getWorkInfoByIdLiveData(downloadImageWorkManager.id)
                    .observe(this, Observer { workInfo ->

                        if (workInfo != null) {
                            when {
                                workInfo.state == WorkInfo.State.SUCCEEDED -> {
                                    progressBar?.visibility = View.GONE
                                    ivDownload?.visibility = View.GONE
                                }
                                workInfo.state == WorkInfo.State.FAILED || workInfo.state == WorkInfo.State.CANCELLED || workInfo.state == WorkInfo.State.BLOCKED -> {
                                    progressBar?.visibility = View.GONE
                                    ivDownload?.visibility = View.VISIBLE
                                }
                                else -> {
                                    if(workInfo.progress.getString(WORK_TYPE) == WORK_IN_PROGRESS){
                                        val progress = workInfo.progress.getInt(WORK_PROGRESS_VALUE, 0)
                                        progressBar?.visibility = View.VISIBLE
                                        progressBar?.progress = progress
                                        ivDownload?.visibility = View.GONE

                                    }
                                }
                            }
                        }
                    })

        }
person Kinjal    schedule 02.05.2020

Разрешения

  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission 
   android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Использование HttpURLConnection

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class DownloadFileUseHttpURLConnection extends Activity {

ProgressBar pb;
Dialog dialog;
int downloadedSize = 0;
int totalSize = 0;
TextView cur_val;
String dwnload_file_path =  
"http://coderzheaven.com/sample_folder/sample_file.png";
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button b = (Button) findViewById(R.id.b1);
    b.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
             showProgress(dwnload_file_path);

                new Thread(new Runnable() {
                    public void run() {
                         downloadFile();
                    }
                  }).start();
        }
    });
}

void downloadFile(){

    try {
        URL url = new URL(dwnload_file_path);
        HttpURLConnection urlConnection = (HttpURLConnection)   
 url.openConnection();

        urlConnection.setRequestMethod("GET");
        urlConnection.setDoOutput(true);

        //connect
        urlConnection.connect();

        //set the path where we want to save the file           
        File SDCardRoot = Environment.getExternalStorageDirectory(); 
        //create a new file, to save the downloaded file 
        File file = new File(SDCardRoot,"downloaded_file.png");

        FileOutputStream fileOutput = new FileOutputStream(file);

        //Stream used for reading the data from the internet
        InputStream inputStream = urlConnection.getInputStream();

        //this is the total size of the file which we are downloading
        totalSize = urlConnection.getContentLength();

        runOnUiThread(new Runnable() {
            public void run() {
                pb.setMax(totalSize);
            }               
        });

        //create a buffer...
        byte[] buffer = new byte[1024];
        int bufferLength = 0;

        while ( (bufferLength = inputStream.read(buffer)) > 0 ) {
            fileOutput.write(buffer, 0, bufferLength);
            downloadedSize += bufferLength;
            // update the progressbar //
            runOnUiThread(new Runnable() {
                public void run() {
                    pb.setProgress(downloadedSize);
                    float per = ((float)downloadedSize/totalSize) *     
                    100;
                    cur_val.setText("Downloaded " + downloadedSize +  

                    "KB / " + totalSize + "KB (" + (int)per + "%)" );
                }
            });
        }
        //close the output stream when complete //
        fileOutput.close();
        runOnUiThread(new Runnable() {
            public void run() {
                // pb.dismiss(); // if you want close it..
            }
        });         

    } catch (final MalformedURLException e) {
        showError("Error : MalformedURLException " + e);        
        e.printStackTrace();
    } catch (final IOException e) {
        showError("Error : IOException " + e);          
        e.printStackTrace();
    }
    catch (final Exception e) {
        showError("Error : Please check your internet connection " +  
e);
    }       
}

void showError(final String err){
    runOnUiThread(new Runnable() {
        public void run() {
            Toast.makeText(DownloadFileDemo1.this, err,  
      Toast.LENGTH_LONG).show();
        }
    });
}

void showProgress(String file_path){
    dialog = new Dialog(DownloadFileDemo1.this);
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setContentView(R.layout.myprogressdialog);
    dialog.setTitle("Download Progress");

    TextView text = (TextView) dialog.findViewById(R.id.tv1);
    text.setText("Downloading file from ... " + file_path);
    cur_val = (TextView) dialog.findViewById(R.id.cur_pg_tv);
    cur_val.setText("Starting download...");
    dialog.show();

     pb = (ProgressBar)dialog.findViewById(R.id.progress_bar);
     pb.setProgress(0);
            pb.setProgressDrawable(
      getResources().getDrawable(R.drawable.green_progress));  
  }
}
person vishnuc156    schedule 03.10.2016

Я добавляю еще один ответ для другого решения, которое использую сейчас, потому что Android Query настолько велик и не обслуживается, чтобы оставаться здоровым. Итак, я перешел на эту https://github.com/amitshekhariitbhu/Fast-Android-Networking.

    AndroidNetworking.download(url,dirPath,fileName).build()
      .setDownloadProgressListener(new DownloadProgressListener() {
        public void onProgress(long bytesDownloaded, long totalBytes) {
            bar.setMax((int) totalBytes);
            bar.setProgress((int) bytesDownloaded);
        }
    }).startDownload(new DownloadListener() {
        public void onDownloadComplete() {
            ...
        }

        public void onError(ANError error) {
            ...
        }
    });
person Renetik    schedule 28.08.2017
comment
@SathishGadde ну, вам следует больше отлаживать его, потому что это не похоже на проблему с библиотекой ... Эта библиотека создана поверх сетевого уровня OkHttp. Так что, если есть проблема с загрузкой, она тоже должна быть у okhttp, и я не верю, что это так ... У вашей проблемы могут быть разные причины, скорее всего, проблема с сетью. - person Renetik; 27.11.2020
comment
спасибо за быстрый ответ. Пока я пытаюсь работать с небольшими видеофайлами, он работает нормально. Проблема возникает только тогда, когда размер файла больше 78 МБ. После 50мб наблюдаю эту проблему. - person Sathish Gadde; 27.11.2020
comment
Ну может будет лучше задать отдельный вопрос. Как я уже сказал, маловероятно, что причиной является FAN, поскольку это всего лишь сетевой слой поверх нормально работающей библиотеки http, но вы можете выяснить это самостоятельно, попробовав то же самое с чистым нормальным http. - person Renetik; 27.11.2020

Вы можете наблюдать за работой диспетчера загрузок с помощью LiveData и сопрограмм, см. Суть ниже

https://gist.github.com/FhdAlotaibi/678eb1f4fa9441874daf74ac

data class DownloadItem(val bytesDownloadedSoFar: Long = -1, val totalSizeBytes: Long = -1, val status: Int)

class DownloadProgressLiveData(private val application: Application, private val requestId: Long) : LiveData<DownloadItem>(), CoroutineScope {

    private val downloadManager by lazy {
        application.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
    }

    private val job = Job()

    override val coroutineContext: CoroutineContext
        get() = Dispatchers.IO + job

    override fun onActive() {
        super.onActive()
        launch {
            while (isActive) {
                val query = DownloadManager.Query().setFilterById(requestId)
                val cursor = downloadManager.query(query)
                if (cursor.moveToFirst()) {
                    val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
                    Timber.d("Status $status")
                    when (status) {
                        DownloadManager.STATUS_SUCCESSFUL,
                        DownloadManager.STATUS_PENDING,
                        DownloadManager.STATUS_FAILED,
                        DownloadManager.STATUS_PAUSED -> postValue(DownloadItem(status = status))
                        else -> {
                            val bytesDownloadedSoFar = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
                            val totalSizeBytes = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
                            postValue(DownloadItem(bytesDownloadedSoFar.toLong(), totalSizeBytes.toLong(), status))
                        }
                    }
                    if (status == DownloadManager.STATUS_SUCCESSFUL || status == DownloadManager.STATUS_FAILED)
                        cancel()
                } else {
                    postValue(DownloadItem(status = DownloadManager.STATUS_FAILED))
                    cancel()
                }
                cursor.close()
                delay(300)
            }
        }
    }

    override fun onInactive() {
        super.onInactive()
        job.cancel()
    }

}
person Fahad Alotaibi    schedule 14.01.2020
comment
Можете ли вы предоставить пример использования этого класса? - person Karim Karimov; 20.04.2020

Важно

AsyncTask устарел в Android 11.

Для получения дополнительной информации, пожалуйста, ознакомьтесь со следующими сообщениями

Вероятно, следует перейти на платформу Concorency Framework, как предлагает Google

person mayank1513    schedule 04.03.2020