setDestinationInExternalFilesDir() 工作 setDestinationInExternalPublicDir() 不

setDestinationInExternalFilesDir() works setDestinationInExternalPublicDir() doesn't

我正在尝试从 url 下载文件并将其保存到常规下载文件夹。 setDestinationInExternalPublicDir() 不起作用,也不会抛出任何异常。但是 setDestinationInExternalFilesDir() 工作正常。知道是什么原因吗?

我的代码是这样的:

webView.setDownloadListener(new DownloadListener() {
    @Override
    public void onDownloadStart(String url, String userAgent,
                                String contentDisposition, String mimeType,
                                long contentLength) {

        if (url.startsWith("data:")) {
            save(url);
            return;
        }


        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        request.setMimeType(mimeType);
        String cookies = CookieManager.getInstance().getCookie(url);
        request.addRequestHeader("cookie", cookies);
        request.addRequestHeader("User-Agent", userAgent);
        request.setDescription(getResources().getString(R.string.downloadingMsg));
        String filename = URLUtil.guessFileName(url, contentDisposition, mimeType);
        request.setTitle(filename);
        request.allowScanningByMediaScanner();
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
//DOESN'T WORK
            request.setDestinationInExternalPublicDir("Downloads", filename); 
//WORKS
            //request.setDestinationInExternalFilesDir(getApplicationContext(), "Downloads", filename); 
        DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        dm.enqueue(request);
        Toast.makeText(getApplicationContext(), R.string.downloadingMsg, Toast.LENGTH_LONG).show();
    }
});

和清单文件:

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

我从 url 下载图像的解决方案。

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.provider.CalendarContract;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.UUID;

public class DownloadImage extends AsyncTask<String, Void, Bitmap> implements MediaScannerConnection.MediaScannerConnectionClient {

    private Context context;
    private File mFile;
    private MediaScannerConnection mMs;


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

    private Bitmap downloadImageBitmap(String sUrl) {
        Bitmap bitmap = null;
        try {
            InputStream inputStream = new URL(sUrl).openStream();   // Download Image from URL
            bitmap = BitmapFactory.decodeStream(inputStream);       // Decode Bitmap
            inputStream.close();
        } catch (Exception e) {
            Log.d(TAG, "Exception 1, Something went wrong!");
            e.printStackTrace();
        }
        return bitmap;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        return downloadImageBitmap(params[0]);
    }

    protected void onPostExecute(Bitmap result) {
        String fileName = UUID.randomUUID().toString();
        getFilePath(fileName + ".jpg", result, context);
    }


    public void getFilePath(String name, Bitmap bitmap2, Context context) {
        Bitmap bitmap = bitmap2;
        String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();//Downloads folder path
        File myDir = new File(root);
        myDir.mkdirs();
        String fname = name.replaceAll("-", "");
        File file = new File(myDir, fname);
        if (file.exists()) {
            file.delete();
        }
        try {
            FileOutputStream out = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
            out.flush();
            out.close();
        } catch (Exception e) {
            Toast.makeText(context, "Error occurred", Toast.LENGTH_SHORT).show();
            return;
        }

        Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show();

        mFile = file;
        mMs = new MediaScannerConnection(context, this);//finding image in gallery after download 
        mMs.connect();

    }

    @Override
    public void onMediaScannerConnected() {
        mMs.scanFile(mFile.getAbsolutePath(), null);
    }

    @Override
    public void onScanCompleted(String path, Uri uri) {
        mMs.disconnect();
    }
}

运行 这个 class 在 Activity:

DownloadImage downloadImage = new DownloadImage(this);
downloadImage.execute("url");

UPD1: 我认为您可以使用此代码下载文件。

所以,我终于可以让 setDestinationInExternalPublicDir() 函数正常工作了。感谢 CommonsWare。通过关注 Commonsware 的评论和回答 ,我了解到在 android 版本 6+ 上,即使在清单文件中声明了权限,也应该在运行时请求它们。你猜怎么着,我正在使用 android 7...就是这样,我得到了 permission denied 错误。

所以我在我的 onCreate() 函数中添加了这些行,它也会提示用户在运行时获得权限(最终解决了我的问题):

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        int PERMISSION_REQUEST_CODE = 1;
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {

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