(Tutorial Android) Http Client On Android With Retrofit



Artikel ini sudah tidak relevan lagi dikarenakan service dari ibacor.com sudah mati. Kaprikornus aku mengharapkan para pembaca untuk memakluminya jikalau aplikasi tidak sanggup dijalankan. Untuk tutorial yang gres sanggup dilihat di sini https://andronut.blogspot.com//search?q=re-tutorial-android-http-client-on

Retrofit merupakan library HTTP Client untuk Android dan Java. Library ini sangat terkenal dan banyak dipakai oleh developer khususnya Android. Retrofit sangat gampang digunakan, simpel, extensibility dan mempunyai performance yang sangat cantik jikalau dibandingkan dengan library yang lain. Dengan memakai Retrofit, kita melaksanakan request ke REST Webservice dengan gampang dengan aneka macam macam method-method yang disediakan. Library Retrofit dikembangkan oleh Square. Saya sendiri suka dengan library ini dan juga sering menggunakannya di setiap project-project yang aku kerjakan. :D

Pada postingan kali ini aku akan membahas wacana penggunaan library Retrofit di Android.

Hal yang perlu disiapkan terlebih dahulu yaitu API service. Di sini aku memakai layanan Free API dari ibacor. Selengkapnya sanggup dilihat di sini http://ibacor.com/api. API yang akan kita gunakan yaitu Jadwal Bioskop 21.

Contoh requestnya sebagai berikut :

Daftar Kota :

GET http://ibacor.com/api/jadwal-bioskop?k=....

Parameter :
k = API Key yang didapat dari ibacor

Response :
{     "status": "success",     "data": [         {             "id": "32",             "kota": "AMBON"         },         {             "id": "6",             "kota": "BALIKPAPAN"         },         …..     ] }  

Semua Jadwal Berdasarkan Id Kota

GET http://ibacor.com/api/jadwal-bioskop?k=...&id=10

Parameter :
k = API Key yang didapat dari ibacor
id = ID Kota

Response :
{     "status": "success",     "kota": "JAKARTA",     "date": "22\/07\/16",     "data": [         {             "movie": "GHOSTBUSTERS",             "poster": "http:\/\/image.tmdb.org\/t\/p\/w300\/4qnJ1hsMADxzwnOmnwjZTNp0rKT.jpg",             "genre": "Action, Comedy, Sci-fi",             "duration": "116 minute",             "jadwal": [                 {                     "bioskop": "ANGGREK XXI",                     "jam": [                         "12:15",                         "14:35",                         "15:25",                         "16:55",                         "19:15",                         "20:15",                         "21:35"                     ],                     "harga": "Rp.50,000"                 },                 …...             ]  …..         }     ] } 

Kita akan menciptakan aplikasi untuk mengetahui gosip kegiatan bioskop 21 di seluruh kota di Indonesia.

Buat project baru.




Pertama, tambahkan library retrofit di gradle. Retrofit yang akan dipakai yaitu Retrofit 2. Latest version sanggup dilihat di http://square.github.io/retrofit/
compile 'com.squareup.retrofit2:retrofit:2.1.0' 
Dan tambahkan juga converter gson, alasannya yaitu json hasil request akan eksklusif di convert ke gson object.
compile 'com.squareup.retrofit2:converter-gson:2.1.0' 
Tambahkan juga beberapa library pendukung yang diharapkan selengkapnya ibarat ini :
dependencies {     compile fileTree(dir: 'libs', include: ['*.jar'])     testCompile 'junit:junit:4.12'     compile 'com.android.support:appcompat-v7:23.3.0'     compile 'com.android.support:design:23.3.0'      compile 'com.squareup.retrofit2:retrofit:2.1.0'     compile 'com.squareup.retrofit2:converter-gson:2.1.0'      compile 'com.squareup.picasso:picasso:2.5.2' } 

Inisialisasi BASE_URL dan API_KEY sebagai di gradle.properties
BASE_URL = "http://ibacor.com" API_KEY = "YOUR API KEY" 

Kemudian letakkan configurasi BASE_URL dan API_KEY di gradle.
... defaultConfig {     applicationId "example.wim.androidretrofit"     minSdkVersion 15     targetSdkVersion 23     versionCode 1     versionName "1.0" }  buildTypes.each {     it.buildConfigField 'String', 'BASE_URL', BASE_URL     it.buildConfigField 'String', 'API_KEY', API_KEY }  ... 
Kita akan mulai menambahkan resource yang diperlukan.

values/colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources>     <color name="colorPrimary">#795548</color>     <color name="colorPrimaryDark">#4E342E</color>     <color name="colorAccent">#FF4081</color>     <color name="colorWhite">#FFFFFF</color>     <color name="colorGrey">#E5E5E5</color> </resources> 

values/string.xml
<resources>     <string name="app_name">Cinema XXI</string>     <string name="genre">Genre : %s</string>     <string name="duration">Duration : %s</string> </resources> 

drawable/bg_rounded.xml
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android">     <solid android:color="@color/colorPrimary"/>     <stroke android:width="1dip" android:color="@color/colorPrimary" />     <corners android:radius="3dip"/>     <padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" /> </shape> 

Buat beberapa layout berikut :

activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     tools:context="example.wim.androidretrofit.MainActivity">     <android.support.v4.widget.SwipeRefreshLayout         android:id="@+id/refresh"         android:layout_width="match_parent"         android:layout_height="wrap_content">         <android.support.v7.widget.RecyclerView             android:id="@+id/rv_city"             android:layout_width="match_parent"             android:layout_height="match_parent"             android:scrollbars="vertical"/>     </android.support.v4.widget.SwipeRefreshLayout> </RelativeLayout> 

activity_movie.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:orientation="vertical"     android:layout_width="match_parent"     android:layout_height="match_parent">     <android.support.v4.widget.SwipeRefreshLayout         android:id="@+id/refresh"         android:layout_width="match_parent"         android:layout_height="wrap_content">         <android.support.v7.widget.RecyclerView             android:id="@+id/rv_movie"             android:layout_width="match_parent"             android:layout_height="match_parent"             android:scrollbars="vertical"/>     </android.support.v4.widget.SwipeRefreshLayout> </LinearLayout> 

activity_showtime.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:orientation="vertical" android:layout_width="match_parent"     android:layout_height="match_parent">     <android.support.v7.widget.RecyclerView         android:id="@+id/rv_showtime"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:scrollbars="vertical"/> </LinearLayout> 

list_item_city.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:orientation="vertical" android:layout_width="match_parent"     android:layout_height="wrap_content"     android:clickable="true"     android:focusable="true"     android:background="?android:attr/selectableItemBackground"     android:padding="16dp">     <TextView         android:id="@+id/city"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:textSize="16sp"         android:text="Jakarta" /> </LinearLayout> 

list_item_movie.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:orientation="vertical"     android:layout_width="match_parent"     android:layout_height="wrap_content"     android:clickable="true"     android:focusable="true"     android:background="?android:attr/selectableItemBackground"     android:padding="@dimen/margin_8dp">     <LinearLayout         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:orientation="horizontal">         <ImageView             android:id="@+id/poster"             android:layout_width="80dp"             android:layout_height="100dp"             android:src="@drawable/star_trek"             android:scaleType="centerCrop"/>             <LinearLayout                 android:layout_width="match_parent"                 android:layout_height="wrap_content"                 android:orientation="vertical"                 android:padding="8dp">                 <TextView                     android:id="@+id/title"                     android:layout_width="match_parent"                     android:layout_height="wrap_content"                     android:text="STAR TREK BEYOND"                     android:textSize="17sp"                     android:textStyle="bold"/>                 <LinearLayout                     android:layout_width="match_parent"                     android:layout_height="wrap_content"                     android:orientation="vertical"                     android:layout_marginTop="8dp">                     <TextView                         android:id="@+id/genre"                         android:layout_width="match_parent"                         android:layout_height="wrap_content"                         android:text="@string/genre"                         android:textSize="16sp"/>                     <TextView                         android:id="@+id/duration"                         android:layout_width="match_parent"                         android:layout_height="wrap_content"                         android:text="@string/duration"                         android:textSize="16sp"/>                 </LinearLayout>             </LinearLayout>     </LinearLayout> </LinearLayout> 

list_item_showtime.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:orientation="vertical" android:layout_width="match_parent"     android:layout_height="wrap_content"     android:padding="@dimen/margin_8dp">     <LinearLayout         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:orientation="vertical"         android:padding="@dimen/margin_8dp"         android:background="@color/colorGrey">         <TextView             android:id="@+id/theater"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:text="ATRIUM XXI"             android:textSize="17sp"             android:textStyle="bold"/>         <example.wim.androidretrofit.util.FlowLayout             android:id="@+id/lyTime"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_marginTop="4dp"             android:orientation="vertical"/>         <TextView             android:id="@+id/price"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_marginTop="@dimen/margin_8dp"             android:text="Rp. 30.000"             android:textSize="16sp"/>     </LinearLayout> </LinearLayout> 

list_item_time.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_margin="4dp"     android:orientation="vertical">     <TextView         android:id="@+id/time"         android:layout_width="64dp"         android:layout_height="wrap_content"         android:background="@drawable/bg_rounded"         android:gravity="center"         android:padding="4dp"         android:text="00:00"         android:textColor="@color/colorWhite"/> </LinearLayout> 


Selanjutnya kita akan melaksanakan deklarasi API dengan Retrofit.

Deklarasi API di Retrofit memakai Annotations di dalam method Interface dan parameter-parameter yang diharapkan untuk melaksanakan request. Setiap method harus mempunyai HTTP Annotation ibarat GET, POST, PUT, DELETE dan HEAD. Setiap URL resource ditentukan oleh Annotation.

Contohnya :
@GET(“users/list”)
@POST(“users/new”)

Selain itu, parameter-parameter di method berupa annotations juga ibarat @Query, @Path, @Body dan @Header.

@Path : variabel substitusi untuk endpoint API.
Contohnya : user id sanggup disisipi {id} di URLnya.

@Query : memilih parameter berupa key dan value.
@Body : mengirimkan request body berupa object melalui POST.
@Header : memilih header.

Selanjutnya menciptakan interface yang berisi method-method tadi. Di method tersebut akan dipakai untuk mengirim request berupa daftar kota dan kegiatan bioskop.
package example.wim.androidretrofit.service; import example.wim.androidretrofit.model.City; import example.wim.androidretrofit.model.Movie;  import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.Query;  /**  * Created by Wim on 7/19/16.  */ public interface ApiInterface {      @GET("api/jadwal-bioskop")     Call<City> getCity();      @GET("api/jadwal-bioskop")     Call<Movie> getMovie(             @Query("id") String id); }  

Kemudian buat kelas service dengan nama ApiService. Di sini kita akan menciptakan konfigurasi dari Retrofit.
package example.wim.androidretrofit.service;  import java.io.IOException; import java.util.concurrent.TimeUnit;  import example.wim.androidretrofit.BuildConfig; import okhttp3.HttpUrl; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import retrofit2.Callback; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory;  /**  * Created by Wim on 7/19/16.  */ public class ApiService {      private ApiInterface apiInterface;      public ApiService(){         Retrofit retrofit = new Retrofit.Builder()                 .baseUrl(BuildConfig.BASE_URL)                 .client(builder())                 .addConverterFactory(GsonConverterFactory.create())                 .build();          apiInterface = retrofit.create(ApiInterface.class);     }      private OkHttpClient builder() {         OkHttpClient.Builder okHttpClient = new OkHttpClient().newBuilder();         okHttpClient.connectTimeout(20, TimeUnit.SECONDS);         okHttpClient.writeTimeout(20, TimeUnit.SECONDS);         okHttpClient.readTimeout(90, TimeUnit.SECONDS);           okHttpClient.addInterceptor(new Interceptor() {             @Override             public Response intercept(Chain chain) throws IOException {                 Request request = chain.request();                 HttpUrl url = request.url()                         .newBuilder()                         .addQueryParameter("k", BuildConfig.API_KEY)                         .build();                  request = request.newBuilder().url(url).build();                 return chain.proceed(request);             }         });          return okHttpClient.build();     }      public void getCityList(Callback callback){         apiInterface.getCity().enqueue(callback);     }      public void getMovieList(String id, Callback callback){         apiInterface.getMovie(id).enqueue(callback);     }  } 


Sampai di sini kita sudah menciptakan kelas untuk melaksanakan request ke API. Selanjutnya yaitu menciptakan kelas model menurut data di JSON. Berikut kelas-kelasnya :

City.java
package example.wim.androidretrofit.model;  import java.util.List;  /**  * Created by Wim on 7/19/16.  */ public class City {      private String status;     private String message;     private List<CityData> data;      public String getStatus() {         return status;     }      public void setStatus(String status) {         this.status = status;     }      public String getMessage() {         return message;     }      public void setMessage(String message) {         this.message = message;     }      public List<CityData> getData() {         return data;     }      public void setData(List<CityData> data) {         this.data = data;     } } 

CityData.java
package example.wim.androidretrofit.model; import android.os.Parcel; import android.os.Parcelable;  /**  * Created by Wim on 7/19/16.  */ public class CityData implements Parcelable {      private String id;     private String kota;      public CityData() {     }      protected CityData(Parcel in) {         this.id = in.readString();         this.kota = in.readString();     }      public static final Parcelable.Creator<CityData> CREATOR = new Parcelable.Creator<CityData>() {         @Override         public CityData createFromParcel(Parcel source) {             return new CityData(source);         }          @Override         public CityData[] newArray(int size) {             return new CityData[size];         }     };      public String getId() {         return id;     }      public void setId(String id) {         this.id = id;     }      public String getKota() {         return kota;     }      public void setKota(String kota) {         this.kota = kota;     }      @Override     public int describeContents() {         return 0;     }      @Override     public void writeToParcel(Parcel dest, int flags) {         dest.writeString(this.id);         dest.writeString(this.kota);     }  }

Movie.java
package example.wim.androidretrofit.model;  import java.util.List;  /**  * Created by Wim on 7/19/16.  */ public class Movie {      private String status;     private String message;     private String kota;     private String date;     private List<MovieData> data;      public String getStatus() {         return status;     }      public void setStatus(String status) {         this.status = status;     }      public String getMessage() {         return message;     }      public void setMessage(String message) {         this.message = message;     }      public String getKota() {         return kota;     }      public void setKota(String kota) {         this.kota = kota;     }      public String getDate() {         return date;     }      public void setDate(String date) {         this.date = date;     }      public List<MovieData> getData() {         return data;     }      public void setData(List<MovieData> data) {         this.data = data;     } }  

MovieData.java
package example.wim.androidretrofit.model; import android.os.Parcel; import android.os.Parcelable; import java.util.ArrayList; import java.util.List;  /**  * Created by Wim on 7/19/16.  */  public class MovieData implements Parcelable {      private String movie;     private String poster;     private String genre;     private String duration;     private List<Showtime> jadwal;      public MovieData() {     }      protected MovieData(Parcel in) {         this.movie = in.readString();         this.poster = in.readString();         this.genre = in.readString();         this.duration = in.readString();         this.jadwal = new ArrayList<Showtime>();         in.readList(this.jadwal, Showtime.class.getClassLoader());     }      public static final Parcelable.Creator<MovieData> CREATOR = new Parcelable.Creator<MovieData>() {         @Override         public MovieData createFromParcel(Parcel source) {             return new MovieData(source);         }         @Override         public MovieData[] newArray(int size) {             return new MovieData[size];         }     };      public String getMovie() {         return movie;     }      public void setMovie(String movie) {         this.movie = movie;     }      public String getPoster() {         return poster;     }      public void setPoster(String poster) {         this.poster = poster;     }      public String getGenre() {         return genre;     }      public void setGenre(String genre) {         this.genre = genre;     }      public String getDuration() {         return duration;     }       public void setDuration(String duration) {         this.duration = duration;     }      public List<Showtime> getJadwal() {         return jadwal;     }      public void setJadwal(List<Showtime> jadwal) {         this.jadwal = jadwal;     }      @Override     public int describeContents() {         return 0;     }      @Override     public void writeToParcel(Parcel dest, int flags) {         dest.writeString(this.movie);         dest.writeString(this.poster);         dest.writeString(this.genre);         dest.writeString(this.duration);         dest.writeList(this.jadwal);     } } 

Showtime.java
package example.wim.androidretrofit.model; import android.os.Parcel; import android.os.Parcelable; import java.util.List;  /**  * Created by Wim on 7/19/16.  */ public class Showtime implements Parcelable {      private String bioskop;     private List<String> jam;     private String harga;      public Showtime() {     }      protected Showtime(Parcel in) {         this.bioskop = in.readString();         this.jam = in.createStringArrayList();         this.harga = in.readString();     }      public static final Parcelable.Creator<Showtime> CREATOR = new Parcelable.Creator<Showtime>() {         @Override         public Showtime createFromParcel(Parcel source) {             return new Showtime(source);         }         @Override         public Showtime[] newArray(int size) {             return new Showtime[size];         }     };      public String getBioskop() {         return bioskop;     }      public void setBioskop(String bioskop) {         this.bioskop = bioskop;     }      public List<String> getJam() {         return jam;     }      public void setJam(List<String> jam) {         this.jam = jam;     }      public String getHarga() {         return harga;     }      public void setHarga(String harga) {         this.harga = harga;     }      @Override     public int describeContents() {         return 0;     }      @Override     public void writeToParcel(Parcel dest, int flags) {         dest.writeString(this.bioskop);         dest.writeStringList(this.jam);         dest.writeString(this.harga);     } } 


Setelah kelas model dibuat, berikutnya menciptakan kelas-kelas utility.

DividerItemDecoration.java
package example.wim.androidretrofit.util; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View;  /**  * Created by Wim on 7/18/16.  */ public class DividerItemDecoration extends RecyclerView.ItemDecoration {      private static final int[] ATTRS = new int[]{             android.R.attr.listDivider     };     public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;     public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;     private Drawable mDivider;     private int mOrientation;      public DividerItemDecoration(Context context, int orientation) {         final TypedArray a = context.obtainStyledAttributes(ATTRS);         mDivider = a.getDrawable(0);         a.recycle();         setOrientation(orientation);     }      public void setOrientation(int orientation) {         if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {             throw new IllegalArgumentException("invalid orientation");         }         mOrientation = orientation;     }      @Override     public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {         if (mOrientation == VERTICAL_LIST) {             drawVertical(c, parent);         } else {             drawHorizontal(c, parent);         }     }      public void drawVertical(Canvas c, RecyclerView parent) {         final int left = parent.getPaddingLeft();         final int right = parent.getWidth() - parent.getPaddingRight();         final int childCount = parent.getChildCount();         for (int i = 0; i < childCount; i++) {             final View child = parent.getChildAt(i);             final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child                     .getLayoutParams();             final int top = child.getBottom() + params.bottomMargin;             final int bottom = top + mDivider.getIntrinsicHeight();             mDivider.setBounds(left, top, right, bottom);             mDivider.draw(c);         }     }      public void drawHorizontal(Canvas c, RecyclerView parent) {         final int top = parent.getPaddingTop();         final int bottom = parent.getHeight() - parent.getPaddingBottom();         final int childCount = parent.getChildCount();         for (int i = 0; i < childCount; i++) {             final View child = parent.getChildAt(i);             final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child                     .getLayoutParams();             final int left = child.getRight() + params.rightMargin;             final int right = left + mDivider.getIntrinsicHeight();             mDivider.setBounds(left, top, right, bottom);             mDivider.draw(c);         }     }      @Override     public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {         if (mOrientation == VERTICAL_LIST) {             outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());         } else {             outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);         }     } } 


FlowLayout.java
package example.wim.androidretrofit.util; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import example.wim.androidretrofit.R;  /**  * Created by Wim on 7/21/16.  */ public class FlowLayout extends ViewGroup {      private int paddingHorizontal;     private int paddingVertical;      public FlowLayout(Context context) {         super(context);         init();     }      public FlowLayout(Context context, AttributeSet attrs) {         this(context, attrs, 0);     }      public FlowLayout(Context context, AttributeSet attrs, int defStyle) {         super(context, attrs, defStyle);         init();     }      private void init() {         paddingHorizontal = getResources().getDimensionPixelSize(R.dimen.margin_8dp);         paddingVertical = getResources().getDimensionPixelSize(R.dimen.margin_8dp);     }      @Override     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {         int childLeft = getPaddingLeft();         int childTop = getPaddingTop();         int lineHeight = 0;         // 100 is a dummy number, widthMeasureSpec should always be EXACTLY for FlowLayout         int myWidth = resolveSize(100, widthMeasureSpec);         int wantedHeight = 0;         for (int i = 0; i < getChildCount(); i++) {             final View child = getChildAt(i);             if (child.getVisibility() == View.GONE) {                 continue;             }             // let the child measure itself             child.measure(                     getChildMeasureSpec(widthMeasureSpec, 0, child.getLayoutParams().width),                     getChildMeasureSpec(heightMeasureSpec, 0, child.getLayoutParams().height));             int childWidth = child.getMeasuredWidth();             int childHeight = child.getMeasuredHeight();             // lineheight is the height of current line, should be the height of the heightest view             lineHeight = Math.max(childHeight, lineHeight);             if (childWidth + childLeft + getPaddingRight() > myWidth) {                 // wrap this line                 childLeft = getPaddingLeft();                 childTop += paddingVertical + lineHeight;                 lineHeight = childHeight;             }             childLeft += childWidth + paddingHorizontal;         }         wantedHeight += childTop + lineHeight + getPaddingBottom();         setMeasuredDimension(myWidth, resolveSize(wantedHeight, heightMeasureSpec));     }      @Override     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {         int childLeft = getPaddingLeft();         int childTop = getPaddingTop();         int lineHeight = 0;         int myWidth = right – left;          for (int i = 0; i < getChildCount(); i++) {             final View child = getChildAt(i);             if (child.getVisibility() == View.GONE) {                 continue;             }             int childWidth = child.getMeasuredWidth();             int childHeight = child.getMeasuredHeight();             lineHeight = Math.max(childHeight, lineHeight);             if (childWidth + childLeft + getPaddingRight() > myWidth) {                 childLeft = getPaddingLeft();                 childTop += paddingVertical + lineHeight;                 lineHeight = childHeight;             }             child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);             childLeft += childWidth + paddingHorizontal;         }     } } 


Buat beberapa kelas adapter berikut :

CityListAdapter.java
package example.wim.androidretrofit.adapter; import android.content.Context; 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.ArrayList; import java.util.List; import example.wim.androidretrofit.R; import example.wim.androidretrofit.listener.RecyclerViewItemClickListener; import example.wim.androidretrofit.model.CityData;  /**  * Created by Wim on 7/21/16.  */ public class CityListAdapter extends RecyclerView.Adapter<CityListAdapter.CityViewHolder>{      private List<CityData> cityDataList;     private Context context;     private RecyclerViewItemClickListener recyclerViewItemClickListener;      public CityListAdapter(Context context) {         this.context = context;         cityDataList = new ArrayList<>();     }      private void add(CityData item) {         cityDataList.add(item);         notifyItemInserted(cityDataList.size() - 1);     }      public void addAll(List<CityData> cityDataList) {         for (CityData cityData : cityDataList) {             add(cityData);         }     }      public void remove(CityData item) {         int position = cityDataList.indexOf(item);         if (position > -1) {             cityDataList.remove(position);             notifyItemRemoved(position);         }     }      public void clear() {         while (getItemCount() > 0) {             remove(getItem(0));         }     }      public CityData getItem(int positon){         return cityDataList.get(positon);     }      @Override     public CityViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {         View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_city, parent, false);         final CityViewHolder cityViewHolder = new CityViewHolder(view);         cityViewHolder.itemView.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View v) {                 int adapterPos = cityViewHolder.getAdapterPosition();                 if (adapterPos != RecyclerView.NO_POSITION) {                     if (recyclerViewItemClickListener != null) {                         recyclerViewItemClickListener.onItemClick(adapterPos, cityViewHolder.itemView);                     }                 }             }         });         return cityViewHolder;     }      @Override     public void onBindViewHolder(CityViewHolder holder, int position) {         final CityData cityData = cityDataList.get(position);         holder.city.setText(cityData.getKota());     }      @Override     public int getItemCount() {         return cityDataList.size();     }     public void setRecyclerViewItemClickListener(RecyclerViewItemClickListener recyclerViewItemClickListener) {         this.recyclerViewItemClickListener = recyclerViewItemClickListener;     }      static class CityViewHolder extends RecyclerView.ViewHolder {          TextView city;          public CityViewHolder(View itemView) {             super(itemView);              city = (TextView) itemView.findViewById(R.id.city);         }     } } 

MovieListAdapter.java
package example.wim.androidretrofit.adapter; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.squareup.picasso.Picasso; import java.util.ArrayList; import java.util.List; import example.wim.androidretrofit.R; import example.wim.androidretrofit.listener.RecyclerViewItemClickListener; import example.wim.androidretrofit.model.MovieData;  /**  * Created by Wim on 7/20/16.  */ public class MovieListAdapter extends RecyclerView.Adapter<MovieListAdapter.MovieViewHolder> {      private List<MovieData> movieDataList;     private Context context;     private RecyclerViewItemClickListener recyclerViewItemClickListener;      public MovieListAdapter(Context context) {         this.context = context;         movieDataList = new ArrayList<>();     }      private void add(MovieData item) {         movieDataList.add(item);         notifyItemInserted(movieDataList.size() - 1);     }      public void addAll(List<MovieData> movieDataList) {         for (MovieData movieData : movieDataList) {             add(movieData);         }     }      public void remove(MovieData item) {         int position = movieDataList.indexOf(item);         if (position > -1) {             movieDataList.remove(position);             notifyItemRemoved(position);         }     }     public void clear() {         while (getItemCount() > 0) {             remove(getItem(0));         }     }      public MovieData getItem(int positon){         return movieDataList.get(positon);     }      @Override     public MovieViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {         View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_movie, parent, false);         final MovieViewHolder movieViewHolder = new MovieViewHolder(view);         movieViewHolder.itemView.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View v) {                 int adapterPos = movieViewHolder.getAdapterPosition();                 if (adapterPos != RecyclerView.NO_POSITION) {                     if (recyclerViewItemClickListener != null) {                         recyclerViewItemClickListener.onItemClick(adapterPos, movieViewHolder.itemView);                     }                 }             }         });         return movieViewHolder;     }      @Override     public void onBindViewHolder(MovieViewHolder holder, int position) {         final MovieData movieData = movieDataList.get(position);         Picasso.with(context)                 .load(movieData.getPoster())                 .into(holder.poster);         holder.title.setText(Html.fromHtml(movieData.getMovie()));         holder.genre.setText(context.getResources().getString(R.string.genre, movieData.getGenre()));         holder.duration.setText(context.getResources().getString(R.string.duration, movieData.getDuration()));     }      @Override     public int getItemCount() {         return movieDataList.size();     }      public void setRecyclerViewItemClickListener(RecyclerViewItemClickListener recyclerViewItemClickListener) {         this.recyclerViewItemClickListener = recyclerViewItemClickListener;     }      static class MovieViewHolder extends RecyclerView.ViewHolder {          ImageView poster;         TextView title;         TextView genre;         TextView duration;          public MovieViewHolder(View itemView) {             super(itemView);              poster = (ImageView) itemView.findViewById(R.id.poster);             title = (TextView) itemView.findViewById(R.id.title);             genre = (TextView) itemView.findViewById(R.id.genre);             duration = (TextView) itemView.findViewById(R.id.duration);         }     } } 

ShowtimeListAdapter.java
package example.wim.androidretrofit.adapter; import android.content.Context; 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.ArrayList; import java.util.List; import example.wim.androidretrofit.R; import example.wim.androidretrofit.model.Showtime; import example.wim.androidretrofit.util.FlowLayout;  /**  * Created by Wim on 7/21/16.  */ public class ShowtimeListAdapter extends RecyclerView.Adapter<ShowtimeListAdapter.ShowtimeViewHolder>{      private List<Showtime> showtimeList;     private Context context;      public ShowtimeListAdapter(Context context) {         this.context = context;         showtimeList = new ArrayList<>();     }      private void add(Showtime item) {         showtimeList.add(item);         notifyItemInserted(showtimeList.size() - 1);     }      public void addAll(List<Showtime> showtimeList) {         for (Showtime showtime : showtimeList) {             add(showtime);         }     }      public void remove(Showtime item) {         int position = showtimeList.indexOf(item);         if (position > -1) {             showtimeList.remove(position);             notifyItemRemoved(position);         }     }      public void clear() {         while (getItemCount() > 0) {             remove(getItem(0));         }     }      public Showtime getItem(int positon){         return showtimeList.get(positon);     }      @Override     public ShowtimeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {         View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_showtime, parent, false);         return new ShowtimeViewHolder(view);     }      @Override     public void onBindViewHolder(ShowtimeViewHolder holder, int position) {         final Showtime showtime = showtimeList.get(position);         holder.theater.setText(showtime.getBioskop());         for (int i=0; i<showtime.getJam().size(); i++) {             View view = LayoutInflater.from(context).inflate(R.layout.list_item_time, holder.lyTime, false);             TextView time = (TextView) view.findViewById(R.id.time);             time.setText(showtime.getJam().get(i));             holder.lyTime.addView(view);         }         holder.price.setText(showtime.getHarga());     }      @Override     public int getItemCount() {         return showtimeList.size();     }      static class ShowtimeViewHolder extends RecyclerView.ViewHolder {          TextView theater;         FlowLayout lyTime;         TextView price;          public ShowtimeViewHolder(View itemView) {             super(itemView);              theater = (TextView) itemView.findViewById(R.id.theater);             lyTime = (FlowLayout) itemView.findViewById(R.id.lyTime);             price = (TextView) itemView.findViewById(R.id.price);         }     } } 


Buat interface untuk listener saat recycler item di klik.

RecyclerItemClickListener.java
package example.wim.androidretrofit.listener; import android.view.View; /**  * Created by Wim on 7/17/16.  */ public interface RecyclerViewItemClickListener {     void onItemClick(int position, View view); } 


Langkah selanjutnya yaitu buat activity berikut :

MainActivity.java
package example.wim.androidretrofit;  import android.os.Handler; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.widget.Toast;  import java.net.SocketTimeoutException;  import example.wim.androidretrofit.adapter.CityListAdapter; import example.wim.androidretrofit.listener.RecyclerViewItemClickListener; import example.wim.androidretrofit.model.City; import example.wim.androidretrofit.service.ApiService; import example.wim.androidretrofit.util.DividerItemDecoration; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response;  public class MainActivity extends AppCompatActivity implements RecyclerViewItemClickListener {      private RecyclerView rvCity;     private SwipeRefreshLayout swipeRefreshLayout;      private LinearLayoutManager linearLayoutManager;     private CityListAdapter cityListAdapter;      private ApiService apiService;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          rvCity = (RecyclerView) findViewById(R.id.rv_city);         swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh);          linearLayoutManager = new LinearLayoutManager(this);         cityListAdapter = new CityListAdapter(this);         cityListAdapter.setRecyclerViewItemClickListener(this);          rvCity.setLayoutManager(linearLayoutManager);         rvCity.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));         rvCity.setAdapter(cityListAdapter);          swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);         swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {             @Override             public void onRefresh() {                 refreshData();             }         });          loadData();     }      private void loadData(){         if (swipeRefreshLayout != null)             swipeRefreshLayout.post(new Runnable() {                 @Override                 public void run() {                     swipeRefreshLayout.setRefreshing(true);                 }             });          apiService = new ApiService();         apiService.getCityList(new Callback() {             @Override             public void onResponse(Call call, Response response) {                 City city = (City) response.body();                  if(city != null) {                     if(city.getStatus().equals("success")) {                         cityListAdapter.addAll(city.getData());                     }else{                         Toast.makeText(MainActivity.this, city.getMessage(), Toast.LENGTH_LONG).show();                     }                     Log.i("STATUS", city.getStatus());                 }else{                     Toast.makeText(MainActivity.this, "No Data!", Toast.LENGTH_LONG).show();                 }                  if (swipeRefreshLayout != null)                     swipeRefreshLayout.setRefreshing(false);             }              @Override             public void onFailure(Call call, Throwable t) {                 if(t instanceof SocketTimeoutException) {                     Toast.makeText(MainActivity.this, "Request Timeout. Please try again!", Toast.LENGTH_LONG).show();                 }else{                     Toast.makeText(MainActivity.this, "Connection Error!", Toast.LENGTH_LONG).show();                 }                 Log.i("FAILURE", t.toString());                  if (swipeRefreshLayout != null)                     swipeRefreshLayout.setRefreshing(false);             }         });     }      private void refreshData(){         new Handler().post(new Runnable() {             @Override             public void run() {                 cityListAdapter.clear();                 loadData();             }         });     }      @Override     public void onItemClick(int position, View view) {         MovieActivity.start(this, cityListAdapter.getItem(position));     } }  

MovieActivity.java
package example.wim.androidretrofit;  import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.support.annotation.Nullable; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.MenuItem; import android.view.View; import android.widget.Toast;  import java.net.SocketTimeoutException;  import example.wim.androidretrofit.adapter.MovieListAdapter; import example.wim.androidretrofit.listener.RecyclerViewItemClickListener; import example.wim.androidretrofit.model.CityData; import example.wim.androidretrofit.model.Movie; import example.wim.androidretrofit.service.ApiService; import example.wim.androidretrofit.util.DividerItemDecoration; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response;  /**  * Created by Wim on 7/20/16.  */ public class MovieActivity extends AppCompatActivity implements RecyclerViewItemClickListener {      private RecyclerView rvMovie;     private SwipeRefreshLayout swipeRefreshLayout;      private LinearLayoutManager linearLayoutManager;     private MovieListAdapter movieListAdapter;      private ApiService apiService;     private CityData cityData;     private Movie movie;      public static void start(Context context, CityData cityData) {         Intent intent = new Intent(context, MovieActivity.class);         intent.putExtra(MovieActivity.class.getSimpleName(), cityData);         context.startActivity(intent);     }      @Override     protected void onCreate(@Nullable Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_movie);          cityData = getIntent().getParcelableExtra(MovieActivity.class.getSimpleName());          ActionBar actionBar = getSupportActionBar();         actionBar.setTitle(cityData.getKota());         actionBar.setDisplayHomeAsUpEnabled(true);          rvMovie = (RecyclerView) findViewById(R.id.rv_movie);         swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh);          linearLayoutManager = new LinearLayoutManager(this);         movieListAdapter = new MovieListAdapter(this);         movieListAdapter.setRecyclerViewItemClickListener(this);          rvMovie.setLayoutManager(linearLayoutManager);         rvMovie.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));         rvMovie.setAdapter(movieListAdapter);          swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);         swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {             @Override             public void onRefresh() {                 refreshData();             }         });          loadData(cityData.getId());     }      private void loadData(String id){         if (swipeRefreshLayout != null)             swipeRefreshLayout.post(new Runnable() {                 @Override                 public void run() {                     swipeRefreshLayout.setRefreshing(true);                 }             });           apiService = new ApiService();         apiService.getMovieList(id, new Callback() {             @Override             public void onResponse(Call call, Response response) {                 movie = (Movie) response.body();                  if(movie != null){                     if(movie.getStatus().equals("success")) {                         movieListAdapter.addAll(movie.getData());                     }else{                         Toast.makeText(MovieActivity.this, movie.getMessage(), Toast.LENGTH_LONG).show();                     }                     Log.i("STATUS", movie.getStatus());                 }else{                     Toast.makeText(MovieActivity.this, "No Data!", Toast.LENGTH_LONG).show();                 }                  if (swipeRefreshLayout != null)                     swipeRefreshLayout.setRefreshing(false);             }              @Override             public void onFailure(Call call, Throwable t) {                 if(t instanceof SocketTimeoutException) {                     Toast.makeText(MovieActivity.this, "Request Timeout. Please try again!", Toast.LENGTH_LONG).show();                 }else{                     Toast.makeText(MovieActivity.this, "Connection Error!", Toast.LENGTH_LONG).show();                 }                  Log.i("FAILURE", t.toString());                  if (swipeRefreshLayout != null)                     swipeRefreshLayout.setRefreshing(false);             }         });     }      private void refreshData(){         new Handler().post(new Runnable() {             @Override             public void run() {                 movieListAdapter.clear();                 loadData(cityData.getId());             }         });     }      @Override     public void onBackPressed() {         super.onBackPressed();         finish();     }      @Override     public boolean onOptionsItemSelected(MenuItem item) {         switch (item.getItemId()) {             case android.R.id.home:                 finish();                 return true;             default:                 return super.onOptionsItemSelected(item);         }     }      @Override     public void onItemClick(int position, View view) {         ShowtimeActivity.start(this, movieListAdapter.getItem(position), movie.getDate());     } }  
ShowtimeActivity.java
import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.Html; import android.view.MenuItem;  import example.wim.androidretrofit.adapter.ShowtimeListAdapter; import example.wim.androidretrofit.model.MovieData;  /**  * Created by Wim on 7/21/16.  */ public class ShowtimeActivity extends AppCompatActivity {      private RecyclerView rvShowtime;      private LinearLayoutManager linearLayoutManager;     private ShowtimeListAdapter showtimeListAdapter;      private MovieData movieData;     private String date;      public static void start(Context context, MovieData movieData, String date) {         Intent intent = new Intent(context, ShowtimeActivity.class);         intent.putExtra(ShowtimeActivity.class.getSimpleName() + ".movie", movieData);         intent.putExtra(ShowtimeActivity.class.getSimpleName() + ".date", date);         context.startActivity(intent);     }      @Override     protected void onCreate(@Nullable Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_showtime);          movieData = getIntent().getParcelableExtra(ShowtimeActivity.class.getSimpleName() + ".movie");         date = getIntent().getStringExtra(ShowtimeActivity.class.getSimpleName() + ".date");          ActionBar actionBar = getSupportActionBar();         actionBar.setTitle(Html.fromHtml(movieData.getMovie()));         actionBar.setSubtitle(date);         actionBar.setDisplayHomeAsUpEnabled(true);          rvShowtime = (RecyclerView) findViewById(R.id.rv_showtime);          linearLayoutManager = new LinearLayoutManager(this);         showtimeListAdapter = new ShowtimeListAdapter(this);          rvShowtime.setLayoutManager(linearLayoutManager);         rvShowtime.setAdapter(showtimeListAdapter);          showtimeListAdapter.addAll(movieData.getJadwal());     }      @Override     public void onBackPressed() {         super.onBackPressed();         finish();     }      @Override     public boolean onOptionsItemSelected(MenuItem item) {         switch (item.getItemId()) {             case android.R.id.home:                 finish();                 return true;             default:                 return super.onOptionsItemSelected(item);         }     } } 
Langkah terakhir jangan lupa tambahkan permission di AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/> 

Finally, aplikasi kita sudah jadi kini tinggal di build dan running. Berikut screenshotnya :





Source code lengkap sanggup dilihat di https://github.com/andronut/Android-JadwalBioskop21
Sekian tutorial dari saya, agar bermanfaat. :)


*Arigatou*

Comments

Popular posts from this blog

Tugas Komplemen Terakhir

Transmisi Data

Konsep Oop Encapsulation