(Tutorial Android) Upload Image Using Retrofit


Upload file atau image dari Android ke server sanggup dilakukan dengan aneka macam macam cara, salah satunya memakai library retrofit.

Pada postingan kali ini saya akan menunjukkan tutorial upload image memakai retrofit.

Pada perkara kali ini kita akan mencoba mengupload image dengan dua metode yakni :

1. Multipart
2. Base64

Saya akan sedikit menjelaskan metode upload image dengan multipart maupun base64 tersebut.

Multipart : Metode yang memakai HTTP Request untuk mengirim data ke server. Metode ini biasanya dipakai untuk mengupload file yang sizenya besar.

Base64 : Metode yang dipakai untuk melaksanakan proses encoding terhadap suatu binary data (contohnya: image). Proses encoding tersebut akan menghasilkan format string. Nah, format string inilah nantinya yang akan dikirim ke server dan dilakukan proses decode untuk mengembalikannya ke binary.

Oke mari kita pribadi praktek saja.

Buat API 

- Pertama buat folder di htdocs dengan nama api
- Buat file php dengan nama upload.php, kemudian isikan code berikut :
<?php  $action = htmlspecialchars($_POST['action']);   $response = array("success" => FALSE);   if($action == "multipart") {      if ($_FILES["photo"]["error"] > 0) {       $response["success"] = FALSE;    $response["message"] = "Upload Failed";      } else {    $name_file=htmlspecialchars($_FILES['photo']['name']);              if (@getimagesize($_FILES["photo"]["tmp_name"]) !== false) {      move_uploaded_file($_FILES["photo"]["tmp_name"], $name_file);      $response["success"] = TRUE;        $response["message"] = "Upload Successfull";         }else{     $response["success"] = FALSE;     $response["message"] = "Upload Failed";    }     echo json_encode($response);      }  }else if($action == "base64") {   $photo = htmlspecialchars($_POST['photo']);    $photo = str_replace('data:image/png;base64,', '', $photo);   $photo = str_replace(' ', '+', $photo);    $data = base64_decode($photo);   $file = uniqid() . '.png';    file_put_contents($file, $data);    $response["success"] = TRUE;   $response["message"] = "Upload Successfull";      echo json_encode($response);  }  ?> 
Buat Project Android

Pertama, tambahkan library retrofit dan okhttp3 ke gradle module-level
dependencies {     compile fileTree(dir: 'libs', include: ['*.jar'])     testCompile 'junit:junit:4.12'     compile 'com.android.support:appcompat-v7:24.2.1'      // Network     compile 'com.squareup.retrofit2:retrofit:2.1.0'     compile 'com.squareup.retrofit2:converter-gson:2.1.0'     compile "com.squareup.okhttp3:okhttp:3.4.1"     compile 'com.squareup.okhttp3:logging-interceptor:3.4.1' }  
Buat layout dengan nama activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:paddingBottom="@dimen/activity_vertical_margin"     android:paddingLeft="@dimen/activity_horizontal_margin"     android:paddingRight="@dimen/activity_horizontal_margin"     android:paddingTop="@dimen/activity_vertical_margin"     tools:context="com.wimso.android_uploadimage.MainActivity">      <Button         android:id="@+id/btn_choose"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:text="Choose Photo"         android:layout_alignParentTop="true"         android:layout_alignParentLeft="true"         android:layout_alignParentStart="true" />      <ImageView         android:id="@+id/img_thumb"         android:layout_width="match_parent"         android:layout_height="250dp"         android:layout_below="@+id/btn_choose"         android:src="@mipmap/ic_launcher"         android:scaleType="centerCrop"         android:layout_alignParentLeft="true"         android:layout_alignParentStart="true" />      <Button         android:id="@+id/btn_upload_1"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:text="Upload with Multipart"         android:layout_below="@+id/img_thumb"         android:layout_alignParentLeft="true"         android:layout_alignParentStart="true" />      <Button         android:id="@+id/btn_upload_2"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:text="Upload with Base64"         android:layout_below="@+id/btn_upload_1"         android:layout_alignParentLeft="true"         android:layout_alignParentStart="true" />  </RelativeLayout>  
Buat package dengan nama network.

Buat kelas dengan nama Config.java di package network. Kelas ini berisi URL dan Endpoint dari API.
/**  * Created by Wim on 11/14/16.  */ public class Config {      public static final String BASE_URL = "http://192.168.2.31"; // Your local IP Address     public static final String API_DIR = "/api";      public static final String API_UPLOAD = BASE_URL + API_DIR + "/upload.php";  } 
Kemudian buat kelas dengan nama BaseResponse.java
/**  * Created by Wim on 11/14/16.  */ public class BaseResponse {      private boolean success;     private String message;      public boolean isSuccess() {         return success;     }      public void setSuccess(boolean success) {         this.success = success;     }      public String getMessage() {         return message;     }      public void setMessage(String message) {         this.message = message;     } }  
Kemudian buat sebuah interface dengan nama UploadInterface.java yang berisi method untuk mengupload image ke server. Method untuk mengupload image terdiri dari 2 yakni method dengan teknik multipart dan base46.
import okhttp3.MultipartBody; import okhttp3.RequestBody; import retrofit2.Call; import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.Multipart; import retrofit2.http.POST; import retrofit2.http.Part;  /**  * Created by Wim on 10/6/16.  */ public interface UploadInterface {      @Multipart     @POST(Config.API_UPLOAD)     Call<BaseResponse> uploadPhotoMultipart(             @Part("action") RequestBody action,             @Part MultipartBody.Part photo);      @FormUrlEncoded     @POST(Config.API_UPLOAD)     Call<BaseResponse> uploadPhotoBase64(             @Field("action") String action,             @Field("photo") String photo);  }  
Kemudian buat kelas UploadService.java untuk konfigurasi retrofit dan method dari interface.
/**  * Created by Wim on 10/7/16.  */ public class UploadService {      private UploadInterface uploadInterface;      public UploadService() {         OkHttpClient.Builder okhttpBuilder = new OkHttpClient().newBuilder();         okhttpBuilder.connectTimeout(60, TimeUnit.SECONDS);         okhttpBuilder.writeTimeout(60, TimeUnit.SECONDS);         okhttpBuilder.readTimeout(60, TimeUnit.SECONDS);         okhttpBuilder.retryOnConnectionFailure(true);          if (BuildConfig.DEBUG) {             HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();             interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);             okhttpBuilder.addInterceptor(interceptor);         }          Retrofit retrofit = new Retrofit.Builder()                 .baseUrl(Config.BASE_URL)                 .client(okhttpBuilder.build())                 .addConverterFactory(GsonConverterFactory.create())                 .build();          uploadInterface = retrofit.create(UploadInterface.class);     }      public void uploadPhotoMultipart(RequestBody action, MultipartBody.Part photo, Callback callback) {         uploadInterface.uploadPhotoMultipart(action, photo).enqueue(callback);     }      public void uploadPhotoBase64(String action, String photo, Callback callback) {         uploadInterface.uploadPhotoBase64(action, photo).enqueue(callback);     }  }  
Selanjutnya buat beberapa kelas utility berikut :

FileUtils.java
(Kelas ini saya modifikasi dari https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java )
import android.content.ContentUris; import android.content.Context; import android.content.CursorLoader; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.provider.DocumentsContract; import android.provider.MediaStore;  import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream;  /**  * Created by Wim on 9/29/16.  */ public class FileUtils {      /**      * @return Whether the URI is a local one.      */     public static boolean isLocal(String url) {         if (url != null && !url.startsWith("http://") && !url.startsWith("https://")) {             return true;         }         return false;     }      /**      * @param uri The Uri to check.      * @return Whether the Uri authority is ExternalStorageProvider.      * @author paulburke      */     public static boolean isExternalStorageDocument(Uri uri) {         return "com.android.externalstorage.documents".equals(uri.getAuthority());     }      /**      * @param uri The Uri to check.      * @return Whether the Uri authority is DownloadsProvider.      * @author paulburke      */     public static boolean isDownloadsDocument(Uri uri) {         return "com.android.providers.downloads.documents".equals(uri.getAuthority());     }      /**      * @param uri The Uri to check.      * @return Whether the Uri authority is MediaProvider.      * @author paulburke      */     public static boolean isMediaDocument(Uri uri) {         return "com.android.providers.media.documents".equals(uri.getAuthority());     }      /**      * @param uri The Uri to check.      * @return Whether the Uri authority is Old Google Photos.      */     public static boolean isGoogleOldPhotosUri(Uri uri) {         return "com.google.android.apps.photos.content".equals(uri.getAuthority());     }      /**      * @param uri The Uri to check.      * @return Whether the Uri authority is New Google Photos.      */     public static boolean isGoogleNewPhotosUri(Uri uri) {         return "com.google.android.apps.photos.contentprovider".equals(uri.getAuthority());     }      public static String getDataColumn(Context context, Uri uri, String selection,                                        String[] selectionArgs) {          Cursor cursor = null;         final String column = "_data";         final String[] projection = {                 column         };          try {             cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,                     null);             if (cursor != null && cursor.moveToFirst()) {                 final int column_index = cursor.getColumnIndexOrThrow(column);                 return cursor.getString(column_index);             }         } finally {             if (cursor != null)                 cursor.close();         }         return null;     }      public static String getPath(final Context context, final Uri uri) {         // DocumentProvider         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {             if(DocumentsContract.isDocumentUri(context, uri)) {                 // ExternalStorageProvider                 if (isExternalStorageDocument(uri)) {                     final String docId = DocumentsContract.getDocumentId(uri);                     final String[] split = docId.split(":");                     final String type = split[0];                      if ("primary".equalsIgnoreCase(type)) {                         return Environment.getExternalStorageDirectory() + "/" + split[1];                     }                      // TODO handle non-primary volumes                 }                 // DownloadsProvider                 else if (isDownloadsDocument(uri)) {                      final String id = DocumentsContract.getDocumentId(uri);                     final Uri contentUri = ContentUris.withAppendedId(                             Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));                      return getDataColumn(context, contentUri, null, null);                 }                 // MediaProvider                 else if (isMediaDocument(uri)) {                     final String docId = DocumentsContract.getDocumentId(uri);                     final String[] split = docId.split(":");                     final String type = split[0];                      Uri contentUri = null;                     if ("image".equals(type)) {                         contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;                     }                      final String selection = "_id=?";                     final String[] selectionArgs = new String[]{                             split[1]                     };                      return getDataColumn(context, contentUri, selection, selectionArgs);                 }             }             // MediaStore (and general)             else if ("content".equalsIgnoreCase(uri.getScheme())) {                  // Return the remote address                 if (isGoogleOldPhotosUri(uri)) {                     // return http path, then download file.                     return uri.getLastPathSegment();                 }                 else if (isGoogleNewPhotosUri(uri)) {                     if(getDataColumn(context,  uri, null, null) == null) {                         return getDataColumn(context,  Uri.parse(getImageUrlWithAuthority(context,uri)), null, null);                     }else{                         return getDataColumn(context,  uri, null, null);                     }                 }                  return getDataColumn(context, uri, null, null);             }             // File             else if ("file".equalsIgnoreCase(uri.getScheme())) {                 return uri.getPath();             }         }else{             String[] proj = { MediaStore.Images.Media.DATA };             String result = null;              CursorLoader cursorLoader = new CursorLoader(                     context,                     uri, proj, null, null, null);             Cursor cursor = cursorLoader.loadInBackground();              if(cursor != null){                 int column_index =                         cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);                 cursor.moveToFirst();                 result = cursor.getString(column_index);             }              return result;         }           return null;     }      public static File getFile(Context context, Uri uri) {         if (uri != null) {             String path = getPath(context, uri);             if (path != null && isLocal(path)) {                 return new File(path);             }         }         return null;     }      public static String getImageUrlWithAuthority(Context context, Uri uri) {         InputStream is = null;         if (uri.getAuthority() != null) {             try {                 is = context.getContentResolver().openInputStream(uri);                 Bitmap bmp = BitmapFactory.decodeStream(is);                  return writeToTempImageAndGetPathUri(context, bmp).toString();             } catch (FileNotFoundException e) {                 e.printStackTrace();             }finally {                 try {                     is.close();                 } catch (IOException e) {                     e.printStackTrace();                 }             }         }         return null;     }      public static Uri writeToTempImageAndGetPathUri(Context inContext, Bitmap inImage) {         ByteArrayOutputStream bytes = new ByteArrayOutputStream();         inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);         String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);         return Uri.parse(path);     } } 
ImageUtils.java
import android.graphics.Bitmap; import android.util.Base64;  import java.io.ByteArrayOutputStream;  /**  * Created by Wim on 11/14/16.  */ public class ImageUtils {      public static String bitmapToBase64String(Bitmap bmp, int quality) {         ByteArrayOutputStream baos = new ByteArrayOutputStream();         bmp.compress(Bitmap.CompressFormat.JPEG, quality, baos);         byte[] bytes = baos.toByteArray();         return Base64.encodeToString(bytes, Base64.DEFAULT);     }  } 
Sekarang Buka MainActivity.java dan lengkapi dengan aba-aba berikut :
import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.net.Uri; import android.provider.MediaStore; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast;  import com.wimso.android_uploadimage.network.BaseResponse; import com.wimso.android_uploadimage.network.UploadService;  import java.io.File; import java.io.IOException;  import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.RequestBody; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response;  public class MainActivity extends AppCompatActivity implements View.OnClickListener{      private static final int PICK_IMAGE = 1;     private static final int PERMISSION_REQUEST_STORAGE = 2;      private static final String TYPE_1 = "multipart";     private static final String TYPE_2 = "base64";      private ImageView imgThumb;      private Button btnChoose;     private Button btnUpload1;     private Button btnUpload2;      private UploadService uploadService;     private Uri uri;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          imgThumb = (ImageView) findViewById(R.id.img_thumb);         btnChoose = (Button) findViewById(R.id.btn_choose);         btnUpload1 = (Button) findViewById(R.id.btn_upload_1);         btnUpload2 = (Button) findViewById(R.id.btn_upload_2);          btnChoose.setOnClickListener(this);         btnUpload1.setOnClickListener(this);         btnUpload2.setOnClickListener(this);     }      private void choosePhoto() {         if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE)                 != PackageManager.PERMISSION_GRANTED                 && ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)                 != PackageManager.PERMISSION_GRANTED) {              ActivityCompat.requestPermissions(this,                     new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE},                     PERMISSION_REQUEST_STORAGE);          }else{             openGallery();         }     }      public void openGallery() {         Intent intent = new Intent();         intent.setType("image/*");         intent.setAction(Intent.ACTION_GET_CONTENT);         startActivityForResult(Intent.createChooser(intent, "Select Image"), PICK_IMAGE);     }      @Override     public void onClick(View view) {         if(view == btnChoose) {             choosePhoto();         }else if(view == btnUpload1) {             if(uri != null) {                 File file = FileUtils.getFile(this, uri);                 uploadMultipart(file);             }else{                 Toast.makeText(this, "You must choose the image", Toast.LENGTH_SHORT).show();             }         }else if(view == btnUpload2) {             if(uri != null) {                 Bitmap bitmap = null;                 try {                     bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);                 } catch (IOException e) {                     e.printStackTrace();                 }                  String encoded = ImageUtils.bitmapToBase64String(bitmap, 100);                 uploadBase64(encoded);             }else{                 Toast.makeText(this, "You must choose the image", Toast.LENGTH_SHORT).show();             }         }     }     private void uploadMultipart(File file) {         RequestBody photoBody = RequestBody.create(MediaType.parse("image/*"), file);         MultipartBody.Part photoPart = MultipartBody.Part.createFormData("photo",                 file.getName(), photoBody);          RequestBody action = RequestBody.create(MediaType.parse("text/plain"), TYPE_1);          uploadService = new UploadService();         uploadService.uploadPhotoMultipart(action, photoPart, new Callback() {             @Override             public void onResponse(Call call, Response response) {                 BaseResponse baseResponse = (BaseResponse) response.body();                  if(baseResponse != null) {                     Toast.makeText(MainActivity.this, baseResponse.getMessage(), Toast.LENGTH_SHORT).show();                 }             }              @Override             public void onFailure(Call call, Throwable t) {                 t.printStackTrace();             }         });     }      private void uploadBase64(String imgBase64) {         uploadService = new UploadService();         uploadService.uploadPhotoBase64(TYPE_2, imgBase64, new Callback() {             @Override             public void onResponse(Call call, Response response) {                 BaseResponse baseResponse = (BaseResponse) response.body();                  if(baseResponse != null) {                     Toast.makeText(MainActivity.this, baseResponse.getMessage(), Toast.LENGTH_SHORT).show();                 }             }              @Override             public void onFailure(Call call, Throwable t) {                 t.printStackTrace();             }         });     }      @Override     protected void onActivityResult(int requestCode, int resultCode, Intent data) {         super.onActivityResult(requestCode, resultCode, data);         if (requestCode == PICK_IMAGE && resultCode == Activity.RESULT_OK) {             if(data != null) {                 uri = data.getData();                  imgThumb.setImageURI(uri);             }         }     }      @Override     public void onRequestPermissionsResult(int requestCode,                                            String permissions[], int[] grantResults) {         switch (requestCode) {             case PERMISSION_REQUEST_STORAGE: {                 // If request is cancelled, the result arrays are empty.                 if (grantResults.length > 0                         && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                      openGallery();                 }                  return;             }         }     }  } 
Terakhir, tambahkan permission di AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
Build dan jalankan aplikasi kemudian coba upload image dengan 2 metode :



Mari kita lihat image yang sudah ter-upload :


- Image baris pertama merupakan hasil dari upload memakai Base64.
- Image baris kedua merupakan hasil dari upload memakai Multipart.

Dari kedua image tersebut sanggup kita lihat bahwa dengan memakai Base64, ukuran image menjadi jauh lebih besar dibandingkan dengan ukuran orisinil image tersebut. Sedangkan dengan memakai Multipart, ukuran image tidak terlalu besar lengan berkuasa dari ukuran aslinya.

Ukuran orisinil image sekitar 55 kb.


Kesimpulannya yakni silahkan tentukan sendiri metode apa yang diinginkan sesuai dengan kebutuhan masing-masing :D

Source code lengkap sanggup dilihat di https://github.com/andronut/Android-UploadImage

Terima kasih dan agar bermanfaat.
Happy Coding :)

Comments

Popular posts from this blog

Pewarnaan Objek Geometri Di Java 2D

Tugas Komplemen Terakhir

Konsep Oop Encapsulation