Descargue un archivo con Android y muestre el progreso en un ProgressDialog

Estoy tratando de escribir una aplicación simple que se actualice. Para esto necesito una función simple que pueda descargar un archivo y mostrar el progreso actual en un parche de ProgressDialog. Yo se como hacer el ProgressDialog, pero no estoy seguro de cómo mostrar el progreso actual y cómo descargar el archivo en primer lugar.

preguntado el 12 de junio de 10 a las 07:06

Espero que el siguiente enlace pueda ser de ayuda ... androidhive.info/2012/04/… -

Para una solución rápida referir esta respuesta -

16 Respuestas

Hay muchas formas de descargar archivos. A continuación, publicaré las formas más comunes; Depende de usted decidir qué método es mejor para su aplicación.

1. Utilizar AsyncTask y mostrar el progreso de la descarga en un cuadro de diálogo

Este método le permitirá ejecutar algunos procesos en segundo plano y actualizar la interfaz de usuario al mismo tiempo (en este caso, actualizaremos una barra de progreso).

Importaciones:

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

Este es un código de ejemplo:

// 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
    }
});

La AsyncTask se verá así:

// 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;
    }

El método anterior (doInBackground) se ejecuta siempre en un hilo de fondo. No debe realizar ninguna tarea de la interfaz de usuario allí. Por otro lado, el onProgressUpdate y onPreExecute ejecutar en el hilo de la interfaz de usuario, por lo que allí puede cambiar la barra de progreso:

    @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();
    }

Para que esto se ejecute, necesita el permiso WAKE_LOCK.

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

2. Descarga del servicio

La gran pregunta aquí es: ¿Cómo actualizo mi actividad desde un servicio?. En el siguiente ejemplo, usaremos dos clases que quizás no conozca: ResultReceiver y IntentService. ResultReceiver es el que nos permitirá actualizar nuestro hilo desde un servicio; IntentService es una subclase de Service que genera un hilo para hacer un trabajo en segundo plano desde allí (debe saber que un Service se ejecuta realmente en el mismo hilo de su aplicación; cuando te extiendes Service, debe generar manualmente nuevos subprocesos para ejecutar operaciones de bloqueo de CPU).

El servicio de descarga puede tener este aspecto:

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);
    }
}

Agrega el servicio a tu manifiesto:

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

Y la actividad se verá así:

// 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);

Aquí es donde ResultReceiver viene a jugar:

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 Usar la biblioteca Groundy

terroso es una biblioteca que básicamente le ayuda a ejecutar fragmentos de código en un servicio en segundo plano, y se basa en el ResultReceiver concepto mostrado arriba. Esta biblioteca es en este momento. Así es como el todo el código se vería así:

La actividad en la que está mostrando el diálogo ...

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;
            }
        }
    };
}

A GroundyTask implementación utilizada por terroso para descargar el archivo y mostrar el progreso:

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;
        }
    }
}

Y solo agregue esto al manifiesto:

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

Creo que no podría ser más fácil. Solo toma el último frasco de Github y estás listo para empezar. Manten eso en mente terrosoEl objetivo principal es realizar llamadas a API REST externas en un servicio en segundo plano y publicar los resultados en la interfaz de usuario fácilmente. Si está haciendo algo así en su aplicación, podría ser realmente útil.

2.2 Uso https://github.com/koush/ion

3. Utilizar DownloadManager clase (GingerBread y solo más reciente)

GingerBread trajo una nueva característica, DownloadManager, que le permite descargar archivos fácilmente y delegar el arduo trabajo de manejar hilos, flujos, etc. al sistema.

Primero, veamos un método de utilidad:

/**
 * @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;
}

El nombre de Method lo explica todo. Una vez que este seguro DownloadManager está disponible, puede hacer algo como esto:

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);

El progreso de la descarga se mostrará en la barra de notificaciones.

Reflexiones finales

El primer y segundo método son solo la punta del iceberg. Hay muchas cosas que debe tener en cuenta si desea que su aplicación sea sólida. Aquí hay una breve lista:

  • Debe verificar si el usuario tiene una conexión a Internet disponible
  • Asegúrese de tener los permisos correctos (INTERNET y WRITE_EXTERNAL_STORAGE); además ACCESS_NETWORK_STATE si desea consultar la disponibilidad de Internet.
  • Asegúrese de que el directorio donde va a descargar los archivos exista y tenga permisos de escritura.
  • Si la descarga es demasiado grande, es posible que desee implementar una forma de reanudar la descarga si fallaron los intentos anteriores.
  • Los usuarios agradecerán que les permita interrumpir la descarga.

A menos que necesite un control detallado del proceso de descarga, considere usar DownloadManager (3) porque ya maneja la mayoría de los elementos enumerados anteriormente.

Pero también considere que sus necesidades pueden cambiar. Por ejemplo, DownloadManager no almacena en caché la respuesta. Descargará a ciegas el mismo archivo grande varias veces. No hay una manera fácil de solucionarlo después del hecho. ¿Dónde si empiezas con un básico? HttpURLConnection (1, 2), entonces todo lo que necesita es agregar un HttpResponseCache. Por lo tanto, el esfuerzo inicial de aprender las herramientas básicas y estándar puede ser una buena inversión.

Esta clase quedó obsoleta en el nivel de API 26. ProgressDialog es un diálogo modal que evita que el usuario interactúe con la aplicación. En lugar de usar esta clase, debe usar un indicador de progreso como ProgressBar, que se puede incrustar en la interfaz de usuario de su aplicación. Alternativamente, puede utilizar una notificación para informar al usuario del progreso de la tarea. Para más detalles Enlace

respondido 06 nov., 19:08

DownloadManager es parte del sistema operativo, lo que significa que siempre estará disponible en GB + y no se puede desinstalar. - Cristian

Hay un problema en la respuesta de Cristian. Porque el código en "1. Utilice AsyncTask y muestre el progreso de la descarga en un cuadro de diálogo"does connection.connect (); luego InputStream input = new BufferedInputStream (url.openStream ()); el código hace 2 conexiones al servidor. He logrado cambiar este comportamiento actualizando el código de la siguiente manera InputStream input = new BufferedInputStream (connection .getInputStream ()); - NL

Desearía que la documentación de Android fuera así de concisa. - lou morda

Sugerido a close() los arroyosinput y output) en finally en lugar de try, de lo contrario, si se lanza alguna excepción antes close(), tienes arroyos sin cerrar dando vueltas. - Pang

No codifique /sdcard/ utilizado Environment.getExternalStorageDirectory() en lugar de. - nima g

¡No olvide agregar permisos a su archivo de manifiesto si va a descargar cosas de Internet!

<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>

Respondido 24 Abr '15, 22:04

Estoy bastante seguro de que no necesita READ_PHONE_STATE y definitivamente no necesita WRITE_EXTERNAL_STORAGE; es un permiso peligroso que puede evitarse utilizando Storage Access Framework. - Reincorporar a Monica

Sí, el código anterior funcionará. Pero si está actualizando su progressbar in onProgressUpdate of Asynctask y presionas el botón de retroceso o terminas tu actividad AsyncTask pierde su seguimiento con su interfaz de usuario. Y cuando regrese a su actividad, incluso si la descarga se está ejecutando en segundo plano, no verá ninguna actualización en la barra de progreso. Pronto OnResume() intenta ejecutar un hilo como runOnUIThread con una tarea de temporizador que actualiza tu progressbar con valores que se actualizan desde el AsyncTask funcionamiento de fondo.

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);
    }
};

No olvides Destruir el hilo cuando tu actividad no es visible.

private void destroyRunningThreads() {
    if (background != null) {
        background.interrupt();
        background=null;
    }
}

Respondido el 28 de diciembre de 16 a las 17:12

Este es exactamente mi problema. ¿Puedes decirme cómo hacer una tarea de temporizador para actualizar la barra de progreso? Cómo obtener la actualización de valores desde AsyncTask que se ejecuta detrás - user1417127

okk tome una variable global o estática a dónde actualizar sus valores de asynctask ... o puede insertarla en DataBase para un lado seguro ... para que la aplicación de cierre no obstaculice ... Y cuando reinicie la actividad donde desea actualizar su La interfaz de usuario ejecuta el hilo de la interfaz de usuario ... ver el ejemplo a continuación sheetal

La interfaz de usuario debería tener la referencia nueva ... como la barra de progreso recién iniciada en mi caso - sheetal

@sheetal, ¡pero funciona bien sin tu código! ¡¿Por qué?! Mi dispositivo es Xperia P con Android 4.0.4. He definido una variable booleana estática que onPreExecute la establece en verdadero y onPostExecute la establece en falso. Muestra que estamos descargando o no, por lo que podemos comprobar si la variable es igual a verdadera, mostrar el diálogo de la barra de progreso anterior. - Behzad

@sheetal, tu código es un poco oscuro, ¿puedes darme algún consejo? - sol

Te recomiendo que uses mi proyecto Netroide, Se basa en Volea. Le agregué algunas características, como devolución de llamada de múltiples eventos, administración de descarga de archivos. Esto podría ser de alguna ayuda.

Respondido 30 Oct 17, 11:10

¿Es compatible con la descarga de varios archivos? Estoy trabajando en un proyecto que permite al usuario descargar programado. A una hora específica (por ejemplo, a las 12 a. M.), El servicio descargará todos los enlaces que el usuario seleccionó antes. Me refiero a que el servicio que necesito debe poder poner en cola los enlaces de descarga y luego descargarlos todos (uno por uno o en paralelo, según el usuario). Gracias - Hoang Trin

@piavgh sí, todo lo que quería era satisfacer, puede consultar mi apk de muestra, que incluía una demostración de gestión de descarga de archivos. - VinceEstilo

¡Gran biblioteca! Funciona bien, aunque tengo problemas para descargar contenido de URL HTTPS, aunque uno puede configurar el suyo SSLSocketFactory agregando un HostnameVerifier no es posible y necesito tal verificador. Levantó un , el asunto de con respecto a ese. - Cygnus oscuro

enlace para Voleo. -> Extraviado - Rumit Patel

Yo he modificado AsyncTask clase para manejar la creación de progressDialog en el mismo contexto. Creo que el siguiente código será más reutilizable. (se puede llamar desde cualquier actividad, simplemente pase el contexto, el archivo de destino, el mensaje de diálogo)

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();
    }
}

Respondido el 28 de diciembre de 16 a las 17:12

No olvidó agregar el permiso de activación de bloqueo - hitesh sahu

¿De dónde viene el método publishProgress? - Guru

No olvide reemplazar "/ sdcard ..." por archivo nuevo("/ mnt / sdcard / ...") de lo contrario, obtendrá un Excepción de archivo no encontrado

Respondido 10 Feb 14, 00:02

En la parte 2 Descargar desde el cuadro de diálogo de progreso del servicio no puede mostrar el incremento de progreso. devuelve 100 directamente, así que si 100 comprueba directamente setprogress 100 y progresa, ¿cómo incrementar el progreso? muestra solo 0 progreso pero en realidad descarga en ejecución - Nirav Mehta

muestra solo 0% de 100 solo otros funcionan correctamente - Nirav Mehta

¡No lo hagas! Hay Environment.getExternalStorageDirectory().getAbsolutePath() para obtener una ruta a sdcard. Además, no olvide verificar si el almacenamiento externo está montado: Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) (mannaz) - naXa

Encontré este La publicación de blog es muy útil, está usando loopJ para descargar archivos, solo tiene una función simple, será útil para algunos nuevos tipos de Android.

Respondido 01 ago 14, 15:08

Mientras comenzaba a aprender sobre el desarrollo de Android, había aprendido que ProgressDialog es el camino a seguir. Ahí está el setProgress método de ProgressDialog que se puede invocar para actualizar el nivel de progreso a medida que se descarga el archivo.

Lo mejor que he visto en muchas aplicaciones es que personalizan los atributos de este cuadro de diálogo de progreso para darle una mejor apariencia al cuadro de diálogo de progreso que la versión estándar. Es bueno mantener al usuario involucrado con algunas animaciones como ranas, elefantes o lindos gatos / cachorros. Cualquier animación en el cuadro de diálogo de progreso atrae a los usuarios y no tienen ganas de tener que esperar mucho.

Respondido el 24 de diciembre de 18 a las 11:12

Mi consejo personal es utilizar Diálogo de progreso y acumular antes de la ejecución, o iniciar en OnPreExecute() , publique el progreso con frecuencia si usa el estilo horizontal de la barra de progreso del cuadro de diálogo de progreso. La parte restante es optimizar el algoritmo de doInBackground.

contestado el 30 de mayo de 14 a las 10:05

Use la biblioteca de consultas de Android, muy bueno, puede cambiarla para usar ProgressDialog como puede ver en otros ejemplos, este mostrará la vista de progreso de su diseño y la ocultará después de la finalización.

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  
        } 
    }
});

Respondido el 28 de diciembre de 16 a las 17:12

La cuestión es que dejé de usarlo porque no se ha mantenido, así que no suponga que esta sea una buena respuesta. - Renetik

Podemos usar la corrutina y el administrador de trabajo para descargar archivos en kotlin.

Agrega una dependencia en build.gradle

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

Clase 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)
        }
    }

Iniciar la descarga a través del administrador de trabajo en la clase de actividad.

 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

                                    }
                                }
                            }
                        }
                    })

        }

contestado el 02 de mayo de 20 a las 09:05

Permissions

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

Usar 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));  
  }
}

Respondido 03 Oct 16, 12:10

Estoy agregando otra respuesta para otra solución que estoy usando ahora porque Android Query es tan grande y no se mantiene para mantenerse saludable. Así que me mudé a esto 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) {
            ...
        }
    });

Respondido 28 ago 17, 19:08

Error al descargar archivos más grandes con esta biblioteca. github.com/amitshekhariitbhu/Fast-Android-Networking/issues/541 - sathish gade

@SathishGadde bueno, deberías depurarlo más porque esto no parece un problema de "biblioteca" ... Esta biblioteca está hecha sobre la capa de red OkHttp. Entonces, si hay algún problema de descarga, okhttp también debe tenerlo y no creo que este sea el caso ... Su problema puede tener varias causas, probablemente algún problema de red. - Renetik

gracias por la rápida respuesta. Mientras intento con archivos de video pequeños, funciona bien. Problema surgido solo cuando el tamaño del archivo es mayor, como 78 MB. Después de 50mb am observador este problema. - sathish gade

Bueno, tal vez sea mejor hacer una pregunta separada. Como dije, es muy poco probable que FAN sea una causa, ya que es solo una capa de red de fin en la parte superior de la biblioteca ok http, pero puede averiguarlo usted mismo intentando lo mismo con ok http puro. - Renetik

Puede observar el progreso del administrador de descargas usando LiveData y corrutinas, ver la esencia a continuación

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

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()
    }

}

Respondido el 20 de enero de 20 a las 12:01

¿Puede proporcionar un ejemplo de caso de uso para esta clase? - Karim Karimov

Importante:

AsyncTask está obsoleto en Android 11.

Para obtener más información, consulte las siguientes publicaciones

Probablemente debería pasar al marco de concorency como lo sugiere Google

respondido 04 mar '20, 17:03

    private class DownloadTask extends AsyncTask<String, Integer, String> {

        private PowerManager.WakeLock mWakeLock;
        String onlinePathBundle, onlinePathMusic, offlinePathBundle, offlinePathMusic;

        CircleProgressBar progressBar;
        RelativeLayout rl_progress;
        ImageView btn_download;
        TextView tv_progress;

        public DownloadTask(String onlinePathBundle, String onlinePathMusic, String offlinePathBundle, String offlinePathMusic, CircleProgressBar progressBar, RelativeLayout rl_progress, ImageView btn_download,
                            TextView tv_progress) {
            this.offlinePathBundle = offlinePathBundle;
            this.offlinePathMusic = offlinePathMusic;
            this.progressBar = progressBar;
            this.rl_progress = rl_progress;
            this.btn_download = btn_download;
            this.tv_progress = tv_progress;
            this.onlinePathBundle = onlinePathBundle;
            this.onlinePathMusic = onlinePathMusic;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressBar.setMax(100);
            rl_progress.setVisibility(View.VISIBLE);
            btn_download.setVisibility(View.GONE);

            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
            mWakeLock.acquire();
        }

        @Override
        protected String doInBackground(String... sUrl) {
            String firstResult = downTask(onlinePathBundle, 1, offlinePathBundle);
            String seondResult = downTask(onlinePathMusic, 2, offlinePathMusic);
            if (firstResult != null) {
                Toast.makeText(SplashActivity.this, "Download error: " + firstResult, Toast.LENGTH_LONG).show();
                return firstResult;
            } else {
                return seondResult;
            }

        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            super.onProgressUpdate(progress);
            progressBar.setProgress(progress[0]);
            tv_progress.setText(progress[0] + "%");

        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            rl_progress.setVisibility(View.GONE);
            btn_download.setVisibility(View.VISIBLE);
            if (result != null) {
                Toast.makeText(SplashActivity.this, "Download error: " + result, Toast.LENGTH_LONG).show();
            } else {
                rl_progress.setVisibility(View.GONE);
                btn_download.setVisibility(View.GONE);
            }

        }

        public String downTask(String onlineNewPath, int numberOfTask, String offlineNewPath) {
            InputStream input = null;
            OutputStream output = null;
            HttpURLConnection connection = null;
            try {
                URL url = new URL(onlineNewPath);
                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(offlineNewPath);

                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
                        if (numberOfTask == 1) {
                            publishProgress((int) (total * 50 / fileLength));
                        } else if (numberOfTask == 2) {
                            publishProgress(((int) (total * 50 / fileLength)) + 50);
                        }

                    }
                    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;
        }
    }

Respondido 23 Abr '21, 17:04

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.