web-dev-qa-db-fra.com

Comment télécharger un fichier à l'aide de DownloadManager dans l'API 29 ou Android Q?

Comme je suis nouveau dans Android Development, j'essaie de faire une application simple en utilisant DownloadManager.

Voici le code

public class MainActivity extends AppCompatActivity implements ActivityCompat.OnRequestPermissionsResultCallback{

Button btn;

private long referenceID;
private DownloadManager downloadManager;
private static final int PERMISSION_REQUEST_CODE = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    btn = findViewById(R.id.btn);

    btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {



            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){


                if (checkPermission())
                {

                    /*** If Storage Permission Is Given, Check External storage is available for read and write***/

                    Uri image_uri = Uri.parse("https://unifiedclothes.com/Unifiedclothes/App_Gallery/thumb_8_121432471036-1432471036-SC-505.jpg");

                    referenceID = DownloadImage(image_uri);




                } else {

                    requestPermission();
                }

            }

            else{
                Toast.makeText(MainActivity.this,"Permission Is Granted..",Toast.LENGTH_SHORT).show();

            }
        }
    });

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

private BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {

        String action = intent.getAction();

        if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)){



            DownloadManager.Query ImageDownloadQuery = new DownloadManager.Query();
            //set the query filter to our previously Enqueued download
            ImageDownloadQuery.setFilterById(referenceID);

            //Query the download manager about downloads that have been requested.
            Cursor cursor = downloadManager.query(ImageDownloadQuery);

            if(cursor.moveToFirst()){

                Toast.makeText(MainActivity.this,DownloadStatus(cursor),Toast.LENGTH_SHORT).show();
            }



        }

    }
};

private String DownloadStatus(Cursor cursor){

    //column for download  status
    int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
    int status = cursor.getInt(columnIndex);
    //column for reason code if the download failed or paused
    int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
    int reason = cursor.getInt(columnReason);



    String statusText = "";
    String reasonText = "";

    switch(status){
        case DownloadManager.STATUS_FAILED:
            statusText = "STATUS_FAILED";
            switch(reason){
                case DownloadManager.ERROR_CANNOT_RESUME:
                    reasonText = "ERROR_CANNOT_RESUME";
                    break;
                case DownloadManager.ERROR_DEVICE_NOT_FOUND:
                    reasonText = "ERROR_DEVICE_NOT_FOUND";
                    break;
                case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
                    reasonText = "ERROR_FILE_ALREADY_EXISTS";
                    break;
                case DownloadManager.ERROR_FILE_ERROR:
                    reasonText = "ERROR_FILE_ERROR";
                    break;
                case DownloadManager.ERROR_HTTP_DATA_ERROR:
                    reasonText = "ERROR_HTTP_DATA_ERROR";
                    break;
                case DownloadManager.ERROR_INSUFFICIENT_SPACE:
                    reasonText = "ERROR_INSUFFICIENT_SPACE";
                    break;
                case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
                    reasonText = "ERROR_TOO_MANY_REDIRECTS";
                    break;
                case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
                    reasonText = "ERROR_UNHANDLED_HTTP_CODE";
                    break;
                case DownloadManager.ERROR_UNKNOWN:
                    reasonText = "ERROR_UNKNOWN";
                    break;
            }
            break;
        case DownloadManager.STATUS_PAUSED:
            statusText = "STATUS_PAUSED";
            switch(reason){
                case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
                    reasonText = "PAUSED_QUEUED_FOR_WIFI";
                    break;
                case DownloadManager.PAUSED_UNKNOWN:
                    reasonText = "PAUSED_UNKNOWN";
                    break;
                case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
                    reasonText = "PAUSED_WAITING_FOR_NETWORK";
                    break;
                case DownloadManager.PAUSED_WAITING_TO_RETRY:
                    reasonText = "PAUSED_WAITING_TO_RETRY";
                    break;
            }
            break;
        case DownloadManager.STATUS_PENDING:
            statusText = "STATUS_PENDING";
            break;
        case DownloadManager.STATUS_SUCCESSFUL:
            statusText = "Image Saved Successfully";
            //reasonText = "Filename:\n" + filename;
            Toast.makeText(MainActivity.this, "Download Status:" + "\n" + statusText + "\n" + reasonText, Toast.LENGTH_SHORT).show();
            break;
    }

    return statusText + reasonText;


}


private long DownloadImage(Uri uri){

    long downloadReference;

    downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);

    DownloadManager.Request request = new DownloadManager.Request(uri);
    //Setting title of request
    request.setTitle("Image Download");

    //Setting description of request
    request.setDescription("Image download using DownloadManager.");


    request.setDestinationInExternalPublicDir(getExternalFilesDir(Environment.DIRECTORY_PICTURES) + "/NewFile","sample2.jpg");
    //request.allowScanningByMediaScanner();
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
    downloadReference = downloadManager.enqueue(request);


    return  downloadReference;
}


private boolean checkPermission() {
    int result = ContextCompat.checkSelfPermission(MainActivity.this, Android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (result == PackageManager.PERMISSION_GRANTED) {
        return true;
    } else {
        return false;
    }
}


private void requestPermission() {

    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (requestCode == PERMISSION_REQUEST_CODE) {

        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

            Uri image_uri = Uri.parse("https://www.dccomics.com/sites/default/files/Char_GetToKnow_Batman80_5ca54cb83a27a6.53173051.png");

            referenceID = DownloadImage(image_uri);


        }

        else {

            Toast.makeText(MainActivity.this, "Permission Denied... \n You Should Allow External Storage Permission To Download Images.", Toast.LENGTH_LONG).show();
        }
    }
}

}

Cela fonctionne bien lorsque je l'exécute sur n'importe quel appareil inférieur à l'API 29 (mon appareil de test était le Nexus 5X, l'émulateur ApI 28). Mais lorsque je l'exécute sur le Nexus 5X, l'API 29, l'application se bloque. Voici les journaux:

2019-09-24 20:51:46.354 11322-11344/? E/DatabaseUtils: Writing exception to parcel
Java.lang.IllegalStateException: Not one of standard directories: /storage/emulated/0/Android/data/com.blz.prisoner.downloadmanager/files/Pictures/NewFile
    at com.Android.providers.downloads.DownloadProvider.call(DownloadProvider.Java:651)
    at Android.content.ContentProvider.call(ContentProvider.Java:2152)
    at Android.content.ContentProvider$Transport.call(ContentProvider.Java:477)
    at Android.content.ContentProviderNative.onTransact(ContentProviderNative.Java:277)
    at Android.os.Binder.execTransactInternal(Binder.Java:1021)
    at Android.os.Binder.execTransact(Binder.Java:994)

2019-09-24 20: 51: 46.355 15023-15023/com.blz.prisoner.downloadmanager D/AndroidRuntime: arrêt de la machine virtuelle

--------- beginning of crash
2019-09-24 20:51:46.360 15023-15023/com.blz.prisoner.downloadmanager E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.blz.prisoner.downloadmanager, PID: 15023
    Java.lang.IllegalStateException: Not one of standard directories: /storage/emulated/0/Android/data/com.blz.prisoner.downloadmanager/files/Pictures/NewFile
        at Android.os.Parcel.createException(Parcel.Java:2079)
        at Android.os.Parcel.readException(Parcel.Java:2039)
        at Android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.Java:188)
        at Android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.Java:140)
        at Android.content.ContentProviderProxy.call(ContentProviderNative.Java:658)
        at Android.content.ContentProviderClient.call(ContentProviderClient.Java:558)
        at Android.content.ContentProviderClient.call(ContentProviderClient.Java:546)
        at Android.app.DownloadManager$Request.setDestinationInExternalPublicDir(DownloadManager.Java:567)
        at com.blz.prisoner.downloadmanager.MainActivity.DownloadImage(MainActivity.Java:206)
        at com.blz.prisoner.downloadmanager.MainActivity.access$200(MainActivity.Java:29)
        at com.blz.prisoner.downloadmanager.MainActivity$1.onClick(MainActivity.Java:60)
        at Android.view.View.performClick(View.Java:7140)
        at Android.view.View.performClickInternal(View.Java:7117)
        at Android.view.View.access$3500(View.Java:801)
        at Android.view.View$PerformClick.run(View.Java:27351)
        at Android.os.Handler.handleCallback(Handler.Java:883)
        at Android.os.Handler.dispatchMessage(Handler.Java:100)
        at Android.os.Looper.loop(Looper.Java:214)
        at Android.app.ActivityThread.main(ActivityThread.Java:7356)
        at Java.lang.reflect.Method.invoke(Native Method)
        at com.Android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.Java:492)
        at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:930)

Je pense que le problème est en ligne "request.setDestinationInExternalPublicDir (getExternalFilesDir (Environment.DIRECTORY_PICTURES) +" /NewFile","sample2.jpg"); "in DownloadImage (Uri uri)) fonction. Comment résoudre le problème??

Un autre problème est que lorsque j'exécute l'application sur l'appareil en dessous de l'API 29, elle fonctionne bien, mais lorsque je clique sur la notification après avoir terminé le téléchargement, elle n'ouvre pas l'image sur la galerie/sur le dossier où elle a été enregistrée.

7
Bishal Imtiaz

changer compileSdkVersion et targetSdkVersion de 29 à 28 a résolu mon problème.

0
Hadi Ahmadi

J'ai résolu juste en utilisant:

setDestinationInExternalFilesDir(context, relativePath, filename);

Au lieu de:

setDestinationInExternalPublicDir(relativePath, filename);

Mon chemin relatif est:

Environment.getExternalStorageDirectory().getPath() + "MyExternalStorageAppPath"

J'ai également dans mon manifeste:

Android:requestLegacyExternalStorage="true"

Pour utiliser la gestion du stockage hérité (stockage partagé) au lieu de la nouvelle gestion du stockage (stockage étendu) utilisée à partir de Android 10 et supérieur).

0
Z3R0