Загрузить файл хранилища Firebase в URI на Android - PullRequest
0 голосов
/ 27 января 2020

Я использую хранилище Firebase для хранения изображений после того, как они были выбраны в галерее или с камеры. У меня есть функция createUriForFile(), которую я использую, чтобы получить URI для локального сохранения изображения. Когда изображение выбрано, оно сохраняется в правильном месте и, используя glide и тот же createUriForFile(), что и раньше, оно отображается и также корректно загружается в Firebase. Но когда я использую другой эмулятор, чем тот, на котором были сделаны изображения, и пытаюсь загрузить изображение, оно выдает Java.io.IOException: no such file or directory. Я не понимаю почему, потому что все работает с этим спецификацией c URI, за исключением загрузки его для сохранения на устройстве.

Я знаю, что настройки и код для Firebase верны, потому что когда я использую File в качестве цели вместо URI, изображение загружается и отображается (API <= 28). Но с Android 29 мы больше не можем использовать прямой доступ к файлам (я хочу сохранить изображение в общей папке, чтобы отобразить его в галерее). Я понимаю, что вы можете использовать <code>inputStream и outputStream, но это кажется такой большой работой, поскольку getFile() принимает URI в качестве аргумента. Так что я думаю, что это должно быть что-то, что я делаю неправильно. Он не работает ни по API 29, ни по <= 28. Каталоги создаются, когда приложение пытается загрузить файл, и оно работает при сохранении и загрузке, поэтому <code>URI вроде бы нормально.

Я добавил fileprovider в файл манифеста и добавил пути к файлу xml.

createUriForFile:

EXTERNAL_PICTURE_RELATIVE_PATH = Environment.DIRECTORY_PICTURES + File.separator + baseActivity.getString(R.string.app_name);
EXTERNAL_PICTURE_STORAGE_DIR = baseActivity.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath() + File.separator + EXTERNAL_PICTURE_RELATIVE_PATH;

public Uri createUriForFile(String fileName, String parentId)
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
    {
        //check if there is already an entry in ContentResolver
        Uri uriFromContentResolver = getUriFromContentResolver(fileName);
        if(uriFromContentResolver != null)
        {
            return uriFromContentResolver;
        }else
        {
            ContentResolver resolver = baseActivity.getApplicationContext().getContentResolver();
            ContentValues contentValues = new ContentValues();
            contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
            contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
            contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, EXTERNAL_PICTURE_RELATIVE_PATH);
            return resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
        }
    }else
    {
        checkAndCreatePictureDir(parentId);
        File pictureFile = new File(EXTERNAL_PICTURE_STORAGE_DIR + File.separator + parentId + File.separator + fileName);

        return FileProvider.getUriForFile(baseActivity.getBaseContext(), baseActivity.getApplicationContext().getPackageName() + ".fileprovider", pictureFile);
    }
}

Stacktrace для ошибки:

E/StorageException: StorageException has occurred.
An unknown error occurred, please check the HTTP result code and inner exception for server response.
 Code: -13000 HttpResult: 200
No such file or directory
java.io.IOException: No such file or directory
    at java.io.UnixFileSystem.createFileExclusively0(Native Method)
    at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:281)
    at java.io.File.createNewFile(File.java:1008)
    at com.google.firebase.storage.FileDownloadTask.processResponse(com.google.firebase:firebase-storage)
    at com.google.firebase.storage.FileDownloadTask.run(com.google.firebase:firebase-storage)
    at com.google.firebase.storage.StorageTask.lambda$getRunnable$7(com.google.firebase:firebase-storage@@19.1.0:1072)
    at com.google.firebase.storage.StorageTask$$Lambda$12.run(Unknown Source:2)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:764)

Любая помощь или подсказка высоко ценится.

Ответы [ 2 ]

0 голосов
/ 31 января 2020

При поиске решения я дважды проверил документацию Firebase. Я нашел это:

getFile(Uri destinationUri)
Asynchronously downloads the object at this StorageReference to a specified system filepath.

Хотя я не видел его первые пару раз, и он говорит, что может принять URI, ему все еще нужен реальный путь к файлу в системе. Поэтому я решил go с использованием inputStream и outputStream для записи данных через ContentResolver

0 голосов
/ 27 января 2020

Вам необходимо объявить разрешение в Android Манифесте и объявить метаданные тега

    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths"/>
    </provider>

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path
        name="external_files"
        path="." />
</paths>
...