通过Retrofit从内存上传位图

3

我想要:

  1. 从相册或相机加载文件。
  2. 调整其大小。
  3. 通过Retrofit将获取的Bitmap上传到类似于“/api/file”的服务器请求。

步骤1和2已完成,我想上传Bitmap。该请求是POST(Accept:application/json,Content-Type:multipart/form-data)。它接收文件作为文件而不是文本。

我找到了许多主题,例如https://futurestud.io/tutorials/retrofit-2-how-to-upload-files-to-server如何使用Retrofit / Android将位图发布到服务器如何在Retrofit 2中上传图像文件,但我不理解:

1)我应该将内存中的Bitmap保存为文件并上传,

2)还是可以使用Retrofit将其作为字节数组或流从内存中上传?

如果选择2,我该如何编写请求?


你可以尝试这个:https://dev59.com/Q4zda4cB1Zd3GeqPr9oL - Santanu Sur
尝试第二个答案...在帖子中。 - Santanu Sur
@SantanuSur,谢谢,我可能会尝试。 - CoolMind
你应该先告诉我们服务器希望以哪种方式接收你的图像。只有这样,我们才能建议如何操作。如果服务器需要一个jpg文件,发送base64是没有意义的。 - greenapps
@greenapps,可能它期望的是JPEG文件,但这并不是限制(我认为,我们可以加载多种类型的图片)。据我所知,Base64格式在我们的服务器上受支持。我还能在问题中添加什么? - CoolMind
@ greenapps,看起来服务器不接受文本,只接受文件(4xx错误,Postman也显示带有错误消息的JSON)。因此,我认为这个问题不再可靠。 - CoolMind
1个回答

1
根据图像大小,您可以将其转换为Base64编码,并在正文中使用标准上传内容。
如果要上传大文件,则应坚持使用多部分上传,在这种情况下,它将作为文件进行发送,但您必须指定文件类型,API需要适当解析。有许多出色的库可帮助您完成此操作,如OKHTTP,Retro也将利用此库。
但是,图像、文档和视频在传输层上都只是文件,只需要在调用中为图像提供适当的请求类型,以帮助API适当处理。
这是他们教程中的内容:
   HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

// Change base URL to your upload server URL.
service = new Retrofit.Builder().baseUrl("http://192.168.0.234:3000").client(client).build().create(Service.class);

.
.
.

File file = new File(filePath);

RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("upload", file.getName(), reqFile);
RequestBody name = RequestBody.create(MediaType.parse("text/plain"), "upload_test");

retrofit2.Call<okhttp3.ResponseBody> req = service.postImage(body, name);
req.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { 
        // Do Something
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        t.printStackTrace();
    }
});

如果文件不太大,可以使用Base64编码。

    public class Base64EncodeMediaAsyncTask extends AsyncTask<Void, Void, MediaModel> {

    /*///////////////////////////////////////////////////////////////
    // MEMBERS
    *////////////////////////////////////////////////////////////////
    private static final String TAG = Globals.SEARCH_STRING + Base64EncodeMediaAsyncTask.class.getSimpleName();
    private Context mContext;
    private MediaModel mMediaModelToConvert;


    /*///////////////////////////////////////////////////////////////
    // CONSTRUCTOR
    *////////////////////////////////////////////////////////////////
    public Base64EncodeMediaAsyncTask(Context context, MediaModel model){
        mContext = context;
        mMediaModelToConvert = model;

    }


    /*///////////////////////////////////////////////////////////////
    // OVERRIDES
    *////////////////////////////////////////////////////////////////
    @Override
    protected MediaModel doInBackground(Void... params) {
        try{
            InputStream inputStream = new FileInputStream(mMediaModelToConvert.getAbsoluteLocalPath());//You can get an inputStream using any IO API
            byte[] bytes;
            byte[] buffer = new byte[(int) new File(mMediaModelToConvert.getAbsoluteLocalPath()).length()];
            int bytesRead;

            ByteArrayOutputStream output = new ByteArrayOutputStream();
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                output.write(buffer, 0, bytesRead);
            }

            bytes = output.toByteArray();

            mMediaModelToConvert.setBase64String(Base64.encodeToString(bytes, Base64.DEFAULT));

        }catch (Exception ex){
            //todo consider moving failed uploads to table known for failures to let user know to delete, or validate file or try again
            A35Log.e(TAG, "Failed to get base 64 encoding for file: " + mMediaModelToConvert.getAbsoluteLocalPath());
            return null;

        }

        return mMediaModelToConvert;

    }
    @Override
    protected void onPostExecute(MediaModel success) {
        super.onPostExecute(success);

    }

}

请忽略我用于包装其他内容的复杂对象MediaModel,只使用标准文件(即指向您的图像的指针)


谢谢。如果我将其转换为Base64(https://dev59.com/4Wox5IYBdhLWcg3wazmR),我可以在请求体中上传此字符串吗? - CoolMind
更新,请查看最新版本。 - Sam
谢谢。我认为服务器不接受Base64编码的文本,只接受文件。所以我会尝试其他上传方式。 - CoolMind
Sam,你的代码按预期处理文件。我将再次尝试Base64。 - CoolMind
很酷,只要确保你不使用multipart,如果你想使用base64编码的Jon属性路由。祝你好运。 - Sam
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接