I know it's a common and recurrent question, but I didn't find any good or recent answer.
Please do not close this question. It can be a very recent reference for future Android developers who try to achieve that because most of the answers that I've seen through SO are deprecated or do not work as expected.
I want to pick one image or video from an Android device and upload it to my server.
I've already achieved pick and upload part of an image but the solution is barely good.
First, it is in Java (my whole project is in Kotlin, if I refactor directly the solution in Kotlin I get some crash on runtime).
Second, I don't think this solution is the best to achieve the same process with a video (even if the process is working on small video ~5/10 seconds, on longer video 30 to 180 seconds, I get a timeout).
How I pick a media:
private fun importPicture() {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
startActivityForResult(intent, PICK_IMAGE_REQUEST_CODE)
}
private fun importVideo(){
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "video/*"
startActivityForResult(intent, PICK_VIDEO_REQUEST_CODE)
}
My process to upload the media after getting the Uri
: Uri
-> File
-> MultipartBody
using Retrofit2
and RxJava2
Here is the solution that I'm using to get the File
from the Uri
from this answer (other answers on this post don't work !!):
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.OpenableColumns;
import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class FileUtile {
private static final int EOF = -1;
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
public static File from(Context context, Uri uri) throws IOException {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
String fileName = getFileName(context, uri);
String[] splitName = splitFileName(fileName);
File tempFile = File.createTempFile(splitName[0] + "tmp", splitName[1]);
tempFile = rename(tempFile, fileName);
tempFile.deleteOnExit();
FileOutputStream out = null;
try {
out = new FileOutputStream(tempFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if (inputStream != null) {
copy(inputStream, out);
inputStream.close();
}
if (out != null) {
out.close();
}
return tempFile;
}
private static String[] splitFileName(String fileName) {
String name = fileName;
String extension = "";
int i = fileName.lastIndexOf(".");
if (i != -1) {
name = fileName.substring(0, i);
extension = fileName.substring(i);
}
return new String[]{name, extension};
}
private static String getFileName(Context context, Uri uri) {
String result = null;
if (uri.getScheme().equals("content")) {
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
}
if (result == null) {
result = uri.getPath();
int cut = result.lastIndexOf(File.separator);
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}
private static File rename(File file, String newName) {
File newFile = new File(file.getParent(), newName);
if (!newFile.equals(file)) {
if (newFile.exists() && newFile.delete()) {
Log.d("FileUtil", "Delete old " + newName + " file");
}
if (file.renameTo(newFile)) {
Log.d("FileUtil", "Rename file to " + newName);
}
}
return newFile;
}
private static long copy(InputStream input, OutputStream output) throws IOException {
long count = 0;
int n;
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
while (EOF != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
}
How I build my requests:
fun uploadPost(token: String,
file: File,
post: Post): Completable {
val map = HashMap<String, Any>()
map["location"] = post.location
map["title"] = post.title
map["description"] = post.description
map["categories"] = post.categories.toList()
map["tags"] = post.tags.toList()
map["price"] = post.priceExcT
val body = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("model", JSONObject(map.toMap()).toString())
.addFormDataPart("file", file.name, RequestBody.create(MEDIA_TYPE_JPEG, file))
.build()
return apiService.uploadPost(token, body)
}
fun uploadVideo(token: String,
file: File,
post: Post): Completable {
val map = HashMap<String, Any>()
map["location"] = post.location
map["title"] = post.title
map["description"] = post.description
map["categories"] = post.categories.toList()
map["tags"] = post.tags.toList()
map["price"] = post.priceExcT
val body = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("model", JSONObject(map.toMap()).toString())
.addFormDataPart("file", file.name, RequestBody.create(MEDIA_TYPE_MP4, file))
.build()
return apiService.uploadVideo(token, body)//simple POST in ApiService which is an Interface
}
I already tried several and simple solutions as uri.toFile()
of course it doesn't work.
If you need any more information or snippet please ask me.