2017-07-15 1 views
0

s'il vous plaît voir mon code ci-dessous que je utiliser pour télécharger une vidéo sur un serveur. Toutefois, pour les vidéos suffisamment volumineuses, j'obtiens une exception OutOfMemory. Est-ce que quelqu'un peut me diriger dans la bonne direction sur comment éviter l'exception OutOfMemory? Y a-t-il un moyen de passer de InputStream à requestBody?Android - comment télécharger une vidéo en morceaux en utilisant OkHTTP?

Répondre

1

Vous pouvez créer un RequestBody personnalisé qui diffuse les données. Vous devrez faire attention: il peut être réutilisé plusieurs fois car OkHttp peut décider de réessayer la requête. Assurez-vous de pouvoir rouvrir le InputStream à chaque fois.

ContentResolver contentResolver = context.getContentResolver(); 
final String contentType = contentResolver.getType(videoUri); 
final AssetFileDescriptor fd = contentResolver.openAssetFileDescriptor(videoUri, "r"); 
if (fd == null) { 
    throw new FileNotFoundException("could not open file descriptor"); 
} 
RequestBody videoFile = new RequestBody() { 
    @Override public long contentLength() { return fd.getDeclaredLength(); } 
    @Override public MediaType contentType() { return MediaType.parse(contentType); } 
    @Override public void writeTo(BufferedSink sink) throws IOException { 
     try (InputStream is = fd.createInputStream()) { 
      sink.writeAll(Okio.buffer(Okio.source(is))); 
     } 
    } 
}; 
RequestBody requestBody = new MultipartBody.Builder() 
     .setType(MultipartBody.FORM) 
     .addFormDataPart("file", "fname", videoFile) 
     .build(); 
Request request = new Request.Builder() 
     .url(uploadURL) 
     .post(requestBody) 
     .build(); 
client.newCall(request).enqueue(new Callback() { 
    @Override public void onFailure(Call call, IOException e) { 
     try { 
      fd.close(); 
     } catch (IOException ex) { 
      e.addSuppressed(ex); 
     } 
     Log.e(TAG, "failed", e); 
    } 
    @Override public void onResponse(Call call, Response response) throws IOException { 
     fd.close(); 
    } 
}); 
+0

Merci beaucoup! Savez-vous comment je peux rouvrir le flux au cas où la demande serait réessayée? – JK140

+0

Aussi, quel est le but d'appeler fd.close() seulement après qu'une réponse est reçue? – JK140

+0

@ JK140 1. Ouvrez un 'InputStream' chaque fois que' RequestBody.writeTo() 'est appelé, comme dans cet exemple. Si vous ouvrez le 'InputStream' en dehors de' writeTo() ', il lira le tout la première fois et les tentatives suivantes n'auront aucune donnée. 2. Le 'AssetFileDescriptor' continue à être utilisé jusqu'à ce que la réponse soit complète (et il doit être fermé, sinon c'est une fuite de ressource). Vous pouvez également utiliser * non * 'AssetFileDescriptor', et récupérer à la place la longueur une fois (peut-être en utilisant' ContentResolver.query() '), et utiliser et fermer' ContentResolver.openInputStream() 'dans' writeTo'. – ephemient