Подтвердить что ты не робот

Загрузка двоичного файла с помощью okhttp из ресурсов

Мне нужно загрузить двоичный файл, входящий в apk, на сервер, используя okhttp. Используя urlconnection, вы можете просто получить входной поток в актив и затем поместить его в свой запрос. Однако okhttp дает вам возможность загружать байт-массивы, строки или файлы. Поскольку вы не можете получить путь к файлу для ресурса, входящего в apk, является единственной возможностью скопировать файл в локальный каталог файлов (я бы этого не сделал), а затем предоставить файл okhttp? Нет ли способа просто сделать запрос с использованием ресурса-источника непосредственно на веб-сервере?

EDIT: я использовал принятый ответ, но вместо создания статического класса утилиты я просто подклассифицировал RequestBody

 public class InputStreamRequestBody extends RequestBody {

private InputStream inputStream;
private MediaType mediaType;

public static RequestBody create(final MediaType mediaType, final InputStream inputStream) {


    return new InputStreamRequestBody(inputStream, mediaType);
}

private InputStreamRequestBody(InputStream inputStream, MediaType mediaType) {
    this.inputStream = inputStream;
    this.mediaType = mediaType;
}

@Override
public MediaType contentType() {
    return mediaType;
}

@Override
public long contentLength() {
    try {
        return inputStream.available();
    } catch (IOException e) {
        return 0;
    }
}

@Override
public void writeTo(BufferedSink sink) throws IOException {
    Source source = null;
    try {
        source = Okio.source(inputStream);
        sink.writeAll(source);
    } finally {
        Util.closeQuietly(source);
    }
 }
}

Моя единственная проблема с этим подходом - ненадежность inputstream.available() для длины содержимого. Статический конструктор должен соответствовать внутренней реализации okhttp

4b9b3361

Ответ 1

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

public class RequestBodyUtil {

    public static RequestBody create(final MediaType mediaType, final InputStream inputStream) {
        return new RequestBody() {
            @Override
            public MediaType contentType() {
                return mediaType;
            }

            @Override
            public long contentLength() {
                try {
                    return inputStream.available();
                } catch (IOException e) {
                    return 0;
                }
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                Source source = null;
                try {
                    source = Okio.source(inputStream);
                    sink.writeAll(source);
                } finally {
                    Util.closeQuietly(source);
                }
            }
        };
    }
}

Затем просто используйте его так

OkHttpClient client = new OkHttpClient();

MediaType MEDIA_TYPE_MARKDOWN
        = MediaType.parse("text/x-markdown; charset=utf-8");

InputStream inputStream = getAssets().open("README.md");

RequestBody requestBody = RequestBodyUtil.create(MEDIA_TYPE_MARKDOWN, inputStream);
Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(requestBody)
        .build();

Response response = client.newCall(request).execute();
if (!response.isSuccessful())
    throw new IOException("Unexpected code " + response);

Log.d("POST", response.body().string());    

Этот примерный код был основан на этом коде. Замените имя файла Assets и MediaType на свой собственный.