Создать файл из URI фотографии на Android - PullRequest
1 голос
/ 25 мая 2019

У меня есть приложение для Android, которое позволяет пользователю выбирать некоторые изображения из галереи и отправлять эти изображения на сервер (вместе с некоторыми другими данными).

Чтобы позволить пользователю выбирать изображения, которые яв моем фрагменте есть следующее:

private void pickImages() {
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.setType("image/*");
    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
    startActivityForResult(intent, PICK_PHOTO_FOR_AVATAR);
}

Я получаю результат выбранных фотографий пользователем здесь:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == PICK_PHOTO_FOR_AVATAR && resultCode == Activity.RESULT_OK) {
        if (data == null) {
            //Display an error
            Toast.makeText(getActivity(), "There was an error getting the pictures", Toast.LENGTH_LONG).show();
            return;
        }

        ClipData clipData = data.getClipData();
        String fileName = null, extension = null;

        //if ClipData is null, then we have a regular file
        if (clipData == null) {
            //get the selected file uri
            fileName = FileUtils.getPath(getActivity(), data.getData());
            //obtain the extension of the file
            int index = fileName.lastIndexOf('.');
            if (index > 0) {
                extension = fileName.substring(index + 1);
                if (extension.equals("jpg") || extension.equals("png") || extension.equals("bmp") || extension.equals("jpeg"))
                    isAttachedFile = true;
            }
        }

        ArrayList<Uri> photosUris = new ArrayList<>();

        //for each image in the list of images, add it to the filesUris
        if (clipData != null) for (int i = 0; i < clipData.getItemCount(); i++) {
            ClipData.Item item = clipData.getItemAt(i);
            Uri uri = item.getUri();
            switch (i) {
                case 0:
                    picture1Uri = uri;
                    break;
                case 1:
                    picture2Uri = uri;
                    break;
            }
            photosUris.add(uri);
        }
        else if (isAttachedFile) {
            Uri uri = Uri.parse(fileName);
            picture1Uri = uri;
            photosUris.add(uri);
        }

        uris = photosUris;

        if (picture1Uri != null) {
            image1.setVisibility(View.VISIBLE);
            image1.setImageURI(picture1Uri);
        }
        if (picture2Uri != null) {
            image2.setVisibility(View.VISIBLE);
            image2.setImageURI(picture2Uri);
        }
    }

Затем я отправляю список URI докладчику,где я выполняю мой вызов MultiPart Retrofit к бэкэнду:

//obtain the file(s) information of the message, if any
    if (uris != null && uris.size() > 0) {
        for (int i = 0; i < uris.size(); i++) {
            File file = null;

            //this is the corect way to encode the pictures
            String encodedPath = uris.get(i).getEncodedPath();
            file = new File(encodedPath);

            builder.addFormDataPart("photos[]", file.getName(), RequestBody.create(MediaType.parse("multipart/form-data"), file));
        }
    }

    MultipartBody requestBody = builder.build();

    //send the newly generated ticket
    Call<GenerateNewTicketResponse> generateNewTicketCall = OperatorApplication.getApiClient().generateNewTicket(Constants.BEARER + accessToken, requestBody);

Проблема в том, что это иногда работает, иногда нет.Иногда я получаю сообщение об ошибке «java.io.FileNotFoundException», которое приводит меня к обратному вызову onFailure() вызова Retrofit.

Я обнаружил следующую запись stackoverflow Чтение файла из Uri дает java.io.FileNotFoundException: open failed: ENOENT , но я не совсем уверен, как реализовать общее предложение в этом ответе на мою конкретную ситуацию.

Каков будет правильный путь, чтобы получить правильный путь ккартинки, выбранные пользователем, чтобы я мог создавать из них файлы и прикреплять их в своем запросе MultiPart?

Commonsware предложила

Используйте ContentResolver и openInputStream (), чтобы получитьInputStream для контента, на который указывает Uri.Затем передайте это вашей логике декодирования, такой как BitmapFactory и ее метод decodeStream ().

, но я не совсем уверен, как это сделать программно.

Любая помощьбудет оценена.

1 Ответ

1 голос
/ 25 мая 2019

Чтобы позволить пользователю выбирать изображения, у меня есть следующее в моем фрагменте:

Этот код использует ACTION_GET_CONTENT. В частности, на Android 7.0+, как правило, он возвращает значения Uri со схемой content. Ваш код предполагает, что вы получаете Uri значений по схеме file, где путь действительно имеет значение. Более того, ваш код предполагает, что пользователь выбирает файлы в файловой системе, к которым у вас есть доступ, и нет ничего, что заставляло бы пользователя делать это. ACTION_GET_CONTENT может поддерживаться приложениями, содержимое которых:

  • Локальный файл на внешнем хранилище
  • Локальный файл на внутреннем хранилище для другого приложения
  • Локальный файл на съемном носителе
  • Локальный файл, который зашифрован и должен быть расшифрован на лету
  • Поток байтов, содержащийся в столбце BLOB в базе данных
  • Часть содержимого в Интернете, которую сначала необходимо загрузить другим приложением
  • Контент, который генерируется на лету
  • ... и т. Д.

Вместо RequestBody.create() используйте InputStreamRequestBody из этого комментария к выпуску OkHttp . Вы предоставляете тот же тип носителя, что и раньше, но вместо File (который вы создаете неправильно) вы предоставляете ContentResolvergetContentResolver() на Context) и Uri.

...