Cara Membuat Timeline Layout di Android

Yudi Setiawan 21 Februari 2017

Cara Membuat Timeline Layout di Android

Pengantar

Tutorial ini juga merupakan bagian atau ada hubungannya dengan tutorial saya sebelumnya yang berjudul Cara Membuat RecyclerView dengan Multiple View Type di Android. Timeline Layout merupakan salah satu bentuk pemanfaatan dari widget RecyclerView yang ada. Coba perhatikan Timeline Layout berikut. Contoh Timeline Layout

Timeline Layout bentuknya itu bisa berbagai macam dan semuanya itu tergantung dari datanya. Contoh seperti pada gambar diatas itu merupakan data yang menampilkan rute penerbangan. "Terus kapan timeline layout itu dipakai?" Kalau menurut penulis, sepertinya timeline layout cocok untuk menampilkan data yang berhubungan dengan data waktu, lokasi, dan lainnya seperti, menampilkan jam tayang jadwal bioskop, rute penerbangan pesawat, rute keberangkatan kereta api, jadwal dan rute keberangkatan bus, dan lain-lainnya. Oya, sebelum kita masuk ke projeknya mari kita analisa terlebih dahulu gambar diatas, kira-kira menurut para pembaca komponen(widget) apa aja yang ada pada gambar? Kalau menurut penulis, kira-kira seperti inilah hasil analisanya.

  1. Ada menggunakan TabLayout
  2. Ada beberapa TextView dengan size yang berbeda-beda dan ImageView
  3. Kemudian, yang bulat kecil di garis vertical itu sepertinya widget View yang diberi background custom drawable dengan solid darker gray
  4. Selanjutnya, untuk kotak yang garis putus-putus itu sepertinya hampir sama penggunaannya seperti poin nomor 3 hanya saja ini menggunakan TextView yang menggunakan background custom drawable dengan atribut dashGap dan corners radius
  5. Selanjutnya, ada apa lagi ya??? Oya, ada satu komponen penting pada gambar diatas yaitu, RecyclerView sebagai container.

Persiapan

Sebelum kita masuk, ke pembuatan projeknya ada beberapa hal yang perlu Anda persiapkan pada tutorial ini yaitu sebagai berikut.

  1. Pastikan Anda sudah memasang aplikasi Android Studio versi latest-nya di website canary android studio
  2. Pastikan juga Anda dalam kondisi terhubung ke internet karena, ada beberapa library dependency yang akan digunakan dalam pembuatan projek.

Pembuatan Projek

Pada tutorial ini, kita akan membuat aplikasi jadwal kereta api dengan sumber API-nya dari http://ibacor.com/. Bagi para pembaca yang belum mempunyai API key-nya saya sarankan daftar sekarang juga di website tersebut karena, pada tutorial ini kita wajib menggunakan API key. Pada tutorial ini, ada beberapa library yang saya pakai yaitu:

  1. EventBus GreenRobot
    Pada projek ini, EventBus saya pakai untuk komunikasi data antar class. Karena, pada tutorial ini kita ada mengirimkan data POJO jadi, penggunaan EventBus menurut penulis cukup memudahkan proses pengirimannya.
  2. Retrofit2
    Kalau yang ini penulis menggunakan Retrofit2 sebagai salah satu teknik komunikasi ke server API untuk mengambil datanya. Sebenarnya, selain Retrofit2 Anda juga bisa memakai Volley namun, saya lebih suka dengan Retrofit2.

Untuk langkah pertama, silakan Anda buat projek baru di Android Studio dengan nama Codepolitan-JadwalKeretaApi selanjutnya, setting file build.gradle(Module:app) dan tambahkan beberapa library dependency berikut kedalam projek.

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.1.0'
    compile 'com.android.support.constraint:constraint-layout:1.0.0-beta4'
    compile 'com.google.code.gson:gson:2.8.0'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:retrofit-converters:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    compile 'org.greenrobot:eventbus:3.0.0'
    compile 'com.android.support:design:25.1.0'
    testCompile 'junit:junit:4.12'
}

Colors.xml

Buka file Colors.xml dan ubah dengan source code berikut.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#009688</color>
    <color name="colorPrimaryDark">#00796B</color>
    <color name="colorAccent">#FF4081</color>
</resources>

Pembuatan File POJO

Nah, untuk pembuatan file POJO-nya saya rasa nggak mungkin saya jelaskan semuanya disini. Anda bisa membuatnya sendiri dari website www.jsonschema2pojo.org/ dan Anda bisa menggunakan aplikasi Postman untuk menangkap format response-nya dari server.

Pembuatan File API Service

Dalam penggunaan Retrofit, kita memerlukan sebuah file interface baru dalam penggunaannya. Di kelas interface tersebut akan kita deklarasikan baseApiUrl, Api Key dan path endpoint yang akan kita pakai pada tutorial ini. Silakan Anda buat file interface baru dengan nama KeretaApiService.java dan isi dengan source code berikut.

package ysn.codepolitan_jadwalkeretaapi.api;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
import retrofit2.http.Query;
import ysn.codepolitan_jadwalkeretaapi.model.data_jadwal.DataJadwal;
import ysn.codepolitan_jadwalkeretaapi.model.data_stasiun.DataStasiun;

/**
 * Created by root on 15/02/17.
 */

public interface KeretaApiService {

    public final String baseApiUrl = "http://ibacor.com/";
    public final String apiKey = "<Your API Key>";

    @GET("api/kereta-api")
    Call<DataStasiun> getDataStasiun(@Query("k") String apiKey);

    @GET("api/kereta-api")
    Call<ResponseBody> getDataJadwal(
            @Query("tanggal") String tanggal,
            @Query("asal") String asal,
            @Query("tujuan") String tujuan,
            @Query("k") String apiKey
    );
}

Pembuatan File Pendukung

Pada tutorial ini, ada 3 file pendukung yang akan kita pakai pada bagian drawable yaitu, background_button.xml, background_circle_berangkat.xml, dan background_circle_datang.xml. Dan berikut source code dari setiap file tersebut.

background_button.xml

<?xml version="1.0" encoding="utf-8"?>
<inset
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <selector>
        <item
            android:state_pressed="true"
            >
            <shape
                android:shape="rectangle"
                >
                <corners
                    android:radius="5dp"
                    />
                <solid
                    android:color="@android:color/darker_gray"
                    />
            </shape>
        </item>
        <item>
            <shape
                android:shape="rectangle"
                >
                <corners
                    android:radius="5dp"
                    />
                <solid
                    android:color="@android:color/transparent"
                    />
            </shape>
        </item>
    </selector>
</inset>

background_circle_berangkat.xml

<?xml version="1.0" encoding="utf-8"?>
<inset
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <selector>
        <item>
            <shape
                android:shape="oval"
                >
                <solid
                    android:color="@color/colorPrimary"
                    />
            </shape>
        </item>
    </selector>
</inset>

background_circle_datang.xml

<?xml version="1.0" encoding="utf-8"?>
<inset
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <selector>
        <item>
            <shape
                android:shape="oval"
                >
                <solid
                    android:color="@color/colorAccent"
                    />
            </shape>
        </item>
    </selector>
</inset>

Splash Screen

Splash screen kita gunakan di awal aplikasi karena, untuk menampilkan data jadwal kereta api kita membutuhkan data awal dari server. Silakan buka file activity_main.xml dan ubah menjadi source code berikut.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:background="@color/colorPrimary"
    tools:context="ysn.codepolitan_jadwalkeretaapi.activity.MainActivity"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/text_view_app_name_activity_main"
        android:text="Jadwal Kereta Api"
        android:textSize="30sp"
        android:textColor="@android:color/white"
        android:layout_centerInParent="true"
        />

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/progress_bar_activity_main"
        android:layout_centerInParent="true"
        android:layout_below="@+id/text_view_app_name_activity_main"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:indeterminate="true"
        />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button_try_again_activity_main"
        android:layout_below="@+id/text_view_app_name_activity_main"
        android:layout_centerInParent="true"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:text="Try Again"
        android:visibility="gone"
        />

</RelativeLayout>

Selanjutnya, ubah juga source code pada file MainActivity.java menjadi seperti berikut.

package ysn.codepolitan_jadwalkeretaapi.activity;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

import org.greenrobot.eventbus.EventBus;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import ysn.codepolitan_jadwalkeretaapi.R;
import ysn.codepolitan_jadwalkeretaapi.api.KeretaApiService;
import ysn.codepolitan_jadwalkeretaapi.model.data_stasiun.DataStasiun;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivityTAG";
    private static String data;
    private Retrofit retrofit;
    private Button buttonTryAgain;
    private ProgressBar progressBar;

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

    private void loadComponent() {
        progressBar = (ProgressBar) findViewById(R.id.progress_bar_activity_main);
        buttonTryAgain = (Button) findViewById(R.id.button_try_again_activity_main);
        buttonTryAgain.setOnClickListener(this);
    }

    private void loadData() {
        KeretaApiService keretaApiService = retrofit.create(KeretaApiService.class);
        final Call<DataStasiun> resultCallDataStasiun = keretaApiService.getDataStasiun(keretaApiService.apiKey);
        resultCallDataStasiun.enqueue(new Callback<DataStasiun>() {
            @Override
            public void onResponse(Call<DataStasiun> call, Response<DataStasiun> response) {
                Intent intent = new Intent(MainActivity.this, HomeActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
                EventBus.getDefault().postSticky(response.body());
                startActivity(intent);
            }

            @Override
            public void onFailure(Call<DataStasiun> call, Throwable t) {
                t.printStackTrace();
                Toast.makeText(MainActivity.this, "Koneksi timeout", Toast.LENGTH_LONG)
                        .show();
                progressBar.setVisibility(View.GONE);
                buttonTryAgain.setVisibility(View.VISIBLE);
            }
        });
    }

    private void initializeRetrofit() {
        retrofit = new Retrofit.Builder()
                .baseUrl(KeretaApiService.baseApiUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

    }

    @Override
    public void onClick(View view) {
        if (view == buttonTryAgain) {
            progressBar.setVisibility(View.VISIBLE);
            buttonTryAgain.setVisibility(View.GONE);
            loadData();
        }
    }

}

Penjelasan singkat untuk logic dari file diatas ialah bahwa ketika aplikasi pertama kali dibuka maka, aplikasi akan melakukan request ke server untuk mengambil data awal yang kita perlukan untuk mencari data jadwal kereta api. Pada source code diatas bisa Anda lihat bahwa apabila request-nya sukses maka, kita akan menuju ke HomeActivity dan mengirimkan data POJO-nya lewat EventBus.

Form Cari Jadwal Kereta Api

Selanjutnya, silakan Anda buat activity baru dengan nama HomeActivity. Dan isi source code berikut pada file layout-nya.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:id="@+id/activity_home"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="ysn.codepolitan_jadwalkeretaapi.activity.HomeActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar_activity_home"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Cek Jadwal Kereta Api"
            android:textColor="@android:color/white"
            android:textSize="18sp" />

    </android.support.v7.widget.Toolbar>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        >

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            >

            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/edit_text_kota_asal_activity_home"
                android:hint="Kota Asal"
                android:focusable="false"
                />

        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            >

            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/edit_text_kota_tujuan_activity_home"
                android:hint="Kota Tujuan"
                android:focusable="false"
                />

        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            >

            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/edit_text_tanggal_keberangkatan_activity_home"
                android:focusable="false"
                android:hint="Tanggal Keberangkatan"
                />

        </android.support.design.widget.TextInputLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            >

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/button_cek_jadwal_activity_home"
                android:text="Cek Jadwal"
                android:textColor="@color/colorPrimary"
                android:layout_centerHorizontal="true"
                android:background="@drawable/background_button"
                android:minWidth="0dp"
                android:minHeight="0dp"
                android:paddingTop="13dp"
                android:paddingRight="13dp"
                android:paddingBottom="13dp"
                android:paddingLeft="13dp"
                />

        </RelativeLayout>

    </LinearLayout>

</LinearLayout>

Dan isi juga source code berikut pada file HomeActivity.java.

package ysn.codepolitan_jadwalkeretaapi.activity;

import android.app.DatePickerDialog;
import android.app.ProgressDialog;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Toast;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.json.JSONObject;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import ysn.codepolitan_jadwalkeretaapi.R;
import ysn.codepolitan_jadwalkeretaapi.api.KeretaApiService;
import ysn.codepolitan_jadwalkeretaapi.model.data_jadwal.DataJadwal;
import ysn.codepolitan_jadwalkeretaapi.model.data_jadwal.Kereta;
import ysn.codepolitan_jadwalkeretaapi.model.data_stasiun.DataStasiun;
import ysn.codepolitan_jadwalkeretaapi.model.data_stasiun.Stasiun;
import ysn.codepolitan_jadwalkeretaapi.model.data_stasiun.Tanggal;

public class HomeActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "HomeActivityTAG";
    private DataStasiun dataStasiun;
    private Retrofit retrofit;
    private EditText editTextAsalKeberangkatan;
    private EditText editTextTujuanKeberangkatan;
    private EditText editTextTanggalKeberangkatan;
    private Button buttonCekJadwalKeberangkatan;

    private List<String> listNamaKotaStasiun;
    private List<String> listValueNamaKotaStasiun;
    private List<String> listNamaKotaBesar;
    private String valueKotaAsal;
    private String valueKotaTujuan;
    private String valueTanggal;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        EventBus.getDefault().register(this);
        initializeRetrofit();
        loadComponent();
        loadData();
    }

    private void initializeRetrofit() {
        retrofit = new Retrofit.Builder()
                .baseUrl(KeretaApiService.baseApiUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    private void loadComponent() {
        editTextAsalKeberangkatan = (EditText) findViewById(R.id.edit_text_kota_asal_activity_home);
        editTextTujuanKeberangkatan = (EditText) findViewById(R.id.edit_text_kota_tujuan_activity_home);
        editTextTanggalKeberangkatan = (EditText) findViewById(R.id.edit_text_tanggal_keberangkatan_activity_home);
        buttonCekJadwalKeberangkatan = (Button) findViewById(R.id.button_cek_jadwal_activity_home);

        editTextAsalKeberangkatan.setOnClickListener(this);
        editTextTujuanKeberangkatan.setOnClickListener(this);
        editTextTanggalKeberangkatan.setOnClickListener(this);
        buttonCekJadwalKeberangkatan.setOnClickListener(this);
    }

    private void loadData() {
        //  list kota asal
        listNamaKotaStasiun = new ArrayList<>();
        listValueNamaKotaStasiun = new ArrayList<>();
        listNamaKotaBesar = new ArrayList<>();
        List<Stasiun> listStasiun = dataStasiun.getData().getStasiun();
        for (Stasiun stasiun : listStasiun) {
            String kotaBesar = stasiun.getKota();
            kotaBesar = String.valueOf(kotaBesar.charAt(0)).toUpperCase() + "" + kotaBesar.substring(1).toLowerCase();
             java.util.List<ysn.codepolitan_jadwalkeretaapi.model.data_stasiun.List> listNamaKotaDetail = stasiun.getList();
            for (ysn.codepolitan_jadwalkeretaapi.model.data_stasiun.List dataDetail : listNamaKotaDetail) {
                String namaKotaStasiun = dataDetail.getName();
                String valueNamaKotaStasiun = dataDetail.getValue();
                listNamaKotaStasiun.add(namaKotaStasiun);
                listValueNamaKotaStasiun.add(valueNamaKotaStasiun);
                listNamaKotaBesar.add(kotaBesar);
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        /*EventBus.getDefault().unregister(this);*/
    }

    @Subscribe(sticky = true)
    public void onMessageEvent(DataStasiun dataStasiun) {
        if (dataStasiun != null) {
            this.dataStasiun = dataStasiun;
        }
    }

    @Subscribe
    public void onMessageEvent(Map<String, Object> mapDataKota) {
        if (mapDataKota != null && mapDataKota.containsKey("isKotaAsal")) {
            boolean isKotaAsal = (boolean) mapDataKota.get("isKotaAsal");
            String kotaValue = (String) mapDataKota.get("valueKota");
            String kotaName = (String) mapDataKota.get("kotaName");
            if (isKotaAsal) {
                valueKotaAsal = kotaValue;
                editTextAsalKeberangkatan.setText(kotaName);
            } else {
                valueKotaTujuan = kotaValue;
                editTextTujuanKeberangkatan.setText(kotaName);
            }
        }
    }

    @Override
    public void onClick(View view) {
        if (view == editTextAsalKeberangkatan) {
            Map<String, List<String>> mapListDataKotaAsal = new HashMap<>();
            mapListDataKotaAsal.put("namaKotaStasiun", listNamaKotaStasiun);
            mapListDataKotaAsal.put("valueNamaKotaStasiun", listValueNamaKotaStasiun);
            mapListDataKotaAsal.put("namaKotaBesar", listNamaKotaBesar);
            EventBus.getDefault().postSticky(mapListDataKotaAsal);
            Intent intent = new Intent(this, KotaAsalTujuanActivity.class);
            intent.putExtra("isActivityKotaAsal", true);
            startActivity(intent);
        } else if (view == editTextTujuanKeberangkatan) {
            Map<String, List<String>> mapListDataKotaTujuan = new HashMap<>();
            mapListDataKotaTujuan.put("namaKotaStasiun", listNamaKotaStasiun);
            mapListDataKotaTujuan.put("valueNamaKotaStasiun", listValueNamaKotaStasiun);
            mapListDataKotaTujuan.put("namaKotaBesar", listNamaKotaBesar);
            EventBus.getDefault().postSticky(mapListDataKotaTujuan);
            Intent intent = new Intent(this, KotaAsalTujuanActivity.class);
            intent.putExtra("isActivityKotaAsal", false);
            startActivity(intent);
        } else if (view == editTextTanggalKeberangkatan) {
            Calendar calendar = Calendar.getInstance();
            DatePickerDialog datePickerDialog = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {
                @Override
                public void onDateSet(DatePicker datePicker, int year, int month, int dayOfMonth) {
                    Calendar calendarSet = new GregorianCalendar();
                    calendarSet.set(Calendar.YEAR, year);
                    calendarSet.set(Calendar.MONTH, month);
                    calendarSet.set(Calendar.DAY_OF_MONTH, dayOfMonth);
                    editTextTanggalKeberangkatan.setText(new SimpleDateFormat("EEEE, dd MMMM yyyy").format(calendarSet.getTime()));
                    String namaHari = editTextTanggalKeberangkatan.getText().toString().split(",")[0];
                    if (namaHari.equalsIgnoreCase("Sunday")) {
                        namaHari = "Minggu,";
                    } else if (namaHari.equalsIgnoreCase("Monday")) {
                        namaHari = "Senin,";
                    } else if (namaHari.equalsIgnoreCase("Tuesday")) {
                        namaHari = "Selasa,";
                    } else if (namaHari.equalsIgnoreCase("Wednesday")) {
                        namaHari = "Rabu,";
                    } else if (namaHari.equalsIgnoreCase("Thursday")) {
                        namaHari = "Kamis,";
                    } else if (namaHari.equalsIgnoreCase("Friday")) {
                        namaHari = "Jumat,";
                    } else if (namaHari.equalsIgnoreCase("Saturday")) {
                        namaHari = "Sabtu,";
                    }

                    String namaBulan = editTextTanggalKeberangkatan.getText().toString().split(" ")[2];
                    if (namaBulan.equalsIgnoreCase("January")) {
                        namaBulan = "Januari";
                    } else if (namaBulan.equalsIgnoreCase("February")) {
                        namaBulan = "Februari";
                    } else if (namaBulan.equalsIgnoreCase("March")) {
                        namaBulan = "Maret";
                    } else if (namaBulan.equalsIgnoreCase("April")) {
                        namaBulan = "April";
                    } else if (namaBulan.equalsIgnoreCase("May")) {
                        namaBulan = "Mei";
                    } else if (namaBulan.equalsIgnoreCase("June")) {
                        namaBulan = "Juni";
                    } else if (namaBulan.equalsIgnoreCase("July")) {
                        namaBulan = "Juli";
                    } else if (namaBulan.equalsIgnoreCase("August")) {
                        namaBulan = "Agustus";
                    } else if (namaBulan.equalsIgnoreCase("September")) {
                        namaBulan = "September";
                    } else if (namaBulan.equalsIgnoreCase("October")) {
                        namaBulan = "Oktober";
                    } else if (namaBulan.equalsIgnoreCase("November")) {
                        namaBulan = "November";
                    } else if (namaBulan.equalsIgnoreCase("December")) {
                        namaBulan = "Desember";
                    }
                    String[] splitDate = editTextTanggalKeberangkatan.getText().toString().split(" ");
                    String strDate = namaHari + " " + splitDate[1] + " " + namaBulan + " " + splitDate[3];
                    editTextTanggalKeberangkatan.setText(strDate);
                    List<Tanggal> listTanggal = dataStasiun.getData().getTanggal();
                    for (Tanggal tanggal : listTanggal) {
                        String nameTanggal = tanggal.getName();
                        if (editTextTanggalKeberangkatan.getText().toString().equalsIgnoreCase(nameTanggal)) {
                            valueTanggal = tanggal.getValue();
                            break;
                        }
                    }
                    valueTanggal = (valueTanggal.equals("-") || TextUtils.isEmpty(valueTanggal)) ? "-" : valueTanggal;
                }
            }, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
            datePickerDialog.show();
        } else if (view == buttonCekJadwalKeberangkatan) {
            final ProgressDialog progressDialog = new ProgressDialog(this);
            progressDialog.setMessage("Harap tunggu");
            progressDialog.setIndeterminate(true);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            progressDialog.setCancelable(false);
            progressDialog.show();

            KeretaApiService keretaApiService = retrofit.create(KeretaApiService.class);
            Call<ResponseBody> resultGetResponseBody = keretaApiService.getDataJadwal(valueTanggal, valueKotaAsal, valueKotaTujuan, KeretaApiService.apiKey);
            resultGetResponseBody.enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                    progressDialog.dismiss();
                    try {
                        String dataJadwaljson = response.body().string();
                        JSONObject jsonObjectDataJadwalJson = new JSONObject(dataJadwaljson);
                        String status = jsonObjectDataJadwalJson.getString("status");
                        if (status.equalsIgnoreCase("Success")) {
                            EventBus.getDefault().postSticky(jsonObjectDataJadwalJson);
                            Intent intent = new Intent(HomeActivity.this, JadwalKeretaApiActivity.class);
                            intent.putExtra("kotaAsal", editTextAsalKeberangkatan.getText().toString());
                            intent.putExtra("kotaTujuan", editTextTujuanKeberangkatan.getText().toString());
                            intent.putExtra("tanggalJadwal", editTextTanggalKeberangkatan.getText().toString());
                            startActivity(intent);
                        } else {
                            Toast.makeText(HomeActivity.this, "Data jadwal tidak tersedia", Toast.LENGTH_LONG)
                                    .show();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }

                @Override
                public void onFailure(Call<ResponseBody> call, Throwable t) {
                    progressDialog.dismiss();
                    t.printStackTrace();
                    Toast.makeText(HomeActivity.this, "Koneksi timeout. Silakan coba lagi", Toast.LENGTH_LONG)
                            .show();
                }
            });
        }
    }
}

Pada source code HomeActivity.java, jika Anda lihat bahwa untuk menginput kota asal dan kota tujuannya itu kita menggunakan activity lain dengan nama KotaAsalTujuanActivity. Sebenarnya ini sifatnya opsional bagi Anda karena, Anda bisa menggunakan teknik lain seperti menggunakan Spinner atau EditText untuk menginput nama kota asal dan tujuannya. Hanya saja pada tutorial ini saya lebih suka menggunakan EditText dengan focusable-nya di nonaktifkan dan diberi onClickListener sehingga, proses inputnya itu dilakukan di activity lain dan membuat proses inputan nama kota asal dan tujuannya itu tidak di input melainkan di pilih dengan style searching gitu. Dan untuk menginput tanggal jadwalnya kita menggunakan DatePickerDialog dengan simple logic didalamnya agar formatnya itu sama seperti data yang di server jadi, kita bisa melakukan pencocokan dengan data server untuk mengambil value-nya.

Form Pilih Kota Asal dan Kota Tujuan

Silakan buat satu file activity baru dengan nama KotaAsalTujuanActivity dan isi source code berikut pada file layout-nya.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/activity_kota_asal_tujuan"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="ysn.codepolitan_jadwalkeretaapi.activity.KotaAsalTujuanActivity"
    >
    
    <android.support.v7.widget.Toolbar
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:id="@+id/toolbar_activity_kota_asal_tujuan"
        android:background="@color/colorPrimary"
        app:contentInsetLeft="0dp"
        app:contentInsetStart="0dp"
        app:contentInsetRight="0dp"
        app:contentInsetEnd="0dp"
        >
        
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:layout_marginRight="16dp"
            android:layout_marginBottom="5dp"
            android:layout_marginLeft="16dp"
            >

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/button_batal_activity_kota_asal_tujuan"
                android:layout_alignParentRight="true"
                android:layout_alignParentEnd="true"
                android:layout_centerVertical="true"
                android:text="Batal"
                android:textColor="@android:color/white"
                android:layout_marginLeft="8dp"
                android:layout_marginStart="8dp"
                android:background="@drawable/background_button"
                android:minWidth="0dp"
                android:minHeight="0dp"
                android:paddingTop="13dp"
                android:paddingRight="10dp"
                android:paddingBottom="13dp"
                android:paddingLeft="10dp"
                />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/edit_text_input_kota_asal_activity_kota_asal_tujuan"
                android:hint="Masukkan nama kota"
                android:textColor="@android:color/white"
                android:layout_centerVertical="true"
                android:layout_toLeftOf="@+id/button_batal_activity_kota_asal_tujuan"
                android:layout_toStartOf="@+id/button_batal_activity_kota_asal_tujuan"
                android:background="@android:color/transparent"
                />
            
        </RelativeLayout>
        
    </android.support.v7.widget.Toolbar>

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recycler_view_activity_kota_asal_tujuan"
        android:layout_below="@+id/toolbar_activity_kota_asal_tujuan"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        />

</RelativeLayout>

Kemudian, buat 1 file adapter dengan nama AdapterKotaAsalTujuan.java dan isi dengan source code berikut.

package ysn.codepolitan_jadwalkeretaapi.activity.adapter;

import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.List;
import java.util.Map;

import ysn.codepolitan_jadwalkeretaapi.R;

/**
 * Created by root on 15/02/17.
 */

public class AdapterKotaAsalTujuan extends RecyclerView.Adapter<AdapterKotaAsalTujuan.ItemKotaAsalTujuanViewHolder> {

    private static final String TAG = "AdapterTAG";
    List<String> listNamaKotaStasiun;
    List<String> listValueNamaKotaStasiun;
    List<String> listNamaKotaBesar;
    OnItemClickListener onItemClickListener;

    public AdapterKotaAsalTujuan(List<String> listNamaKotaStasiun,
                                 List<String> listValueNamaKotaStasiun,
                                 List<String> listNamaKotaBesar,
                                 OnItemClickListener onItemClickListener) {
        this.listNamaKotaStasiun = listNamaKotaStasiun;
        this.listValueNamaKotaStasiun = listValueNamaKotaStasiun;
        this.listNamaKotaBesar = listNamaKotaBesar;
        this.onItemClickListener = onItemClickListener;

    }

    @Override
    public ItemKotaAsalTujuanViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_kota_asal_tujuan, null);
        return new ItemKotaAsalTujuanViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ItemKotaAsalTujuanViewHolder holder, int position) {
        holder.textViewNamaKotaStasiun.setText(listNamaKotaStasiun.get(position));
        holder.textViewNamaKotaBesar.setText(listNamaKotaBesar.get(position));
        holder.onClick(listValueNamaKotaStasiun.get(position), listNamaKotaStasiun.get(position));
    }

    @Override
    public int getItemCount() {
        return listNamaKotaStasiun.size();
    }

    public void refreshData(Map<String, List<String>> mapListData) {
        listNamaKotaStasiun = mapListData.get("namaKotaStasiun");
        listValueNamaKotaStasiun = mapListData.get("valueNamaKotaStasiun");
        listNamaKotaBesar = mapListData.get("namaKotaBesar");
    }

    public class ItemKotaAsalTujuanViewHolder extends RecyclerView.ViewHolder {

        private RelativeLayout relativeLayoutItem;
        private TextView textViewNamaKotaStasiun;
        private TextView textViewNamaKotaBesar;

        public ItemKotaAsalTujuanViewHolder(View itemView) {
            super(itemView);
            relativeLayoutItem = (RelativeLayout) itemView.findViewById(R.id.relative_layout_item_kota_asal_tujuan);
            textViewNamaKotaStasiun = (TextView) itemView.findViewById(R.id.text_view_nama_kota_stasiun_item_kota_asal_tujuan);
            textViewNamaKotaBesar = (TextView) itemView.findViewById(R.id.text_view_nama_kota_besar_item_kota_asal_tujuan);
        }

        public void onClick(final String value, final String kota) {
            relativeLayoutItem.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    onItemClickListener.onClick(value, kota);
                }
            });
        }
    }

    public interface OnItemClickListener {
        void onClick(String valueKota, String kotaName);
    }

}

Dan selanjutnya, ubah juga source code pada file KotaAsalTujuanActivity.java menjadi seperti berikut.

package ysn.codepolitan_jadwalkeretaapi.activity;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ysn.codepolitan_jadwalkeretaapi.R;
import ysn.codepolitan_jadwalkeretaapi.activity.adapter.AdapterKotaAsalTujuan;

public class KotaAsalTujuanActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "KotaAsalTAG";
    private EditText editTextInputKotaAsal;
    private Button buttonBatal;
    private RecyclerView recyclerViewKotaAsal;
    private AdapterKotaAsalTujuan adapterKotaAsalTujuan;
    private List<String> listNamaKotaStasiun;
    private List<String> listValueNamaKotaStasiun;
    private List<String> listNamaKotaBesar;
    private boolean isActivityKotaAsal;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_kota_asal_tujuan);
        EventBus.getDefault().register(this);
        loadComponent();
        loadData();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    private void loadComponent() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_activity_kota_asal_tujuan);
        setSupportActionBar(toolbar);

        editTextInputKotaAsal = (EditText) findViewById(R.id.edit_text_input_kota_asal_activity_kota_asal_tujuan);
        buttonBatal = (Button) findViewById(R.id.button_batal_activity_kota_asal_tujuan);
        recyclerViewKotaAsal = (RecyclerView) findViewById(R.id.recycler_view_activity_kota_asal_tujuan);
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerViewKotaAsal.setLayoutManager(layoutManager);
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
        recyclerViewKotaAsal.addItemDecoration(dividerItemDecoration);

        editTextInputKotaAsal.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                String keywordInputNamaKota = editTextInputKotaAsal.getText().toString();
                Map<String, List<String>> mapListData = new HashMap<String, List<String>>();
                if (TextUtils.isEmpty(keywordInputNamaKota)) {
                    mapListData.put("namaKotaStasiun", listNamaKotaStasiun);
                    mapListData.put("valueNamaKotaStasiun", listValueNamaKotaStasiun);
                    mapListData.put("namaKotaBesar", listNamaKotaBesar);
                    adapterKotaAsalTujuan.refreshData(mapListData);
                    adapterKotaAsalTujuan.notifyDataSetChanged();
                } else {
                    List<String> listNamaKotaStasiunKeyword = new ArrayList<String>();
                    List<String> listValueNamaKotaStasiunKeyword = new ArrayList<String>();
                    List<String> listNamaKotaBesarKeyword = new ArrayList<String>();
                    for(int a = 0; a < listNamaKotaStasiun.size(); a++) {
                        if (listNamaKotaStasiun.get(a).toLowerCase().contains(keywordInputNamaKota.toLowerCase())
                                || listNamaKotaBesar.get(a).toLowerCase().contains(keywordInputNamaKota.toLowerCase())) {
                            listNamaKotaStasiunKeyword.add(listNamaKotaStasiun.get(a));
                            listValueNamaKotaStasiunKeyword.add(listValueNamaKotaStasiun.get(a));
                            listNamaKotaBesarKeyword.add(listNamaKotaBesar.get(a));
                        }
                    }
                    mapListData.put("namaKotaStasiun", listNamaKotaStasiunKeyword);
                    mapListData.put("valueNamaKotaStasiun", listValueNamaKotaStasiunKeyword);
                    mapListData.put("namaKotaBesar", listNamaKotaBesarKeyword);
                    adapterKotaAsalTujuan.refreshData(mapListData);
                    adapterKotaAsalTujuan.notifyDataSetChanged();
                }
            }
        });
        buttonBatal.setOnClickListener(this);
    }

    private void loadData() {
        recyclerViewKotaAsal.setAdapter(adapterKotaAsalTujuan);
    }

    @Override
    public void onClick(View view) {
        if (view == buttonBatal) {
            finish();
        }
    }

    @Subscribe(sticky = true)
    public void onMessageEvent(Map<String, List<String>> mapListData) {
        listNamaKotaStasiun = mapListData.get("namaKotaStasiun");
        listValueNamaKotaStasiun = mapListData.get("valueNamaKotaStasiun");
        listNamaKotaBesar = mapListData.get("namaKotaBesar");
        Bundle bundle = getIntent().getExtras();
        isActivityKotaAsal = bundle.getBoolean("isActivityKotaAsal");
        AdapterKotaAsalTujuan.OnItemClickListener onItemClickListener = new AdapterKotaAsalTujuan.OnItemClickListener() {
            @Override
            public void onClick(String valueKota, String kotaName) {
                Map<String, Object> mapDataKota = new HashMap<>();
                mapDataKota.put("valueKota", valueKota);
                mapDataKota.put("kotaName", kotaName);
                mapDataKota.put("isKotaAsal", isActivityKotaAsal);
                EventBus.getDefault().post(mapDataKota);
                finish();
            }
        };
        adapterKotaAsalTujuan = new AdapterKotaAsalTujuan(listNamaKotaStasiun, listValueNamaKotaStasiun, listNamaKotaBesar, onItemClickListener);
    }
}

Untuk teknik penginputan ini Anda bisa menggunakan teknik lain seperti menggunakan Spinner atau EditText dengan fitur Auto Complete gitu. Jadi, tidak harus sama dengan saya yah. Silakan explore sendiri. Jadi, form ini akan muncul ketika pengguna menekan EditText kota asal atau EditText kota tujuan yang ada di Form HomeActivity. Form Input Kota Asal atau Kota Tujuan 2

Form Data Jadwal Kereta Api

Nah, fokusnya disini. Karena, timeline layout-nya itu ada di sini. Pada Form Jadwal Kereta Api ini kita menggunakan RecyclerView sebagai container-nya. Dan untuk item dari RecyclerView-nya kita membuat 3 jenis item yaitu, item bagian header, item bagian konten, dan item bagian footer. Sekarang, silakan Anda buat ketiga file item tersebut. Untuk item pertama, silakan Anda buat file layout baru dengan nama item_jadwal_kereta_api_header.xml dan isi dengan source code berikut.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    >

    <View
        android:layout_width="1dp"
        android:layout_height="24dp"
        android:background="@android:color/darker_gray"
        android:layout_marginLeft="100dp"
        android:layout_marginStart="100dp"
        />

</RelativeLayout>

Yap, dibagian headernya kita memang cuma buat garis vertikalnya doang. Hal ini sengaja penulis buat agar bagian kontennya itu tidak perlu diberi margin.

Untuk item kedua, silakan Anda buat file layout baru dengan nama item_jadwal_kereta_api.xml dan isi dengan source code berikut.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >

        <View
            android:layout_width="1dp"
            android:layout_height="210dp"
            android:background="@android:color/darker_gray"
            android:layout_marginLeft="100dp"
            android:layout_marginStart="100dp"
            />

        <View
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:id="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:background="@drawable/background_circle_berangkat"
            android:layout_marginLeft="90dp"
            android:layout_marginStart="90dp"
            android:layout_marginTop="70dp"
            />

        <TextView
            android:layout_width="85dp"
            android:layout_height="wrap_content"
            android:id="@+id/text_view_jam_berangkat_item_jadwal_kereta_api"
            android:layout_marginTop="67dp"
            android:text="10:13"
            android:gravity="center"
            />

        <TextView
            android:layout_width="85dp"
            android:layout_height="wrap_content"
            android:id="@+id/text_view_tanggal_berangkat_item_jadwal_kereta_api"
            android:layout_below="@+id/text_view_jam_berangkat_item_jadwal_kereta_api"
            android:text="18 Feb 2017"
            android:gravity="center"
            android:layout_marginTop="5dp"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/text_view_nama_kereta_api_item_jadwal_kereta_api"
            android:text="SRIBILAH UTAMA (U43)"
            android:textSize="15sp"
            android:layout_toRightOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_toEndOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_marginLeft="15dp"
            android:layout_marginStart="15dp"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/text_view_kelas_subkelas_item_jadwal_kereta_api"
            android:layout_toRightOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_toEndOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_below="@+id/text_view_nama_kereta_api_item_jadwal_kereta_api"
            android:layout_marginLeft="15dp"
            android:layout_marginStart="15dp"
            android:layout_marginTop="3dp"
            android:text="Kelas Eksekutif - I"
            android:textSize="13sp"
            android:textColor="@android:color/darker_gray"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/text_view_harga_tiket_item_jadwal_kereta_api"
            android:layout_toRightOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_toEndOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_below="@+id/text_view_kelas_subkelas_item_jadwal_kereta_api"
            android:layout_marginLeft="15dp"
            android:layout_marginStart="15dp"
            android:layout_marginTop="3dp"
            android:text="Rp 135.000"
            android:textSize="13sp"
            android:textColor="@android:color/darker_gray"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/text_view_kota_asal_item_jadwal_kereta_api"
            android:layout_toRightOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_toEndOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_marginLeft="15dp"
            android:layout_marginStart="15dp"
            android:layout_marginTop="70dp"
            android:text="BATANGKUIS"
            android:textSize="15sp"
            />

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:id="@+id/view_line_horizontal_atas_durasi_item_jadwal_kereta_api"
            android:layout_toRightOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_below="@+id/text_view_kota_asal_item_jadwal_kereta_api"
            android:layout_toEndOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_marginLeft="15dp"
            android:layout_marginStart="15dp"
            android:layout_marginTop="16dp"
            android:background="@android:color/darker_gray"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/text_view_durasi_item_jadwal_kereta_api"
            android:layout_below="@+id/view_line_horizontal_atas_durasi_item_jadwal_kereta_api"
            android:layout_toRightOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_toEndOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_marginLeft="15dp"
            android:layout_marginStart="15dp"
            android:layout_marginTop="8dp"
            android:text="Durasi 3j 36m"
            />

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:id="@+id/view_line_horizontal_bawah_durasi_item_jadwal_kereta_api"
            android:layout_toRightOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_toEndOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_below="@+id/text_view_durasi_item_jadwal_kereta_api"
            android:layout_marginLeft="15dp"
            android:layout_marginStart="15dp"
            android:layout_marginTop="8dp"
            android:background="@android:color/darker_gray"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/text_view_kota_tujuan_item_jadwal_kereta_api"
            android:layout_below="@+id/view_line_horizontal_bawah_durasi_item_jadwal_kereta_api"
            android:layout_toRightOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_marginLeft="15dp"
            android:layout_marginStart="15dp"
            android:layout_toEndOf="@+id/view_circle_berangkat_item_jadwal_kereta_api"
            android:layout_marginTop="16dp"
            android:text="MEDAN"
            android:textSize="15sp"
            />

        <View
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:id="@+id/view_circle_datang_item_jadwal_kereta_api"
            android:background="@drawable/background_circle_datang"
            android:layout_marginLeft="90dp"
            android:layout_marginStart="90dp"
            android:layout_below="@+id/view_line_horizontal_bawah_durasi_item_jadwal_kereta_api"
            android:layout_marginTop="16dp"
            />

        <TextView
            android:layout_width="85dp"
            android:layout_height="wrap_content"
            android:id="@+id/text_view_jam_datang_item_jadwal_kereta_api"
            android:text="13:49"
            android:gravity="center"
            android:layout_below="@+id/view_line_horizontal_bawah_durasi_item_jadwal_kereta_api"
            android:layout_marginTop="13dp"
            />

        <TextView
            android:layout_width="85dp"
            android:layout_height="wrap_content"
            android:id="@+id/text_view_tanggal_datang_item_jadwal_kereta_api"
            android:layout_below="@+id/text_view_jam_datang_item_jadwal_kereta_api"
            android:layout_marginTop="5dp"
            android:text="18 Feb 2017"
            android:gravity="center"
            />

    </RelativeLayout>

</RelativeLayout>

Dan untuk item yang terakhir, silakan Anda buat file layout baru dengan nama item_jadwal_kereta_api_footer.xml dan isi dengan source code berikut.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/relative_line_vertical_item_jadwal_kereta_api_footer"
        android:layout_marginLeft="@dimen/activity_horizontal_margin"
        android:layout_marginStart="@dimen/activity_horizontal_margin"
        android:layout_marginRight="@dimen/activity_horizontal_margin"
        android:layout_marginEnd="@dimen/activity_horizontal_margin"
        >

        <View
            android:layout_width="1dp"
            android:layout_height="24dp"
            android:background="@android:color/darker_gray"
            android:layout_marginLeft="100dp"
            android:layout_marginStart="100dp"
            />

    </RelativeLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@android:color/darker_gray"
        android:layout_below="@+id/relative_line_vertical_item_jadwal_kereta_api_footer"
        />

</RelativeLayout>

Dibagian footernya pun kita juga membuat garis vertikalnya saja hampir sama seperti bagian headernya namun, ada garis horizontalnya juga.

Sekarang, sebelum masuk ke kode utamanya mari kita buat terlebih dahulu file adapternya dengan nama AdapterJadwalKeretaApi.java dan isi dengan source code berikut.

package ysn.codepolitan_jadwalkeretaapi.activity.adapter;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

import ysn.codepolitan_jadwalkeretaapi.R;
import ysn.codepolitan_jadwalkeretaapi.model.data_jadwal.Datum;

/**
 * Created by root on 16/02/17.
 */

public class AdapterJadwalKeretaApi extends RecyclerView.Adapter<AdapterJadwalKeretaApi.ViewHolder> {

    public static final int ITEM_HEADER = 1;
    public static final int ITEM_CONTENT = 2;
    public static final int ITEM_FOOTER = 3;

    List<Datum> listDatum;
    List<Integer> listViewType;
    String kotaAsal;
    String kotaTujuan;

    public AdapterJadwalKeretaApi(List<Datum> listDatum,
                                  List<Integer> listViewType,
                                  String kotaAsal,
                                  String kotaTujuan) {
        this.listDatum = listDatum;
        this.listViewType = listViewType;
        this.kotaAsal = kotaAsal;
        this.kotaTujuan = kotaTujuan;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view;
        if (viewType == ITEM_HEADER) {
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_jadwal_kereta_api_header, null);
            return new ItemJadwalKeretaApiHeaderViewHolder(view);
        } else if (viewType == ITEM_CONTENT) {
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_jadwal_kereta_api, null);
            return new ItemJadwalKeretaApiViewHolder(view);
        } else if (viewType == ITEM_FOOTER) {
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_jadwal_kereta_api_footer, null);
            return new ItemJadwalKeretaApiFooterViewHolder(view);
        } else {
            return null;
        }
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        int viewType = listViewType.get(position);
        if (viewType == ITEM_HEADER || viewType == ITEM_FOOTER) {
            //  nothing to do in here
        } else if (viewType == ITEM_CONTENT) {
            ItemJadwalKeretaApiViewHolder itemJadwalKeretaApiViewHolder = (ItemJadwalKeretaApiViewHolder) holder;
            Datum datum = listDatum.get(position);

            itemJadwalKeretaApiViewHolder.textViewNamaKeretaApi.setText(datum.getKereta().getName());
            itemJadwalKeretaApiViewHolder.textViewKelasSubKelas.setText(datum.getKereta().getClass_() + " - " + datum.getHarga().getSubclass());
            itemJadwalKeretaApiViewHolder.textViewHargaTiket.setText("Rp " + datum.getHarga().getRp());
            itemJadwalKeretaApiViewHolder.textViewJamBerangkat.setText(datum.getBerangkat().getJam());
            itemJadwalKeretaApiViewHolder.textViewTanggalBerangkat.setText(datum.getBerangkat().getTanggal());
            itemJadwalKeretaApiViewHolder.textViewKotaAsal.setText(kotaAsal);
            itemJadwalKeretaApiViewHolder.textViewDurasi.setText("Durasi " + datum.getDurasi());
            itemJadwalKeretaApiViewHolder.textViewJamDatang.setText(datum.getDatang().getJam());
            itemJadwalKeretaApiViewHolder.textViewTanggalDatang.setText(datum.getDatang().getTanggal());
            itemJadwalKeretaApiViewHolder.textViewKotaTujuan.setText(kotaTujuan);
        }
    }

    @Override
    public int getItemCount() {
        return listDatum.size();
    }

    @Override
    public int getItemViewType(int position) {
        return listViewType.get(position);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        public ViewHolder(View itemView) {
            super(itemView);
        }
    }

    public class ItemJadwalKeretaApiHeaderViewHolder extends ViewHolder {

        public ItemJadwalKeretaApiHeaderViewHolder(View itemView) {
            super(itemView);
        }
    }

    public class ItemJadwalKeretaApiFooterViewHolder extends ViewHolder {

        public ItemJadwalKeretaApiFooterViewHolder(View itemView) {
            super(itemView);
        }
    }

    public class ItemJadwalKeretaApiViewHolder extends ViewHolder {

        private TextView textViewNamaKeretaApi;
        private TextView textViewKelasSubKelas;
        private TextView textViewHargaTiket;
        private TextView textViewJamBerangkat;
        private TextView textViewTanggalBerangkat;
        private TextView textViewKotaAsal;
        private TextView textViewDurasi;
        private TextView textViewJamDatang;
        private TextView textViewTanggalDatang;
        private TextView textViewKotaTujuan;

        public ItemJadwalKeretaApiViewHolder(View itemView) {
            super(itemView);
            textViewNamaKeretaApi = (TextView) itemView.findViewById(R.id.text_view_nama_kereta_api_item_jadwal_kereta_api);
            textViewKelasSubKelas = (TextView) itemView.findViewById(R.id.text_view_kelas_subkelas_item_jadwal_kereta_api);
            textViewHargaTiket = (TextView) itemView.findViewById(R.id.text_view_harga_tiket_item_jadwal_kereta_api);
            textViewJamBerangkat = (TextView) itemView.findViewById(R.id.text_view_jam_berangkat_item_jadwal_kereta_api);
            textViewTanggalBerangkat = (TextView) itemView.findViewById(R.id.text_view_tanggal_berangkat_item_jadwal_kereta_api);
            textViewKotaAsal = (TextView) itemView.findViewById(R.id.text_view_kota_asal_item_jadwal_kereta_api);
            textViewDurasi = (TextView) itemView.findViewById(R.id.text_view_durasi_item_jadwal_kereta_api);
            textViewJamDatang = (TextView) itemView.findViewById(R.id.text_view_jam_datang_item_jadwal_kereta_api);
            textViewTanggalDatang = (TextView) itemView.findViewById(R.id.text_view_tanggal_datang_item_jadwal_kereta_api);
            textViewKotaTujuan = (TextView) itemView.findViewById(R.id.text_view_kota_tujuan_item_jadwal_kereta_api);
        }
    }

}

Jika, sebelumnya Anda sudah pernah membaca atau mengikuti tutorial saya sebelumnya pasti Anda tahu bahwa pada adapter ini kita menggunakan teknik multiple view type.

Dan selanjutnya, buat activity baru dengan nama JadwalKeretaApiActivity dan silakan Anda ubah isi file layout-nya menjadi seperti berikut.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/activity_jadwal_kereta_api"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="ysn.codepolitan_jadwalkeretaapi.activity.JadwalKeretaApiActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar_activity_jadwal_kereta_api"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Jadwal Kereta Api"
            android:textColor="@android:color/white"
            android:textSize="18sp" />

    </android.support.v7.widget.Toolbar>

    <RelativeLayout
        android:id="@+id/relative_layout_keterangan_activity_jadwal_kereta_api"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/toolbar_activity_jadwal_kereta_api"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin">

        <RelativeLayout
            android:id="@+id/relative_layout_header_activity_jadwal_kereta_api"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/text_view_kota_asal_activity_jadwal_kereta_api"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_marginEnd="19dp"
                android:layout_marginRight="19dp"
                android:text="BATANGKUIS"
                android:textSize="17sp" />

            <TextView
                android:id="@+id/text_view_kota_tujuan_activity_jadwal_kereta_api"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"
                android:layout_marginLeft="19dp"
                android:layout_marginStart="19dp"
                android:text="MEDAN"
                android:textSize="17sp" />

            <View
                android:id="@+id/view_line_horizontal_activity_jadwal_kereta_api"
                android:layout_width="match_parent"
                android:layout_height="1.5dp"
                android:layout_centerVertical="true"
                android:layout_toEndOf="@+id/text_view_kota_asal_activity_jadwal_kereta_api"
                android:layout_toLeftOf="@+id/text_view_kota_tujuan_activity_jadwal_kereta_api"
                android:layout_toRightOf="@+id/text_view_kota_asal_activity_jadwal_kereta_api"
                android:layout_toStartOf="@+id/text_view_kota_tujuan_activity_jadwal_kereta_api"
                android:background="@android:color/darker_gray" />

            <View
                android:layout_width="14dp"
                android:layout_height="14dp"
                android:layout_centerVertical="true"
                android:layout_toLeftOf="@+id/view_line_horizontal_activity_jadwal_kereta_api"
                android:background="@drawable/background_circle_berangkat" />

            <View
                android:layout_width="14dp"
                android:layout_height="14dp"
                android:layout_centerVertical="true"
                android:layout_toRightOf="@+id/view_line_horizontal_activity_jadwal_kereta_api"
                android:background="@drawable/background_circle_datang" />

        </RelativeLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/relative_layout_header_activity_jadwal_kereta_api">

            <TextView
                android:id="@+id/text_view_kota_asal_placeholder_activity_jadwal_kereta_api"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_marginEnd="19dp"
                android:layout_marginRight="19dp"
                android:text="BATANGKUIS"
                android:textSize="17sp"
                android:visibility="invisible" />

            <TextView
                android:id="@+id/text_view_kota_tujuan_placeholder_activity_jadwal_kereta_api"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"
                android:layout_marginLeft="19dp"
                android:layout_marginStart="19dp"
                android:text="MEDAN"
                android:textSize="17sp"
                android:visibility="invisible" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/text_view_tanggal_jadwal_activity_jadwal_kereta_api"
                android:layout_centerVertical="true"
                android:layout_marginLeft="8dp"
                android:layout_marginRight="8dp"
                android:layout_toEndOf="@+id/text_view_kota_asal_placeholder_activity_jadwal_kereta_api"
                android:layout_toLeftOf="@+id/text_view_kota_tujuan_placeholder_activity_jadwal_kereta_api"
                android:layout_toRightOf="@+id/text_view_kota_asal_placeholder_activity_jadwal_kereta_api"
                android:layout_toStartOf="@+id/text_view_kota_tujuan_placeholder_activity_jadwal_kereta_api"
                android:gravity="center"
                android:text="Rabu, 15 Februari 2017"
                android:textColor="@android:color/darker_gray"
                android:textSize="13sp" />

        </RelativeLayout>

    </RelativeLayout>

    <View
        android:id="@+id/view_line_horizontal_2_activity_jadwal_kereta_api"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_below="@+id/relative_layout_keterangan_activity_jadwal_kereta_api"
        android:background="@android:color/darker_gray" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view_activity_jadwal_kereta_api"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/view_line_horizontal_2_activity_jadwal_kereta_api" />

</RelativeLayout>

Dan yang terakhir, silakan Anda ubah file JadwalKeretaApiActivity.java menjadi seperti berikut.

package ysn.codepolitan_jadwalkeretaapi.activity;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.TextView;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import ysn.codepolitan_jadwalkeretaapi.R;
import ysn.codepolitan_jadwalkeretaapi.activity.adapter.AdapterJadwalKeretaApi;
import ysn.codepolitan_jadwalkeretaapi.api.KeretaApiService;
import ysn.codepolitan_jadwalkeretaapi.model.data_jadwal.Berangkat;
import ysn.codepolitan_jadwalkeretaapi.model.data_jadwal.DataJadwal;
import ysn.codepolitan_jadwalkeretaapi.model.data_jadwal.Datang;
import ysn.codepolitan_jadwalkeretaapi.model.data_jadwal.Datum;
import ysn.codepolitan_jadwalkeretaapi.model.data_jadwal.Harga;
import ysn.codepolitan_jadwalkeretaapi.model.data_jadwal.Kereta;

public class JadwalKeretaApiActivity extends AppCompatActivity {

    private Retrofit retrofit;
    private DataJadwal dataJadwal;
    private TextView textViewKotaAsal;
    private TextView textViewKotaTujuan;
    private TextView textViewTanggalJadwal;
    private RecyclerView recyclerViewJadwal;
    private List<Datum> listDatum;
    private List<Integer> listViewType;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_jadwal_kereta_api);
        EventBus.getDefault().register(this);
        initializeRetrofit();
        loadComponent();
        loadAdapter();
    }

    private void loadAdapter() {
        AdapterJadwalKeretaApi adapterJadwalKeretaApi = new AdapterJadwalKeretaApi(listDatum, listViewType, textViewKotaAsal.getText().toString(), textViewKotaTujuan.getText().toString());
        recyclerViewJadwal.setAdapter(adapterJadwalKeretaApi);
    }

    private void loadComponent() {
        textViewKotaAsal = (TextView) findViewById(R.id.text_view_kota_asal_activity_jadwal_kereta_api);
        textViewKotaTujuan = (TextView) findViewById(R.id.text_view_kota_tujuan_activity_jadwal_kereta_api);
        textViewTanggalJadwal = (TextView) findViewById(R.id.text_view_tanggal_jadwal_activity_jadwal_kereta_api);
        recyclerViewJadwal = (RecyclerView) findViewById(R.id.recycler_view_activity_jadwal_kereta_api);

        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerViewJadwal.setLayoutManager(layoutManager);

        Bundle bundle = getIntent().getExtras();
        textViewKotaAsal.setText(bundle.getString("kotaAsal"));
        textViewKotaTujuan.setText(bundle.getString("kotaTujuan"));
        textViewTanggalJadwal.setText(bundle.getString("tanggalJadwal"));
    }

    private void initializeRetrofit() {
        retrofit = new Retrofit.Builder()
                .baseUrl(KeretaApiService.baseApiUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    @Subscribe(sticky = true)
    public void onMessageEvent(JSONObject jsonObjectDataJadwal) {
        try {
            //  data
            JSONArray jsonArrayData = jsonObjectDataJadwal.getJSONArray("data");
            listDatum = new ArrayList<>();
            listViewType = new ArrayList<>();
            for(int a = 0; a < jsonArrayData.length(); a++) {
                JSONObject jsonObjectItemData = jsonArrayData.getJSONObject(a);
                Datum datum = new Datum();

                //  tiket
                String tiket = jsonObjectItemData.getString("tiket");
                if (!tiket.equalsIgnoreCase("Tersedia")) {
                    continue;
                }

                listViewType.add(AdapterJadwalKeretaApi.ITEM_HEADER);
                listViewType.add(AdapterJadwalKeretaApi.ITEM_CONTENT);
                listViewType.add(AdapterJadwalKeretaApi.ITEM_FOOTER);

                //  kereta
                JSONObject jsonObjectKereta = jsonObjectItemData.getJSONObject("kereta");
                Kereta kereta = new Kereta();
                kereta.setName(jsonObjectKereta.getString("name"));
                kereta.setClass_(jsonObjectKereta.getString("class"));

                //  berangkat
                JSONObject jsonObjectBerangkat = jsonObjectItemData.getJSONObject("berangkat");
                Berangkat berangkat = new Berangkat();
                berangkat.setJam(jsonObjectBerangkat.getString("jam"));
                berangkat.setTanggal(jsonObjectBerangkat.getString("tanggal"));

                //  datang
                JSONObject jsonObjectDatang = jsonObjectItemData.getJSONObject("datang");
                Datang datang = new Datang();
                datang.setJam(jsonObjectDatang.getString("jam"));
                datang.setTanggal(jsonObjectDatang.getString("tanggal"));

                //  durasi
                String durasi = jsonObjectItemData.getString("durasi");
                if (durasi.split(" ")[0].equalsIgnoreCase("0j")) {
                    durasi = durasi.split(" ")[1];
                }
                else if (durasi.split(" ")[1].equalsIgnoreCase("0m")) {
                    durasi = durasi.split(" ")[0];
                }

                //  harga
                JSONObject jsonObjectHarga = jsonObjectItemData.getJSONObject("harga");
                Harga harga = new Harga();
                harga.setRp(jsonObjectHarga.getString("rp"));
                harga.setSubclass(jsonObjectHarga.getString("subclass"));

                datum.setKereta(kereta);
                datum.setBerangkat(berangkat);
                datum.setDatang(datang);
                datum.setDurasi(durasi);
                datum.setHarga(harga);
                datum.setTiket(tiket);
                listDatum.add(datum);
            }

        } catch (JSONException jsone) {
            jsone.printStackTrace();
        }
    }

}

Pada file java-nya, bisa Anda lihat bahwa pada bagian activity ini ada menerima data dari activity sebelumnya yang bisa Anda lihat pada bagian method onMessageEvent(). Disitu bisa Anda lihat bahwa, data yang diterima merupakan data JSON dari HomeActivity.java yang mana pada HomeActivity.java ketika button cek jadwal ditekan maka, ada melakukan request ke server dan selanjutnya, hasilnya itu diterima dalam bentuk ResponseBody dan diubah menjadi json dengan syntax String dataJadwaljson = response.body().string(); dan disimpan dalam variable dataJadwalJson. Jadi, kesimpulannya, ialah bahwa pada bagian JadwalKeretaApiActivity ini hanya menampilkan datanya saja tidak ada melakukan request ke server. Untuk proses request ke server itu hanya ada dilakukan di bagian splash screen untuk nge-load datanya dan ketika di HomeActivity untuk mengambil data jadwalnya. Jadi, kurang lebih seperti inilah output dari program kita kali ini. HomeActivity JadwalKeretaApiActivity

Struktur Projek

Berikut struktur projek pada tutorial ini. Struktur projek

Bagi Anda yang masih bingung terhadap pembuatan timeline layout pada tutorial ini silakan bertanya pada komentar. Untuk semua file pendukung projeknya sudah saya upload di akun github saya di sini