Tutoriel et exemples sur le DownloadManager Android

Nous allons examiner des questions telles que les types de téléchargements que vous pouvez faire avec la classe DownloadManager, comment faire les demandes réelles, comment montrer la progression dans la barre d'état via noification, ouvrir le fichier téléchargé et même supprimer.

Qu'est-ce que le DownloadManager ?

Le DownloadManager est un service système que nous pouvons utiliser pour gérer les téléchargements de longue durée.

Pourquoi télécharger ?

Ne sous-estimez pas la nécessité des téléchargements et leur complexité. L'état de la bande passante à l'époque actuelle implique que nous ne sommes toujours pas en mesure, du moins dans de nombreuses régions du monde, d'obtenir les fichiers dont nous avons besoin à la demande et à tout moment. Les utilisateurs ne laissent pas leur Internet allumé en permanence, car cela coûte cher et épuise la batterie de l'appareil.

Il est donc important de pouvoir télécharger des fichiers et les stocker localement. Mais ce n'est pas une tâche facile à mettre en œuvre correctement. Surtout s'il faut le faire correctement et efficacement. Pourtant, c'est l'une de ces tâches qui peut absolument être partagée entre les applications. La plupart du temps, il n'est pas vraiment nécessaire de réinventer la roue pour effectuer des téléchargements http. Il est logique de disposer d'une classe simple à utiliser, capable d'effectuer cette tâche efficacement et d'informer notre application lorsqu'elle est terminée.

La possibilité de télécharger des données est un moyen puissant d'enrichir nos applications car nous pouvons obtenir des fichiers sur Internet que notre application peut ensuite utiliser. Si l'utilisateur supprime le fichier, nous pouvons le retélécharger à nouveau.

Questions courantes

Voici quelques-unes des questions qui nous permettent de comprendre la classe DownloadManager.

Quels types de téléchargement sont gérés par DownloadManager ?

Normalement, il existe plusieurs protocoles pour les communications entre les appareils. Et bien sûr, le téléchargement d'un fichier est juste une forme de communication entre au moins deux appareils. Un appareil fournit un fichier et un autre le reçoit. Attention, le DownloadManager est utilisé pour gérer uniquement les téléchargements HTTP.

Le DownloadManager est particulièrement utile si vos téléchargements sont longs.

Où les téléchargements ont-ils lieu ?

En ce qui concerne les [fils] (https://camposha.info/android/thread). Eh bien, les téléchargements auront lieu dans le fil de fond.

Pourquoi utiliser le DownloadManager ?

Quels sont ses avantages ? Nous en avons plusieurs. Par exemple

  1. Comme nous l'avons dit, les téléchargements ont lieu en arrière-plan. En fait, en arrière-plan dans une application système. Cela signifie que notre application n'a pas à gérer les téléchargements manuellement dans notre thread principal et que notre interface utilisateur est toujours réactive. Ce fait est très important. Le téléchargement de données est l'une des tâches les plus consommatrices de temps et de ressources des gadgets personnels. Pourtant, c'est l'une des tâches qui rendent les appareils aussi puissants qu'ils le sont. Nous devons donc les effectuer. Mais nous devons les faire dans un thread d'arrière-plan et DownloadManager obéit définitivement à cela.
  2. Deuxièmement, les interactions HTTP sont abstraites pour nous. Nous n'avons pas à nous soucier des différents codes HTTP, des messages et des échecs possibles. En fait, même les tentatives sont effectuées en notre nom. Pourtant, ces tentatives peuvent étonnamment être conservées à travers les changements d'état de la connectivité et les redémarrages du système. La progression peut nous être montrée au fur et à mesure que le téléchargement a lieu, ce qui le rend très convivial.

DownloadManager Quick HowTos and Snippets (en anglais)

1. Comment télécharger des vidéos à l'aide de la classe DownloadManager ?

Nous voulons télécharger des vidéos à l'aide de la classe DownloadManager d'Android. Nous voulons leur donner des noms appropriés et les stocker dans un stockage externe.

    public void downloadvideo(String videoURL)
    {
        if(videoURL.contains(".mp4"))
        {
            File directory = new File(Environment.getExternalStorageDirectory()+File.separator+"My Videos");
            directory.mkdirs();
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(videoURL));
            int Number=pref.getFileName();
            request.allowScanningByMediaScanner();
            request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            File root = new File(Environment.getExternalStorageDirectory() + File.separator+"Facebook Videos");
            Uri path = Uri.withAppendedPath(Uri.fromFile(root), "Video-"+Number+".mp4");
            request.setDestinationUri(path);
            DownloadManager dm = (DownloadManager)getActivity().getSystemService(getActivity().DOWNLOAD_SERVICE);
            if(downloadlist.contains(videoURL))
            {
                Toast.makeText(getActivity().getApplicationContext(),"The Video is Already Downloading",Toast.LENGTH_LONG).show();
            }
            else
            {
                downloadlist.add(videoURL);
                dm.enqueue(request);
                Toast.makeText(getActivity().getApplicationContext(),"Downloading Video-"+Number+".mp4",Toast.LENGTH_LONG).show();
                Number++;
                pref.setFileName(Number);
            }

        }
    }

Tout d'abord, on nous a passé l'url de la vidéo comme paramètre. Let' disons que nous voulons télécharger seulement des fichiers mp4, donc nous fournissons une simple vérification booléenne pour vérifier si elle contenu mp4. Vous pourriez utiliser endsWith() si vous le souhaitez à la place de contains().

Exemples de DownloadManager

Regardons quelques exemples de DownloadManager.

Exemple 1. Télécharger un fichier, Voir tous les téléchargements, Supprimer un téléchargement

Dans cet exemple complet, nous voulons voir comment télécharger un fichier depuis Internet en utilisant la classe downloadManager. Ensuite, nous pouvons ouvrir le fichier téléchargé en cliquant sur la notification dans la barre système ou en interne dans notre application. En outre, nous pouvons supprimer le fichier, afficher tous les téléchargements, etc.

Tutoriel vidéo

Nous avons ici un tutoriel vidéo pour cet exemple.

Démo

Voici la démo de l'application.

Vue d'ensemble de l'application

  1. L'utilisateur clique sur le bouton de téléchargement.
  2. Le téléchargement commence.
  3. Pendant ce temps, la progression est affichée dans la barre d'état sous forme de notification. La notification comprend également le titre et la description du téléchargement.
  4. L'utilisateur est informé par le texte de la barre d'état du système lorsque le téléchargement est terminé.
  5. Lorsque l'utilisateur clique sur la notification, le fichier est ouvert. S'il n'est pas trouvé, un message d'avertissement s'affiche.
  6. Lorsque l'utilisateur clique sur le bouton "Afficher tout", la vue permettant d'afficher tous les téléchargements s'affiche. Vous pouvez avoir d'autres téléchargements en file d'attente à cet endroit, certains ne provenant pas de votre application.
  7. Lorsque l'utilisateur clique sur le bouton "Supprimer", le téléchargement, qu'il soit partiel ou complet, est supprimé.
(a). MainActivity.java

Comme vous pouvez l'imaginer, MainActivity est notre activité de lancement. Elle dérive de AppCompatActivity. C'est là que nous écrivons tout notre code. Mais d'abord, nous commençons par faire plusieurs importations. Ceux-ci incluent :

  1. DownloadManager - La classe responsable de nous permettre d'utiliser le gestionnaire de téléchargement du système.
  2. Intent - Classe responsable de nous permettre d'ouvrir la vue du gestionnaire de téléchargement du système.
  3. Uri - Nous permet d'analyser une chaîne url en un Uri à partir duquel notre fichier peut être téléchargé.
  4. Environment - Nous permet de spécifier le répertoire public où notre fichier téléchargé sera stocké.
  5. Toast - Nous permet d'afficher des messages rapides.

HowTo's

Examinons plusieurs howTos.

**(a). Comment initialiser le DownloadManager ?

En tant que service système, le DownloadManager n'est pas instancié directement. Au lieu de cela, nous allons l'initialiser en utilisant la méthode getSystemService() et caster l'objet résultant dans la classe DownloadManager.

    private void initializeDownloadManager() {
        downloadManager= (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
    }

(b). Comment créer une demande de téléchargement

A l'intérieur de la classe DownloadManager se trouve une classe interne appelée la classe Request. Nous pouvons utiliser cette classe pour définir notre requête HTTP. Nous le faisons commodément via le patteur de construction.

        DownloadManager.Request request=new DownloadManager.Request(Uri.parse("https://raw.githubusercontent.com/Oclemy/SampleJSON/master/spacecrafts/voyager.jpg"));
        request.setTitle("Voyager")
                .setDescription("File is downloading...")
                .setDestinationInExternalFilesDir(this,
                        Environment.DIRECTORY_DOWNLOADS,fileName)
                .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

Vous pouvez clairement voir que nous avons collé le Uri dans notre constructeur Request. Ensuite, nous définissons le titre, la descrription, la destination et la visibilité de la notification.

**(c). Comment mettre un téléchargement en file d'attente ?

Mettre un téléchargement en file d'attente signifie l'ajouter à la file d'attente des téléchargements du gestionnaire de téléchargement. La file d'attente sera ensuite traitée automatiquement par le système. Vous mettez en file d'attente un téléchargement en utilisant la méthode enqueue().

        downLoadId=downloadManager.enqueue(request);

Ceci nous retournera un identifiant de téléchargement.

**(d). Comment supprimer/supprimer un fichier téléchargé ?

Eh bien, vous pouvez supprimer un fichier téléchargé du gestionnaire de téléchargement en utilisant la méthode remove() de la classe DownloadManager. Vous passez l'id du téléchargement.

    private void deleteDownloadedFile(){
        downloadManager.remove(downLoadId);
    }

Voici le code source complet.

package info.camposha.mrdownloadmanager;

import android.app.DownloadManager;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import java.io.FileNotFoundException;

public class MainActivity extends AppCompatActivity {

    private DownloadManager downloadManager;
    private String fileName=null;
    private long downLoadId;

    /**
     * Initialize download manager
     */
    private void initializeDownloadManager() {
        downloadManager= (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        fileName="Voyager";
    }

    /**
     * Set the title and desc of this download, to be displayed in notifications.
     */
    private void downloadFile(){
        DownloadManager.Request request=new DownloadManager.Request(Uri.parse("https://raw.githubusercontent.com/Oclemy/SampleJSON/master/spacecrafts/voyager.jpg"));
        request.setTitle("Voyager")
                .setDescription("File is downloading...")
                .setDestinationInExternalFilesDir(this,
                        Environment.DIRECTORY_DOWNLOADS,fileName)
                .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        //Enqueue the download.The download will start automatically once the download manager is ready
        // to execute it and connectivity is available.
        downLoadId=downloadManager.enqueue(request);
    }

    /**
     * Cancel downloads and remove them from the download manager.
     * If there is a downloaded file, partial or complete, it is deleted.
     */
    private void deleteDownloadedFile(){
        downloadManager.remove(downLoadId);
    }
    private void openOurDownload(){
       //we can open download here
    }

    /**
     * View all downloads in the downloadmanager
     */
    private void viewAllDownloads(){
        Intent intent=new Intent();
        intent.setAction(DownloadManager.ACTION_VIEW_DOWNLOADS);
        startActivity(intent);
    }

    /**
     * Handle button clicks
     * @param view
     */
    public void clickView(View view){
        switch (view.getId()){
            case R.id.downloadBtn:
                downloadFile();
                break;
            case R.id.openDownloadBtn:
                openOurDownload();
                break;
            case R.id.viewDownloadsBtn:
                viewAllDownloads();
                break;
            case R.id.deleteBtn:
                deleteDownloadedFile();
                break;
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initializeDownloadManager();
    }
}
(b). activité_main.xml

Nous avons besoin d'un layout pour notre MainActivity. Voici le code.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout

android_layout_width="match_parent"
android_layout_height="match_parent"
    android_orientation="vertical"
android_background="#009688"
tools_context=".MainActivity">

<TextView
    android_id="@+id/headerTxt"
    android_layout_width="match_parent"
    android_layout_height="wrap_content"
    android_text="DownloadManager Example"
    android_textAlignment="center"
    android_fontFamily="casual"
    android_textStyle="bold"
    android_textAppearance="@style/TextAppearance.AppCompat.Large"
    android_textColor="@color/white" />

<ImageView
    android_layout_width="match_parent"
    android_layout_height="300dp"
    android_layout_centerHorizontal="true"
    android_src="@drawable/logo"
    android_contentDescription="@string/app_name"/>

<LinearLayout
    android_id="@+id/button_zone"
    android_layout_width="match_parent"
    android_layout_height="wrap_content"
    android_orientation="horizontal"
    android_layout_centerInParent="true">

    <Button
        android_id="@+id/downloadBtn"
        style="?android:attr/button"
        android_layout_width="0dp"
        android_layout_height="wrap_content"
        android_layout_weight="1"
        android_onClick="clickView"
        android_text="Download" />
    <Button
        android_id="@+id/viewDownloadsBtn"
        style="?android:attr/button"
        android_layout_width="0dp"
        android_layout_height="wrap_content"
        android_layout_weight="1"
        android_onClick="clickView"
        android_text="View All" />
</LinearLayout>

    <LinearLayout
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_orientation="horizontal"
        android_layout_centerInParent="true">
    <Button
        android_id="@+id/openDownloadBtn"
        style="?android:attr/button"
        android_layout_width="0dp"
        android_layout_height="wrap_content"
        android_layout_weight="1"
        android_onClick="clickView"
        android_text="Open" />

        <Button
            android_id="@+id/deleteBtn"
            style="?android:attr/button"
            android_layout_width="0dp"
            android_layout_height="wrap_content"
            android_layout_weight="1"
            android_onClick="clickView"
            android_text="Delete" />

</LinearLayout>

</LinearLayout>
(c). AndroidManifest.xml

Dans notre AndroidManifest, nous devons ajouter des permissions pour la connectivité internet ainsi que pour l'écriture sur un stockage externe. C'est parce que nous téléchargeons notre image depuis internet et écrivons sur notre stockage externe.

Voici mon fichier AndroidManifest.xml complet :

<?xml version="1.0" encoding="utf-8"?>
<manifest
    package="info.camposha.mrdownloadmanager">

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

    <application
        android_allowBackup="true"
        android_icon="@mipmap/ic_launcher"
        android_label="@string/app_name"
        android_roundIcon="@mipmap/ic_launcher_round"
        android_supportsRtl="true"
        android_theme="@style/AppTheme">
        <activity android_name=".MainActivity">
            <intent-filter>
                <action android_name="android.intent.action.MAIN" />

                <category android_name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
Téléchargement

Voici les ressources de référence :

No. Emplacement Lien
1. GitHub Direct Download
2. GitHub Browse 3.
3. YouTube Video Tutorial
4. YouTube Chaîne TV ProgrammingWizards

Exemple 2 : Exemple de DownloadManager simple Kotlin Android

Un exemple simple de downloadmanager open source Kotlin convenant aux débutants absolus.

Etape 1 : Créer le projet

Commencez par créer un projet AndroidStudio vide.

Étape 2 : Dépendances

Aucune bibliothèque tierce n'est nécessaire pour ce projet.

Étape 3 : Conception de la mise en page

Concevez la mise en page de votre activité principale en ajoutant une vue de texte dans un ConstraintLayout comme indiqué ci-dessous :

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Étape 4 : Écriture du code

Commencez par ajouter des importations :

import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.opengl.Visibility
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

Créez MainActivity en étendant AppCompatActivity :

class MainActivity : AppCompatActivity() {

Définir un identifiant de téléchargement :

    var downloadid: Long = 0

Surcharger le callback onCreate() :

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

Créez un BroadcastReceiver annonyme et à l'intérieur de celui-ci surchargez le onReceive() comme suit :

        val new = object: BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
                if (id == downloadid) Log.d("DOWNLOAD", "DONE")
            }
        }

Créez un Uri de téléchargement :

        val uri = Uri.parse("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf")

Initialiser un DownloadRequest :

        val request = DownloadManager.Request(uri).setDescription("DummyFile").setTitle("Dummy").setAllowedOverMetered(true).setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)

Mettre en file d'attente le téléchargement :

        val location = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
        downloadid = location.enqueue(request)

Enregistrez le BroadcastReceiver :

        registerReceiver(new, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))

Voici le code complet :

MainActivity.kt

import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.opengl.Visibility
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

class MainActivity : AppCompatActivity() {

    var downloadid: Long = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val new = object: BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
                if (id == downloadid) Log.d("DOWNLOAD", "DONE")
            }
        }

        val uri = Uri.parse("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf")

        val request = DownloadManager.Request(uri).setDescription("DummyFile").setTitle("Dummy").setAllowedOverMetered(true).setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)

        val location = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
        downloadid = location.enqueue(request)

        registerReceiver(new, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
    }
}

Étape 5 : Ajouter des permissions

Dans votre AndroidManifest, ajoutez les permissions suivantes :

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

Exécution

Copiez le code ou téléchargez-le dans le lien ci-dessous, construisez et exécutez.

Référence

Voici les liens de référence :

Télécharger Exemple
Suivre code auteur

Exemple 3 : Kotlin Android - Téléchargement dynamique

Dans cet exemple, vous apprenez à télécharger à partir de n'importe quel lien. Le lien est fourni au moment de l'exécution via un EditText.

Etape 1 : Créer le projet

Commencez par créer un projet AndroidStudio vide.

Étape 2 : Dépendances

Aucune dépendance de tierce partie n'est nécessaire pour ce projet.

Étape 3 : Conception de la mise en page

Ajoutez un EditText et un bouton dans le layout de votre activité principale :

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/tilLink"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"

        android:hint="Введите ссылку"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/etLink"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.button.MaterialButton
        android:id="@+id/btnLoad"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="load"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tilLink" />

</androidx.constraintlayout.widget.ConstraintLayout>

Étape 4 : Écrire le code

Commencez par ajouter des imports à votre MainActivity.kt comme suit :

import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.view.Gravity
import android.widget.PopupMenu
import android.widget.Toast
import com.google.android.material.textfield.TextInputEditText

Créez l'activité :

class MainActivity : AppCompatActivity() {

Définissez les champs d'instance :

    private var binding: ActivityMainBinding? = null
    private var dm: DownloadManager? = null

Créez une classe annonyme BroadcastReceiver et implémentez la méthode onReceive() comme suit :

    private val broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            val action = intent?.action
            if (DownloadManager.ACTION_DOWNLOAD_COMPLETE == action) {
                Toast.makeText(context, "Download Completed", Toast.LENGTH_SHORT).show()
            }
        }
    }

Configurez les gestionnaires d'événements :

    private fun setupListeners() {
        binding?.btnLoad?.setOnLongClickListener {
            val popup = PopupMenu(this, it)
            popup.inflate(R.menu.popup)
            popup.show()
            download()
            false
        }
    }

Voici la fonction qui télécharge l'élément :

    private fun download() {
        dm?.enqueue(
                DownloadManager.Request(Uri.parse(LINK_VIDEO))
                        .setAllowedNetworkTypes(
                                DownloadManager.Request.NETWORK_MOBILE or
                                        DownloadManager.Request.NETWORK_WIFI
                        )
                        .setTitle("Download File.mp4")
                        .setDescription("This is very important file")
                        .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
//                        .setDestinationInExternalFilesDir(
//                                applicationContext , Environment.DIRECTORY_DOWNLOADS,   "managerDownload24.mp4"
//                        )
                        .setDestinationInExternalPublicDir(
                                Environment.DIRECTORY_DOWNLOADS,
                                "managerDownload24"
                        )
        )
    }

Désenregistrez le BroadcastReceiver dans la fonction onCreate() :

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(broadcastReceiver)
    }

Voici le code complet :

MainActivity.kt

import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.view.Gravity
import android.widget.PopupMenu
import android.widget.Toast
import com.google.android.material.textfield.TextInputEditText
import ru.trinitydigital.downloadmanager.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private var binding: ActivityMainBinding? = null
    private var dm: DownloadManager? = null

    private val broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            val action = intent?.action
            if (DownloadManager.ACTION_DOWNLOAD_COMPLETE == action) {
                Toast.makeText(context, "Download Completed", Toast.LENGTH_SHORT).show()
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding?.root)
        registerReceiver(broadcastReceiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
        dm = getSystemService(DOWNLOAD_SERVICE) as DownloadManager

        setupListeners()
    }

    private fun setupListeners() {
        binding?.btnLoad?.setOnLongClickListener {
            val popup = PopupMenu(this, it)
            popup.inflate(R.menu.popup)
            popup.show()
            download()
            false
        }
    }

    private fun download() {
        dm?.enqueue(
                DownloadManager.Request(Uri.parse(LINK_VIDEO))
                        .setAllowedNetworkTypes(
                                DownloadManager.Request.NETWORK_MOBILE or
                                        DownloadManager.Request.NETWORK_WIFI
                        )
                        .setTitle("Download File.mp4")
                        .setDescription("This is very important file")
                        .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
//                        .setDestinationInExternalFilesDir(
//                                applicationContext , Environment.DIRECTORY_DOWNLOADS,   "managerDownload24.mp4"
//                        )
                        .setDestinationInExternalPublicDir(
                                Environment.DIRECTORY_DOWNLOADS,
                                "managerDownload24"
                        )
        )
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(broadcastReceiver)
    }

    companion object {
        private const val LINK_VIDEO = "https://images.unsplash.com/photo-1569974507005-6dc61f97fb5c?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MXx8anBnfGVufDB8fDB8&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60"
    }
}

Manifeste Android

Dans le AndroidManifest.xml, ajoutez les permissions suivantes :

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

Exécution

Copiez le code ou téléchargez-le dans le lien ci-dessous, construisez et exécutez.

Référence

Voici les liens de référence :

Numéro Lien
1. Télécharger Exemple
2. Suivre l'auteur du code

Exemple 4 : DownloadManager Kotlin avec permissions d'exécution et coroutines

Voici encore un autre exemple de DownloadManager écrit en Kotlin. Il utilise les coroutines Kotlin. Il implique également la vérification des permissions nécessaires au moment de l'exécution avant le téléchargement.

Étape 1 : Création du projet

Commencez par créer un projet AndroidStudio vide.

Étape 2 : Dépendances

Aucune dépendance de tierce partie n'est utilisée.

Étape 3 : Conception de la mise en page

Concevez une mise en page simple avec un bouton et une vue de texte :

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerVertical="true"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:id="@+id/text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:padding="12dp"
            android:textColor="@color/black"
            android:textSize="25sp" />

        <Button
            android:id="@+id/download_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:padding="12dp"
            android:text="DOWNLOAD PDF"
            android:textColor="@android:color/white" />

    </LinearLayout>

</RelativeLayout>

Étape 4 : Écrire le code

Commencez par ajouter des importations :

import android.Manifest
import android.annotation.TargetApi
import android.app.DownloadManager
import android.content.Context
import android.content.pm.PackageManager
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File

Étendez l'activité AppCompatActivity:``.

class MainActivity : AppCompatActivity() {

Définissez ensuite une URL de téléchargement comme champ d'instance :

    private var imageUrl = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"

Remplacez la fonction onCreate() :

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

Lorsque le bouton de téléchargement est cliqué, avant d'initier le téléchargement, nous vérifions la permission :

        download_btn.setOnClickListener {
            // After API 23 (Marshmallow) and lower Android 10 you need to ask for permission first before save an image
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                askPermissions()
            } else {
                downloadImage(imageUrl)
            }
        }

Si elle est accordée, nous lançons le téléchargement.

Voici la fonction pour initier le téléchargement de l'image :

    private fun downloadImage(url: String) {
        val downloadManager = this.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager

        val downloadUri = Uri.parse(url)

        val request = DownloadManager.Request(downloadUri).apply {
            setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
                .setAllowedOverRoaming(false)
                .setTitle(url.substring(url.lastIndexOf("/") + 1))
                .setDescription("abc")
                .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
                .setDestinationInExternalPublicDir(
                    Environment.DIRECTORY_DOWNLOADS,
                    url.substring(url.lastIndexOf("/") + 1)
                )

        }
        //use when just to download the file with getting status
        //downloadManager.enqueue(request)

        val downloadId = downloadManager.enqueue(request)
        val query = DownloadManager.Query().setFilterById(downloadId)

        lifecycleScope.launchWhenStarted {
            var lastMsg: String = ""
            var downloading = true
            while (downloading) {
                val cursor: Cursor = downloadManager.query(query)
                cursor.moveToFirst()
                if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
                    downloading = false
                }
                val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
                val msg: String? = statusMessage(url, File(Environment.DIRECTORY_DOWNLOADS), status)
                Log.e("DownloadManager", " Status is :$msg")
                if (msg != lastMsg) {
                    withContext(Dispatchers.Main) {
                        // Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
                        text_view.text = msg
                        //Log.e("DownloadManager", "Status is :$msg")
                    }
                    lastMsg = msg ?: ""
                }
                cursor.close()
            }
        }
    }

Voici la fonction qui construit et renvoie le statut de téléchargement comme une chaîne de caractères qui peut être affichée à l'utilisateur :

    private fun statusMessage(url: String, directory: File, status: Int): String? {
        var msg = ""
        msg = when (status) {
            DownloadManager.STATUS_FAILED -> "Download has been failed, please try again"
            DownloadManager.STATUS_PAUSED -> "Paused"
            DownloadManager.STATUS_PENDING -> "Pending"
            DownloadManager.STATUS_RUNNING -> "Downloading..."
            DownloadManager.STATUS_SUCCESSFUL -> "PDF downloaded successfully in $directory" + File.separator + url.substring(
                url.lastIndexOf("/") + 1
            )
            else -> "There's nothing to download"
        }
        return msg
    }

La fonction suivante permettra de demander les autorisations nécessaires avant de procéder au téléchargement :

    @TargetApi(Build.VERSION_CODES.M)
    fun askPermissions() {
        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            // Permission is not granted
            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(
                    this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                )
            ) {
                // Show an explanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission.
                AlertDialog.Builder(this)
                    .setTitle("Permission required")
                    .setMessage("Permission required to save photos from the Web.")
                    .setPositiveButton("Allow") { dialog, id ->
                        ActivityCompat.requestPermissions(
                            this,
                            arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                            MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
                        )
                        finish()
                    }
                    .setNegativeButton("Deny") { dialog, id -> dialog.cancel() }
                    .show()
            } else {
                // No explanation needed, we can request the permission.
                ActivityCompat.requestPermissions(
                    this,
                    arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                    MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
                )
                // MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE is an
                // app-defined int constant. The callback method gets the
                // result of the request.

            }
        } else {
            // Permission has already been granted
            downloadImage(imageUrl)
        }
    }

Traitez ensuite la demande de permission resulytusing le callback suivant :

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
            MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE -> {
                // If request is cancelled, the result arrays are empty.
                if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                    // permission was granted, yay!
                    // Download the Image
                    downloadImage(imageUrl)
                } else {
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.

                }
                return
            }
            // Add other 'when' lines to check for other
            // permissions this app might request.
            else -> {
                // Ignore all other requests.
            }
        }
    }

Voici le code complet :

MainActivity.kt

import android.Manifest
import android.annotation.TargetApi
import android.app.DownloadManager
import android.content.Context
import android.content.pm.PackageManager
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File

class MainActivity : AppCompatActivity() {
    private var imageUrl = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
    //private var imageUrl = "http://10.0.2.2:8087/getFile"

    //private var imageUrl = "https://www.orimi.com/pdf-test.pdf"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        download_btn.setOnClickListener {
            //http://localhost:8087/getFile
            //downloadImage("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf")
            //downloadImage("http://localhost:8087/getFile")
            // After API 23 (Marshmallow) and lower Android 10 you need to ask for permission first before save an image
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                askPermissions()
            } else {
                downloadImage(imageUrl)
            }
        }
    }

    private fun downloadImage(url: String) {
        //val directory = File(Environment.DIRECTORY_PICTURES)

//        if (!directory.exists()) {
//            directory.mkdirs()
//        }

        val downloadManager = this.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager

        val downloadUri = Uri.parse(url)

        val request = DownloadManager.Request(downloadUri).apply {
            setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
                .setAllowedOverRoaming(false)
                .setTitle(url.substring(url.lastIndexOf("/") + 1))
                .setDescription("abc")
                .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
                .setDestinationInExternalPublicDir(
                    Environment.DIRECTORY_DOWNLOADS,
                    url.substring(url.lastIndexOf("/") + 1)
                )

        }
        //use when just to download the file with getting status
        //downloadManager.enqueue(request)

        val downloadId = downloadManager.enqueue(request)
        val query = DownloadManager.Query().setFilterById(downloadId)

        lifecycleScope.launchWhenStarted {
            var lastMsg: String = ""
            var downloading = true
            while (downloading) {
                val cursor: Cursor = downloadManager.query(query)
                cursor.moveToFirst()
                if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
                    downloading = false
                }
                val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
                val msg: String? = statusMessage(url, File(Environment.DIRECTORY_DOWNLOADS), status)
                Log.e("DownloadManager", " Status is :$msg")
                if (msg != lastMsg) {
                    withContext(Dispatchers.Main) {
                        // Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
                        text_view.text = msg
                        //Log.e("DownloadManager", "Status is :$msg")
                    }
                    lastMsg = msg ?: ""
                }
                cursor.close()
            }
        }
    }

    private fun statusMessage(url: String, directory: File, status: Int): String? {
        var msg = ""
        msg = when (status) {
            DownloadManager.STATUS_FAILED -> "Download has been failed, please try again"
            DownloadManager.STATUS_PAUSED -> "Paused"
            DownloadManager.STATUS_PENDING -> "Pending"
            DownloadManager.STATUS_RUNNING -> "Downloading..."
            DownloadManager.STATUS_SUCCESSFUL -> "PDF downloaded successfully in $directory" + File.separator + url.substring(
                url.lastIndexOf("/") + 1
            )
            else -> "There's nothing to download"
        }
        return msg
    }

    @TargetApi(Build.VERSION_CODES.M)
    fun askPermissions() {
        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            // Permission is not granted
            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(
                    this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                )
            ) {
                // Show an explanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission.
                AlertDialog.Builder(this)
                    .setTitle("Permission required")
                    .setMessage("Permission required to save photos from the Web.")
                    .setPositiveButton("Allow") { dialog, id ->
                        ActivityCompat.requestPermissions(
                            this,
                            arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                            MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
                        )
                        finish()
                    }
                    .setNegativeButton("Deny") { dialog, id -> dialog.cancel() }
                    .show()
            } else {
                // No explanation needed, we can request the permission.
                ActivityCompat.requestPermissions(
                    this,
                    arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                    MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
                )
                // MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE is an
                // app-defined int constant. The callback method gets the
                // result of the request.

            }
        } else {
            // Permission has already been granted
            downloadImage(imageUrl)
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
            MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE -> {
                // If request is cancelled, the result arrays are empty.
                if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                    // permission was granted, yay!
                    // Download the Image
                    downloadImage(imageUrl)
                } else {
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.

                }
                return
            }
            // Add other 'when' lines to check for other
            // permissions this app might request.
            else -> {
                // Ignore all other requests.
            }
        }
    }

    companion object {
        private const val MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1
    }
}

Exécution

Copier le code ou le télécharger dans le lien ci-dessous, construire et exécuter.

Référence

Voici les liens de référence :

Télécharger Exemple
Suivre auteur du code

Catégorisé: