Android : Upload Images With Retrofit 2.3.0 (Beginner)

in #utopian-io7 years ago (edited)

Screenshot_2018-01-08-17-52-07-237_com.steemit.daniel.retrofitimageupload.png

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:

  1. Retrofit implementation "com.squareup.retrofit2:retrofit:2.3.0"
  2. OkHttp implementation "com.squareup.okhttp3:logging-interceptor:3.9.0"
  3. Butterknife implementation "com.jakewharton:butterknife:8.8.1"
  4. 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

image.png

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
image.png

code diatas berfungsi untuk membuka galery pada device android, dan memilih foto yang akan di upload.

image.png
code diatas berfungsi untuk memproses file yang telah di pilih, kemudian menampilkannya pada Image View pada layout.
image.png
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
image.png

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

Sort:  

Your contribution cannot be approved yet. See the Utopian Rules. Please edit your contribution to reapply for approval.

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.