Загрузить файл в slack с помощью Retrofit2

Я пытаюсь загрузить файл (дамп кучи) в слабый канал, используя последнюю версию Retrofi2.

@Override
public void onCreate() {
    super.onCreate();
    slackApi = new Retrofit.Builder()
            .baseUrl("https://slack.com/")
            .build() //
            .create(SlackApi.class);
}


@Multipart
    @GTConverterAnnotation(value = GTConverterAnnotation.GSON)
    @POST("api/files.upload")
    Call<ResponseBody> uploadFile(
            @Part("token") String token,
            @Part("file") RequestBody file, @Part("filetype") String filetype,
            @Part("filename") String filename, @Part("title") String title,
            @Part("initial_comment") String initialComment, @Part("channels") String channels);


 RequestBody file = RequestBody
            .create(MediaType.parse("multipart/form-data"), heapDump.heapDumpFile);
    final Call<ResponseBody> call = slackApi.uploadFile(SlackApi.TOKEN,
            file,
            null,
            heapDump.heapDumpFile.getName(), title, initialComment,
            SlackApi.MEMORY_LEAK_CHANNEL);

Следующий код завершается с ошибкой даже до выполнения в «slack.uploaFile» со следующим исключением:

> E/AndroidRuntime: FATAL EXCEPTION: IntentService[com.squareup.leakcanary.AbstractAnalysisResultService]
Process: com.gettaxi.dbx.android, PID: 11127
java.lang.IllegalArgumentException: Could not locate RequestBody converter for class java.lang.String.
Tried:
* retrofit2.BuiltInConverters
at retrofit2.Retrofit.nextRequestBodyConverter(Retrofit.java:298)
at retrofit2.Retrofit.requestBodyConverter(Retrofit.java:258)
at retrofit2.ServiceMethod$Builder.parseParameterAnnotation(ServiceMethod.java:577)
at retrofit2.ServiceMethod$Builder.parseParameter(ServiceMethod.java:328)
at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:201)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:166)
at retrofit2.Retrofit$1.invoke(Retrofit.java:145)
at java.lang.reflect.Proxy.invoke(Proxy.java:397)
at $Proxy13.uploadFile(Unknown Source)
at com.gettaxi.dbx.android.services.LeakSlackUploadService.afterDefaultHandling(LeakSlackUploadService.java:50)
at com.squareup.leakcanary.DisplayLeakService.onHeapAnalyzed(DisplayLeakService.java:86)
at com.squareup.leakcanary.AbstractAnalysisResultService.onHandleIntent(AbstractAnalysisResultService.java:49)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.os.HandlerThread.run(HandlerThread.java:61)

Что мне не хватает? Почему он ищет конвертер RequestBody для строки?

update Только что создано полное решение, похожее на то, что предлагает Matrix: https://gist.github.com/parahall/cbba57d9d10f6dcd850f


person Yonatan Levin    schedule 17.03.2016    source источник


Ответы (2)


Во-первых, я хочу отметить, что есть и другие способы добиться этого, но я пошел дальше, просто убедившись, что решение работает без серьезных недостатков.

Пожалуйста, ознакомьтесь с моим репозиторием здесь: Обновление: URL-адрес и имя репо изменились https://github.com/MaTriXy/Slackrofit

Вставка соответствующего кода:

@Multipart
@POST("api/files.upload")
Call<UploadFileResponse> uploadFile(
        @Query("token") String token,
        @PartMap Map<String, RequestBody> params,
        @Query("filetype") String filetype,
        @Query("filename") String filename, @Query("title") String title,
        @Query("initial_comment") String initialComment, @Query("channels") String channels);

    slackApi = new Retrofit.Builder().baseUrl("https://slack.com/").client(new OkHttpClient())
            .addConverterFactory(GsonConverterFactory.create())
            .build().create(SlackApi.class);


    String str = "Google Places API for Android Samples\n" +
            "===================================\n" +
            "\n" +
            "Samples that use the [Google Places API for Android](https://developers.google.com/places/android/).\n" +
            "\n" +
            "This repo contains the following samples:";
    file = RequestBody.create(MediaType.parse("multipart/form-data"), str.getBytes());

    Map<String, RequestBody> map = new HashMap<>();
    map.put("file\"; filename=\"heapDump.md\"", file);
    call = slackApi.uploadFile(SlackApi.TOKEN, map, "text",
 "heapDump.md", "Test Dump", "Check this out", SlackApi.MEMORY_LEAK_CHANNEL);

Позже, чтобы активировать вызов:

call.clone().enqueue(new Callback<SlackApi.UploadFileResponse>() {
    @Override
    public void onResponse(Call<SlackApi.UploadFileResponse> call, Response<SlackApi.UploadFileResponse> response) {
        if (response != null) {
            Log.e("GAG", response.body().toString());
        }
    }

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

Я использую клон для тестирования нескольких загрузок, хотя это позволяет мне не перестраивать новый вызов каждый раз, когда я хочу его использовать.

UploadFileResponse прост:

public static class UploadFileResponse {

    boolean ok;
    String error;

    @Override
    public String toString() {
        return "UploadFileResponse{" +
                "ok=" + ok +
                ", error='" + error + '\'' +
                '}';
    }
}
person MaTriXy    schedule 19.03.2016

Вы добавили конвертер для своего Retrofit?

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://api.example.com/")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();
person toantran    schedule 17.03.2016
comment
Почему я должен использовать GsonConverterFactory, если я не конвертирую JSON? - person Yonatan Levin; 17.03.2016