Cara Menggunakan Retrofit dalam Mengambil Data dari REST

Rehan Adi Satrya
8 min readApr 12, 2021

--

Retrofit

Halo! Hari ini kita akan membahas bagaimana cara mengambil data dari API untuk digunakan pada aplikasi Android menggunakan Retrofit. API yang akan kita gunakan adalah Sports API yang dapat kamu akses pada link berikut.

Pada link tersebut, kalian perlu membuat akun guna mendapat API_KEY masing-masing. API_KEY bersifat unik untuk setiap akun dan akan digunakan untuk fetching data dari API.

API Key dapat kamu retrieve dari link ini setelah login.
Cara kerja Retrofit

Retrofit adalah sebuah kelas yang dapat mengubah antarmuka API menjadi object yang callable. Untuk menggunakan Retrofit, pastikan kalian sudah memasang semua dependency yang dibutuhkan pada Gradle pada level app.

// retrofit, gson
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.squareup.retrofit2:retrofit:2.0.2'
implementation 'com.squareup.retrofit2:converter-gson:2.0.2'

//recyclerview
implementation 'com.android.support:recyclerview-v7:24.2.0'

Setelah mengedit file gradle, jangan lupa untuk melakukan sinkronisasi ulang dengan mengeklik “Sync now”.

Perlu diingat bahwa retrofit mengambil data pada API menggunakan INTERNET sehingga kita perlu memastikan aplikasi yang kita buat dapat mengakses internet pada perangkat. Tambahkan izin menggunakan internet pada AndroidManifest.xml dengan potongan kode berikut:

<manifest ...>
.
.
.
<uses-permission android:name="android.permission.INTERNET"/>
.
.
.
<application ...>.
.
.
</aplication>
.
.
.
</manifest>

1-Menyiapkan Activity

Kita akan membuat activity sederhana yang terdiri dari recycler view yang nantinya akan berisi dengan berita yang kita ambil dari API. Activity sebaiknya Anda buat sesuai kreativitas masing-masing. Namun, ini adalah contoh implementasi activity dan layout sederhana yang dapat Anda gunakan:

MainActivity.java

public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerNews;
private List<News> newsList;
private final String country = "id";
private final String category = "sports";
private final String API_KEY = <GUNAKAN KEY KALIAN>;
private MainAdapter adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

inject_data(country, category, API_KEY);

}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerNews"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteX="300dp"
tools:layout_editor_absoluteY="200dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

2-Membuat RetrofitClient

RetrofitClient adalah kelas yang akan dipanggil untuk memanggil API dengan menerapkan factory pattern. Tujuan dari penerapan pattern tersebut adalah karena penggunaan retrofit hanya memiliki satu tujuan dan memiliki satu cara penggunaan sehingga jika suatu saat kita memerlukan modifikasi (contoh: BASE_URL) maka kita tidak perlu mengganti semua pemanggilan Retrofit satu persatu, namun hanya perlu mengganti pada kelas ini.

RetrofitClient.java

public class RetrofitClient {private static final String BASE_URL = "https://newsapi.org/v2/";
private static RetrofitClient mInstance;
private Retrofit retrofit;

private RetrofitClient(){
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}

public static synchronized RetrofitClient getInstance(){
if(mInstance == null){
mInstance = new RetrofitClient();
}
return mInstance;
}
public Api getApi() {
return retrofit.create(Api.class);
}
}

3-Membuat Interface API

Api.java adalah interface yang memanggil metode GET dan mengirimkan querynya kepada host api yang berkaitan. Kita dapat mengimplementasikan interface tersebut menggunakan kode sebagai berikut:

Api.java

public interface Api {
@GET("top-headlines")
Call<DefaultResponse> getAllNews(
@Query("country") String country,
@Query("category") String category,
@Query("apiKey") String apiKey
);
}

Note: jika diminta mengimport method GET, ambil dari Retrofit.

4-Membuat Model Response

Response adalah kelas yang akan menampung response dari API. Pada postman, kita dapat melihat bahwa API memberikan respon sebagai berikut:

Respon pada Postman. Sumber: Dokumentasi Pribadi

Sehingga kita perlu menampung respon tersebut pada postman sesuai yang ada pada api. Model Response dapat diimplementasikan sebagai berikut:

DefaultResponse.java

public class DefaultResponse {
@SerializedName("status")
private String status;
@SerializedName("totalResults")
private int totalResults;
@SerializedName("articles")
private List<News> articles;

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public int getTotalResults() {
return totalResults;
}

public void setTotalResults(int totalResults) {
this.totalResults = totalResults;
}

public List<News> getArticles() {
return articles;
}

public void setArticles(List<News> articles) {
this.articles = articles;
}
}

5-Membuat Model News

Seperti yang kita lihat pada screenshot Postman di atas, respon articles merupakan list yang berisi data berita yang tersedia. Untuk menampung list tersebut, kita perlu membuat model news yang dapat menyimpan seluruh informasi berita yang ada pada API. Kita dapat mengimplementasikan model News seperti berikut ini:

News.java

public class News{
private String author;
private String title;
private String description;
private String url;

public News(String author,
String title,
String description,
String url) {
this.author = author;
this.title = title;
this.description = description;
this.url = url;
}

public String getAuthor() {
return author;
}

public void setAuthor(String author) {
this.author = author;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}
}

6-Membuat Adapter

Adapter adalah kelas yang bertanggung jawab untuk memasang potongan data pada holder (object yang meng-contain data pada recycler view).

public class MainAdapter extends RecyclerView.Adapter<MainAdapter.MainViewHolder> {
private List<News> newsList;

public MainAdapter(List<News> newsList){
this.newsList = newsList;
}

@Override
public MainViewHolder onCreateViewHolder(
ViewGroup parent,
int viewType
){
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.news_card_view, parent, false);
return new MainViewHolder(view);
}

@Override
public void onBindViewHolder(
MainViewHolder holder,
int position) {
String title = newsList.get(position).getTitle();
String author = newsList.get(position).getAuthor();
String description = newsList.get(position).getDescription();
holder.txtNewsTitle.setText(title);
holder.txtNewsAuthor.setText(author);
holder.txtNewsDesc.setText(description);
}

@Override
public int getItemCount() {
return (newsList != null) ? newsList.size() : 0;
}

public class MainViewHolder extends RecyclerView.ViewHolder{
private TextView txtNewsDesc, txtNewsTitle, txtNewsAuthor;

public MainViewHolder(View itemView){
super(itemView);
txtNewsTitle = (TextView) itemView
.findViewById(R.id.txt_news_title);
txtNewsAuthor = (TextView) itemView
.findViewById(R.id.txt_news_author);
txtNewsDesc = (TextView) itemView
.findViewById(R.id.txt_news_desc);
}
}

}

news_card_view.xml

<?xml version="1.0" encoding="utf-8"?>

<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="6dp"
card_view:cardElevation="3dp"
card_view:cardUseCompatPadding="true">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:orientation="vertical"
android:padding="5dp">

<TextView
android:id="@+id/txt_news_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Ronaldo Kembali ke MU! Tapi boong"/>

<TextView
android:id="@+id/txt_news_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Author: Tribun Barat"/>

<TextView
android:id="@+id/txt_news_desc"
android:layout_width="match_parent"
android:layout_height="52dp"
android:gravity="center"
android:maxLength="90"/>

</LinearLayout>

</androidx.cardview.widget.CardView>

7-Memasang Retrofit pada Activity

Perhatikan bahwa fungsi inject_data() belum kita implementasikan. Fungsi inject_data() berfungsi untuk mengisi list berita yang akan kita taruh pada recycler view nantinya. Implementasi dari inject_data() dapat dilihat sebagai berikut:

private void inject_data(String country, String category, String API_key) {

newsList = new ArrayList<>();

Call<DefaultResponse> call = RetrofitClient
.getInstance()
.getApi()
.getAllNews(country, category, API_key);

call.enqueue(new Callback<DefaultResponse>(){


@Override
public void onResponse(Call<DefaultResponse> call, Response<DefaultResponse> response) {
List<News> listOfNews =
response.body().getArticles();
for (int i = 0; i < listOfNews.size(); i++){
newsList.add(new News(listOfNews.get(i).getAuthor(), listOfNews.get(i).getTitle(), listOfNews.get(i).getDescription(), listOfNews.get(i).getUrl()));
}hookingAdapter(newsList);

}

@Override
public void onFailure(Call<DefaultResponse> call, Throwable t) {

}
});
}

8-Memasang Adapter

Ketika list sudah lengkap, maka kita perlu memasang isi list tersebut pada sebuah adapter. Konsep dari adapter ini adalah mengambil data yang dibutuhkan, kemudian menaruh potongan data tersebut pada holder (tempat potongan data ditampilkan pada recycler view).

private void hookingAdapter(List<News> listBerita){recyclerNews = (RecyclerView) findViewById(R.id.recyclerNews);
adapter = new MainAdapter(listBerita);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(MainActivity.this);
recyclerNews.setLayoutManager(layoutManager);
recyclerNews.setAdapter(adapter);
recyclerNews.addOnItemTouchListener(
new RecyclerItemClickListener(MainActivity.this, recyclerNews ,new RecyclerItemClickListener.OnItemClickListener() {
@Override public void onItemClick(View view, int position) {
News news = newsList.get(position);//Manfaatkan data dari news sesuai kebutuhan}

@Override public void onLongItemClick(View view, int position) {
// Bebas dimodifikasi
}
})
);
}

untuk mengambil item pada posisi tertentu, jangan lupa membuat click listener untuk Recycler View yang menginherit kelas OnItemTouchListener dari kelas RecyclerView. Listener dapat menggunakan kelas berikut:

RecyclerItemClickListener.java

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener
{
public static interface OnItemClickListener
{
public void onItemClick(View view, int position);
public void onItemLongClick(View view, int position);
}

private OnItemClickListener mListener;
private GestureDetector mGestureDetector;

public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener)
{
mListener = listener;

mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener()
{
@Override
public boolean onSingleTapUp(MotionEvent e)
{
return true;
}

@Override
public void onLongPress(MotionEvent e)
{
View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());

if(childView != null && mListener != null)
{
mListener.onItemLongClick(childView, recyclerView.getChildPosition(childView));
}
}
});
}

@Override
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e)
{
View childView = view.findChildViewUnder(e.getX(), e.getY());

if(childView != null && mListener != null && mGestureDetector.onTouchEvent(e))
{
mListener.onItemClick(childView, view.getChildPosition(childView));
}

return false;
}

@Override
public void onTouchEvent(RecyclerView view, MotionEvent motionEvent){}

@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

}
}

Pada tahap ini, aplikasi sudah dapat dibuild dan dijalankan. Aplikasi akan menampilkan list yang berisi berita dari API.

9-Menggunakan Extra

Sekarang, kita sudah memiliki data dari news yang kita klik pada list. Lalu, apa yang dapat kita lakukan selanjutnya? Banyak sekali! Kita bisa mempergunakan list tersebut untuk membuka berita menggunakan web view, atau bahkan dibuka pada activity buatan kita sendiri. Namun, jika data tersebut ingin digunakan pada activity lain, maka kita perlu menggunakan extra.

Cara kerja extra adalah menyimpan data sebagai tipe data extra pada intent dan “dilabeli” dengan label tertentu. Namun, extra hanya dapat menyimpan tipe bentukan data primitif seperti String, integer, dan lain sebagainya. Sehingga, data yang akan kita kirimkan harus satu persatu kita ekstraksi.

Contoh penggunaan extra adalah sebagai berikut:

//Menginisialisasikan intent yang ingin digunakan
Intent i = new Intent(MainActivity.this, <Context Penerima data>);
//Melabeli data yang akan dikirim
i.putExtra("judul_berita", news.getTitle());
i.putExtra("author_berita", news.getAuthor());
//Memulai activity baru
startActivity(i);

Kemudian, pada activity baru, kita dapat mengakses data tersebut dengan cara:

String judul = getIntent().getStringExtra("judul_berita");
String author = getIntent().getStringExtra("author_berita");

10-Konsep Parcel

Sering kali model yang kita miliki menyimpan suatu data sehingga jika kita perlu mengirimkan sebuah data model, maka akan terjadi pemanggilan extra yang berulang. Semakin kompleks model tersebut, semakin besar peluang kesalahan terjadi. Maka dari itu, kita dapat menggunakan konsep parcel untuk mengirim data sekaligus. Parcel adalah methode yang mengubah model menjadi serial sehingga dapat dikirim menggunakan extra.

Pada kasus ini, model News lah yang akan kita jadikan parcel. Caranya adalah dengan memodifikasi file News.java menjadi seperti berikut ini:

public class News implements Parcelable{
private String author;
private String title;
private String description;
private String url;

//CONSTRUCTOR, GETTER, SETTER
...
@Override
public int describeContents() {
return 0;
}
public static Creator<News> getCREATOR() {
return CREATOR;
}

protected News(Parcel in) {
author = in.readString();
title = in.readString();
description = in.readString();
url = in.readString();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(author);
dest.writeString(title);
dest.writeString(description);
dest.writeString(url);
}

public static final Creator<News> CREATOR = new Creator<News>() {
@Override
public News createFromParcel(Parcel in) {
return new News(in);
}

@Override
public News[] newArray(int size) {
return new News[size];
}
};
}

Setelah News sudah mengimplementasikan parcel, kita dapat langsung mengirim data hanya dengan cara

i.putExtra("newsParcel", news);

Dan mengambil datanya kembali dengan cara:

News news = getIntent().getParcelableExtra("newsParcel");

Konsep parcel ini tidak wajib kamu gunakan jika dirasa sudah nyaman dengan metode awal. Namun, tidak ada salahnya belajar hal baru bukan?

Selamat! Kamu sudah dapat mengambil data dari API dan memanfaatkan data tersebut pada recycler view. Sekian untuk tutorial kali ini. Adios!

Mau kenal lebih jauh? Boleh juga mampir ke LinkedIn saya atau Github saya.

--

--