Как загрузить файл или фото на сервер из Android‑приложения

Короткий ответ: используйте POST с Content-Type: multipart/form-data (Retrofit + OkHttp) — подготовьте файл (или InputStream → временный файл), создайте MultipartBody.Part и RequestBody для дополнительных полей, отправляйте в фоне, показывайте прогресс, проверяйте ошибки сети и используйте HTTPS.

Что выбрать и какие договорённости нужны с backend

Прежде чем писать код, согласуйте с backend:

  • URL и метод (например, POST /api/upload).
  • Имя поля для файла (file, image и т. п.).
  • Требуемые доп. поля (user_id, token, description).
  • Максимальный размер и допустимые MIME‑типы.
  • Формат успешного ответа (JSON: url, id, size).

Если контролируете сервер — предпочтительнее отдавать клиенту endpoint с multipart/form-data. Для больших файлов лучше использовать pre-signed URL (S3/GCS) и загружать напрямую в хранилище.

Практическая реализация (Kotlin, Retrofit + OkHttp)

  1. Разрешения и получение файла
  • Для выбора файла используйте ACTION_OPEN_DOCUMENT (SAF) — не требует READ_EXTERNAL_STORAGE на новых Android.
  • Для камеры — ACTION_IMAGE_CAPTURE + FileProvider, не забудьте runtime‑разрешение CAMERA при необходимости.
  • По Uri открывайте contentResolver.openInputStream(uri) и копируйте в временный файл в context.cacheDir.
  1. Подготовка Multipart
  • Получив File или временный файл: val requestFile = file.asRequestBody(mimeType.toMediaType()) val part = MultipartBody.Part.createFormData("file", file.name, requestFile) val desc = "Описание".toRequestBody("text/plain".toMediaType())
  1. Retrofit API interface UploadApi { @Multipart @POST("upload") suspend fun uploadFile( @Part file: MultipartBody.Part, @Part("description") description: RequestBody ): Response }

  2. Отправка и обработка ответа

  • Выполняйте вызов в корутине (IO Dispatcher) или через WorkManager для фоновой загрузки.
  • Проверяйте response.isSuccessful и разбирайте body() или errorBody() для сообщений об ошибке.
  • Настройте таймауты в OkHttpClient (connect/read/write) для больших файлов.

Как показывать прогресс загрузки

Создайте обёртку RequestBody, которая в writeTo(...) считает отправленные байты и через callback обновляет UI (через Main thread):

  • Не обновляйте UI прямо из writeTo — используйте Handler или сompletion callback, который переключается в основной поток.
  • Для множества файлов реализуйте очередь и атомарные статусы (загружается, успешно, ошибка).

Храните большие временные файлы в context.cacheDir и очищайте их после успешной загрузки.

Обработка ошибок и устойчивость

Частые ситуации:

  • Нет сети: показывайте понятное сообщение и кнопку "Повторить".
  • Таймаут: предложите повторную попытку с экспоненциальной задержкой или по кнопке.
  • 4xx: проверьте авторизацию/поля — покажите текст ошибки от сервера.
  • 5xx: серверная проблема — предложите повтор позже. Технически: разделяйте сетевые ошибки и ошибки API, логируйте (interceptor) и не блокируйте UI.

Безопасность и валидация

  • Всегда используйте HTTPS.
  • Не отправляйте лишних метаданных (пути, локальные идентификаторы).
  • Храните токены безопасно (EncryptedSharedPreferences/Keystore).
  • На сервере проверяйте MIME по сигнатуре, ограничивайте размер и форматы, не полагайтесь на клиентскую проверку.

Частые ошибки

  • Отправка больших изображений без ресайза → таймауты и высокий расход трафика.
  • Неправильное имя поля multipart → 400/422 от сервера.
  • Попытка читать Uri напрямую как File на Android 10+ — используйте InputStream/SAF.
  • Обновление UI из фонового потока внутри RequestBody.writeTo.

FAQ

  • Нужно ли копировать Uri в File? Часто да: многие библиотеки удобнее работают с File, а также чтобы определить размер и имя. Для больших файлов лучше стримить без полного чтения в память.
  • Можно ли отправить файл в JSON (Base64)? Можно, но плохо: размер растёт ~33%, нагрузка на CPU/память; годится только для очень маленьких файлов.
  • Как загрузить в фоне при уходе из приложения? Используйте WorkManager (особенно если нужно гарантировать доставку при рестарте устройства).

Если укажете стек (Kotlin/Java, Retrofit/OkHttp или чистый OkHttp) и точный контракт API — пришлю минимальный рабочий пример кода под вашу конфигурацию.