在Android上通过照片URI创建文件 [英] Create a file from a photo URI on Android

查看:89
本文介绍了在Android上通过照片URI创建文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Android应用程序,需要让用户从图库中选择一些图片,并将这些图片(以及其他一些数据)发送到后端.

I have an Android app that needs to let the user select some pictures from the gallery and send these pictures to the backend (together with some other data).

为允许用户选择图片,我在片段"中添加了以下内容:

To allow the user to select the pictures I have the following in my Fragment:

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);
}

我在这里得到用户选择的照片的结果:

I get the result of the selected photos by the user in here:

@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列表发送给Presenter,在其中执行对后端的MultiPart Retrofit调用:

I then send the list of URIs to the Presenter, where I execute my MultiPart Retrofit call to the backend:

//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",这使我陷入Retrofit调用的onFailure()回调中.

The problem is that this sometimes works, sometimes doesn't. Sometimes I get the error "java.io.FileNotFoundException", which throws me in the onFailure() callback of the Retrofit call.

我发现了以下stackoverflow帖子阅读来自Uri的文件给出了java.io.FileNotFoundException:打开失败:ENOENT ,但是我不确定如何在针对我的特定情况的响应中实施一般建议.

I found the following stackoverflow post Reading File from Uri gives java.io.FileNotFoundException: open failed: ENOENT but I'm not exactly sure how to implement the general suggestion in that response to my particular situation.

为用户选择的图片找到正确路径的正确方法是什么,以便我可以从中创建文件并将其附加到MultiPart请求中?

What would be the right way to get the right path towards the pictures selected by the user such that I can create files out of them and attach them in my MultiPart request?

建议使用

使用ContentResolver和openInputStream()获得有关Uri指向的内容的InputStream.然后,将其传递给您的解码逻辑,例如BitmapFactory及其解码流()方法.

Use a ContentResolver and openInputStream() to get an InputStream on the content pointed to by the Uri. Then, pass that to your decoding logic, such as BitmapFactory and its decodeStream() method.

,但我不确定如何以编程方式进行操作.

, but I'm not sure exactly how to do that programmatically.

任何帮助将不胜感激.

推荐答案

为允许用户选择图片,我在片段"中添加了以下内容:

To allow the user to select the pictures I have the following in my Fragment:

此代码正在使用ACTION_GET_CONTENT.特别是在Android 7.0+上,通常会使用content方案返回Uri值.您的代码假定您使用file方案获取Uri值,而该路径实际上具有含义.而且,您的代码假定用户正在选择您可以访问的文件系统上的文件,并且没有任何强迫用户这样做的事情. ACTION_GET_CONTENT可由其内容为以下内容的应用程序支持:

This code is using ACTION_GET_CONTENT. Particularly on Android 7.0+, generally that will return Uri values with a content scheme. Your code assumes that you are getting Uri values with a file scheme, where the path actually has meaning. Moreover, your code assumes that the user is picking files on the filesystem that you can access, and there is nothing that forces the user to do that. ACTION_GET_CONTENT can be supported by apps where their content is:

  • 外部存储中的本地文件
  • 内部存储中另一个应用程序的本地文件
  • 可移动存储中的本地文件
  • 已加密且需要动态解密的本地文件
  • 数据库的BLOB列中保存的字节流
  • 互联网上的内容首先需要由其他应用下载
  • 动态生成的内容
  • ...等等
  • A local file on external storage
  • A local file on internal storage for the other app
  • A local file on removable storage
  • A local file that is encrypted and needs to be decrypted on the fly
  • A stream of bytes held in a BLOB column in a database
  • A piece of content on the Internet that needs to be downloaded by the other app first
  • Content that is generated on the fly
  • ...and so on

而不是使用RequestBody.create(),而是使用此OkHttp中的InputStreamRequestBody发表评论.您提供了与以前相同的媒体类型,但是提供了ContentResolver(来自Context上的getContentResolver())和Uri来代替File(错误创建).

Instead of using RequestBody.create(), use the InputStreamRequestBody from this OkHttp issue comment. You provide the same media type as before, but instead of a File (that you are incorrectly creating), you provide a ContentResolver (from getContentResolver() on a Context) and the Uri.

这篇关于在Android上通过照片URI创建文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆