Java 在Android上从照片URI创建文件

Java 在Android上从照片URI创建文件,java,android,file,photo,multipart,Java,Android,File,Photo,Multipart,我有一个Android应用程序,需要让用户从图库中选择一些图片,并将这些图片发送到后端(以及其他一些数据) 要允许用户选择图片,我的片段中有以下内容: private void pickImages() { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

我有一个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);
        }
    }
@覆盖
ActivityResult上的公共void(int请求代码、int结果代码、意图数据){
super.onActivityResult(请求代码、结果代码、数据);
if(requestCode==为头像选择照片&&resultCode==Activity.RESULT\u确定){
如果(数据==null){
//显示错误
Toast.makeText(getActivity(),“获取图片时出错”,Toast.LENGTH_LONG.show();
返回;
}
ClipData ClipData=data.getClipData();
字符串文件名=null,扩展名=null;
//如果ClipData为null,则我们有一个常规文件
if(clipData==null){
//获取选定的文件uri
fileName=FileUtils.getPath(getActivity(),data.getData());
//获取文件的扩展名
int index=fileName.lastIndexOf('.');
如果(索引>0){
扩展名=fileName.substring(索引+1);
if(extension.equals(“jpg”)| | extension.equals(“png”)| | extension.equals(“bmp”)| | extension.equals(“jpeg”))
isAttachedFile=true;
}
}
ArrayList photouris=新的ArrayList();
//对于图像列表中的每个图像,将其添加到文件URI中
if(clipData!=null)for(int i=0;i
然后,我将URI列表发送给演示者,在演示者中执行对后端的多部分改装调用:

//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);
//获取消息的文件信息(如果有)
if(uri!=null&&uris.size()>0){
对于(int i=0;i
问题是,这有时有效,有时无效。有时我会收到错误“java.io.FileNotFoundException”,这会使我陷入改装调用的
onFailure()
回调中

我找到了下面的stackoverflow帖子,但我不确定如何根据我的具体情况实施该建议

要获得用户选择的图片的正确路径,以便我可以使用这些图片创建文件并将其附加到我的多部分请求中,正确的方法是什么

建议使用公共软件

使用ContentResolver和openInputStream()获取Uri指向的内容的InputStream。然后,将其传递给解码逻辑,例如BitmapFactory及其decodeStream()方法

,但我不确定如何通过编程实现

任何帮助都将不胜感激

要允许用户选择图片,我的片段中有以下内容:

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);
}
这段代码使用的是
ACTION\u GET\u CONTENT
。尤其是在Android 7.0+上,它通常会使用
CONTENT
方案返回
Uri
值。您的代码假设您使用
file
方案获得
Uri
值,路径实际上是有意义的。此外,您的代码假设用户是在文件系统上选择您可以访问的文件,并且没有任何东西强迫用户这样做。
ACTION\u GET\u CONTENT
可以由应用程序支持,这些应用程序的内容是:

  • 外部存储器上的本地文件
  • 另一个应用程序的内部存储上的本地文件
  • 可移动存储上的本地文件
  • 加密的本地文件,需要动态解密
  • 数据库中
    BLOB
    列中保存的字节流
  • 互联网上需要其他应用程序先下载的内容
  • 动态生成的内容
  • ……等等
不要使用
RequestBody.create()
,而要使用来自的
InputStreamRequestBody
。您提供的媒体类型与以前相同,但您提供的不是
文件(您创建的文件不正确),而是
内容解析程序(来自
上下文上的
getContentResolver()
)和
Uri


演示如何使用
InputStreamRequestBody
(特别是原始版本的Kotlin端口)以这种方式上载内容。提供了对相同问题和类似解决方案的另一种看法。

是的,您是对的。但请记住,我需要随请求发送一些其他键值对,如下所示: