Halo steemians, pada kesempatan ini saya akan menjelaskan tentang upload gambar menggunakan retrofit 2.3.0. Ini adalah tutorial dengan level beginner.
Retrofit adalah sebuah library android yang bertujuan untuk memudahkan programmer dalam melakukan REST client android yang dibuat oleh square, sehingga programmer tidak perlu lagi mengubah API endpoint menjadi sebuah Java interface API service secara manual.
Perhatian!!
Semua percobaan dalam artikel ini telah teruji dan berjalan dengan baik pada platform device Android marshmallow dan kitkat. Untuk device lain belum pernah diuji, dan mungkin beberapa fungsi tidak berjalan dengan baik. Terima kasih.
Oke langsung saja
Library yang perlu kita siapkan ialah:
- Retrofit
implementation "com.squareup.retrofit2:retrofit:2.3.0"
- OkHttp
implementation "com.squareup.okhttp3:logging-interceptor:3.9.0"
- Butterknife
implementation "com.jakewharton:butterknife:8.8.1"
- Design Support
implementation "com.android.support:design:26.1.0"
untuk code
depedencies nya bisa dilihat dibawah ini:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.android.support:design:26.1.0'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}
Tahap Pertama Membuat Layout
Untuk file activity_main.xlm dapat dilihat dibawah ini, kalian juga boleh mengubahnya sesuai dengan keinginan kalian.
<?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:id="@+id/parent_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
android:background="@color/colorSemiWhite">
< android.support.v7.widget.AppCompatImageView
android:id="@+id/img_thumb"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:scaleType="centerCrop"
android:src="@mipmap/ic_launcher" />
< RelativeLayout
android:id="@+id/rl_tambah_gambar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/img_thumb"
android:layout_marginTop="11dp">
<android.support.v7.widget.AppCompatImageView
android:id="@+id/img_add"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginEnd="14dp"
android:layout_marginLeft="28dp"
android:layout_marginRight="14dp"
android:layout_marginStart="28dp"
android:src="@drawable/ic_add"
android:background="@drawable/shape_border"/>
<android.support.v7.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/img_add"
android:layout_toRightOf="@+id/img_add"
android:textColor="@android:color/black"
android:text="Tambah Gambar"
android:textSize="16sp" />
</ RelativeLayout>
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_upload"
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/rl_tambah_gambar"
android:text="Upload" />
</RelativeLayout>
Tahap Kedua Pembuatan Class Java
Class RetrofitClientUtil.java
Class ini berfungsi sebagai inisialisasi library Retrofit, dan juga sebagai fungsi client sehingga setiap class yang membutuhkan retrofit tinggal memanggil fungsi ini saja.
untuk code
nya bisa dilihat dibawah ini:
package com.steemit.daniel.retrofitimageupload.utils;
import com.steemit.daniel.retrofitimageupload.Config;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitClientUtil {
private static Retrofit getRetrofitInstance(){
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.retryOnConnectionFailure(false)
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.addInterceptor(loggingInterceptor)
.build();
return new Retrofit.Builder()
.baseUrl(Config.URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
}
public static RequestInterface getRequestInterface(){
return getRetrofitInstance().create(RequestInterface.class);
}
}
Disini kita menggunakan GsonConverterFactory yang bertujuan untuk mengconvert data JSON yang didapat dari web service ke dalam Java Object.
Class RequestInterface.java
Pada class ini kita membuat sebuah interface API service yang berfungsi untuk memetakan path endpoint pada web service.
package com.steemit.daniel.retrofitimageupload.utils;
import com.steemit.daniel.retrofitimageupload.response.UploadResponse;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
/**
* Created by daniel on 1/6/2018.
*/
public interface RequestInterface {
@Multipart
@POST("upload")
Call<UploadResponse> postImage(@Part MultipartBody.Part image, @Part("name") RequestBody name);
}
Anotasi Multipart
berfungsi untuk menyatakan bahwa seluruh request pada endpoint tersebut sebagai multipart, sedangkan POST
bertujuan untuk menyatakan bahwa kita melakukan POST request ke url endpoint tersebut.
Sedangkan kelas MultipartBody.Part memungkinkan kita untuk mengirim nama file sebenarnya selain data file biner kedalam server.
Class UploadResponse.java
package com.steemit.daniel.retrofitimageupload.response;
/**
* Created by daniel on 1/6/2018.
*/
public class UploadResponse {
private int code;
private String message;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Class ini berfungsi sebagai model penampung dari response yang diberikan server.
Class MainActivity.java
Class ini terdiri dari beberapa fungsi
code
diatas berfungsi untuk membuka galery pada device android, dan memilih foto yang akan di upload.
code
diatas berfungsi untuk memproses file yang telah di pilih, kemudian menampilkannya pada Image View pada layout.
code
diatas berfungsi untuk mengupload foto yang telah di pilih dengan Retrofit kemudian akan ada notifikasi dengan snack bar jika file yang di upload berhasil.
Untuk code
selengkapnya mari kita lihat di bawah ini
package com.steemit.daniel.retrofitimageupload.activity;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatButton;
import android.support.v7.widget.AppCompatImageView;
import android.view.View;
import android.widget.RelativeLayout;
import com.steemit.daniel.retrofitimageupload.R;
import com.steemit.daniel.retrofitimageupload.response.UploadResponse;
import com.steemit.daniel.retrofitimageupload.utils.RequestInterface;
import com.steemit.daniel.retrofitimageupload.utils.RetrofitClientUtil;
import java.io.File;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
private static final int PICK_IMAGE = 100;
private static final int PERMISSION_STORAGE = 2;
@BindView(R.id.parent_layout)
protected RelativeLayout mParent;
@BindView(R.id.img_thumb)
protected AppCompatImageView mImageThumb;
@BindView(R.id.rl_tambah_gambar)
protected RelativeLayout mAddImage;
@BindView(R.id.btn_upload)
protected AppCompatButton mBtnUpload;
private Unbinder mUnbinder;
private String selectImagePath;
private Snackbar mSnackbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mUnbinder = ButterKnife.bind(this);
mAddImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSION_STORAGE);
}else{
openImage();
}
}
});
mBtnUpload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
uploadImage();
}
});
}
private void openImage() {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Image"), PICK_IMAGE);
}
private void uploadImage() {
File file = new File(selectImagePath);
RequestBody reqFile = RequestBody.create(MediaType.parse("image"), file);
MultipartBody.Part imageBody = MultipartBody.Part.createFormData("image", file.getName(), reqFile);
RequestBody ImageName = RequestBody.create(MediaType.parse("text/plain"), file.getName());
RequestInterface request = RetrofitClientUtil.getRequestInterface();
Call<UploadResponse> responseCall = request.postImage(imageBody, ImageName);
responseCall.enqueue(new Callback<UploadResponse>() {
@Override
public void onResponse(Call<UploadResponse> call, Response<UploadResponse> response) {
if (response.isSuccessful()) {
UploadResponse resp = response.body();
if (resp.getCode() == 200) {
mSnackbar = Snackbar.make(mParent, resp.getMessage(), Snackbar.LENGTH_LONG);
View views = mSnackbar.getView();
views.setBackgroundColor(ContextCompat.getColor(MainActivity.this, R.color.colorPrimary));
mSnackbar.show();
}
}
}
@Override
public void onFailure(Call<UploadResponse> call, Throwable t) {
mSnackbar = Snackbar.make(mParent, t.getLocalizedMessage(), Snackbar.LENGTH_LONG);
View views = mSnackbar.getView();
views.setBackgroundColor(ContextCompat.getColor(MainActivity.this, R.color.colorWarmGrey));
mSnackbar.show();
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE && resultCode == Activity.RESULT_OK) {
Uri selectImageUri = data.getData();
selectImagePath = getRealPathFromURI(selectImageUri);
decodeImage(selectImagePath);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSION_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openImage();
}
return;
}
}
}
private String getRealPathFromURI(Uri selectImageUri) {
Cursor cursor = getContentResolver().query(selectImageUri, null, null, null, null);
if (cursor == null) {
return selectImageUri.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
return cursor.getString(idx);
}
}
private void decodeImage(String selectImagePath) {
int targetW = mImageThumb.getWidth();
int targetH = mImageThumb.getHeight();
final BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(selectImagePath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
int scaleFactor = Math.min(photoW / targetW, photoH / targetH);
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
Bitmap bitmap = BitmapFactory.decodeFile(selectImagePath, bmOptions);
if (bitmap != null) {
mImageThumb.setImageBitmap(bitmap);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mUnbinder.unbind();
}
}
Tahapan terakhir kita bisa menambahkan code permission berikut pada AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
Oke, kita sudah selesai silahkan jalan kan aplikasi yang kita bangun pada device android anda. Anda juga dapat bermain-main dengan kodenya dan mengembangkannya menjadi lebih baik lagi. Saya juga berharap kritik yang membangun dari para pembaca sekalian. Terimakasih telah membaca.
GitHub
Untuk Source code lengkap nya bisa dilihat di https://github.com/danielniklaus/Retrofit-Image-Upload
Screenshot
Refrence
https://www.learn2crack.com/2017/08/upload-image-using-retrofit.html
http://square.github.io/retrofit/
Posted on Utopian.io - Rewarding Open Source Contributors
Your contribution cannot be approved yet. See the Utopian Rules. Please edit your contribution to reapply for approval.
You may edit your post here, as shown below:
You can contact us on Discord.
[utopian-moderator]
oke, I've edited my post. thank you :)
Your contribution cannot be approved because it does not follow the Utopian Rules.
You can contact us on Discord.
[utopian-moderator]