Untuk kedua kalinya setelah 55 tahun Indonesia akan menjadi tuan rumah pelaksanaan Asian Games 2018. Asian Games 2018 akan dilaksanakan di Jakarta dan Palembang. Baru – baru ini juga sudah diadakan acara Hitung mundur (countdown) Asian Games 2018 di dua kota tersebut. Persiapan diberbagai bidang pun sudah dilakukan. Tak hanya dibidang olahraga dan infrastruktur saja, Kemenkominfo juga akan melakukan persiapan di bidang IT.
Bekerja sama dengan Ericsson, Kemenkominfo akan menciptakan Official App Asian Games 2018. Dan untuk mewujudkan rencana tersebut akan dibuatkan sebuah ajang perlombaan yang bisa diikuti oleh seluruh developer. Terdapat 2 kategori dalam ajang tersebut, untuk detailnya bisa dilihat di link berikut : Sport Digital Experience dan Smart City Digital Service.
Ericsson juga sudah menyediakan API yang dapat diakses secara terbatas oleh developer. Untuk anda yang berminat untuk menggunakan API dari Ericsson untuk mengikuti Challenge ini, anda dapat melakukan registrasi di link berikut dan kami akan memberikan akses kepada developer terpilih. Developer yang terpilih akan mendapatkan akses ke Ericsson Developer Portal. Beberapa kriteria penilaian untuk mendapatkan akses Ericsson Developer Portal adalah :
💻 Mulai Belajar Pemrograman
Belajar pemrograman di Dicoding Academy dan mulai perjalanan Anda sebagai developer profesional.
Daftar Sekarang- Telah lulus dari salah satu kelas di Dicoding Academy.
- Mempunyai minimal 200 XP.
- Aplikasi yang telah disubmit dalam challenge sebelumnya.
Pada artikel ini, kami akan menyediakan tutorial bagaimana caranya menggunakan ENE API untuk pengembangan aplikasi Android. Aplikasi yang akan dikembangkan adalah Asian Games Schedule, yaitu aplikasi untuk melihat jadwal pertandingan Asian Games 2018. Sebelum memasuki langkah – langkah untuk mengembangkan aplikasi tersebut, alangkah lebih baiknya untuk mengenal Ericsson Developer Portal terlebih dahulu.
Pengenalan Ericsson Developer Portal
Ericsson Networked Event (ENE) Developer Portal adalah sebuah portal yang menyediakan open API untuk developer. Ericsson Developer Portal berisi data dummy yang bisa dimanfaatkan oleh developer yang ingin mengembangkan aplikasi untuk Asian Games 2018. Dengan Ericsson Developer Portal, developer akan mendapatkan beberapa informasi mencakup :
- Informasi untuk event Asian Games
- Informasi live dari event Asian Games
- Informasi secara realtime untuk event Asian Games.
Ericsson Developer Portal dapat diakses melalui http://asiangamesdigitalchallenge2017.kemkominfo-ericsson.com/ dengan memasukan username dan password yang sudah diberikan ketika Anda telah berhasil request akses. Terdapat 3 menu utama dari Ericsson Developer Portal yaitu Ericsson Networked Event yang berisi informasi seputar event Asian Games, Safe City untuk integrasi smart city, dan Ericsson Extensions untuk memanfaatkan beberapa layanan ekstensi dari Ericsson.
Ketika memilih Ericsson Networked Event pada halaman utama, maka Anda akan melihat berbagai macam dokumentasi API yang sangat lengkap dan mudah dipahami. Anda bisa memilih beberapa API yang akan digunakan untuk mengembangkan Official App Asian Games 2018. Terdapat 3 kategori dari ENE API yaitu Core Service, Digital Experience dan Sports. Terdapat juga ENE Admin yang bisa digunakan untuk manage data. ENE Admin dapat diakses di alamat http://ene-dicoding.asiangamesdigitalchallenge2017.kemkominfo-ericsson.com/ . Didalam ENE Admin terdapat dashboard yang menyajikan data dummy, Anda juga bisa melakukan update pada data yang sudah ada atau membuat data baru.
Setiap service juga sudah terdapat penjelasan singkat beserta contoh penggunaannya. API service dapat diakses dengan port 6081 dan Anda perlu menambahkan header Basic Auth (‘Authorization Basic {BASE64 ENCODED “USERNAME:PASSWORD”}’) dan ‘Content-Type: application/json’.
Mencoba Service menggunakan Swagger atau Postman
Setelah berkenalan dengan Ericsson Developer Portal, selanjutnya Anda bisa mencoba beberapa service yang tersedia. Klik tombol Open API documentation, maka Anda akan diarahkan ke portal Swagger dan bisa melakukan eksplorisasi dari beberapa service API yang tersedia. Sebelumnya Anda harus memahami Base Url dan PATH dari service yang akan digunakan. Misalkan Anda ingin menggunakan service Event untuk mendapatkan data berupa daftar event yang tersedia, maka alamat lengkapnya adalah Base Url diikuti PATH dari service get all events ( ene-username.asiangamesdigitalchallenge2017.kemkominfo-ericsson.com/api/v2/program/{customer}/events ) dengan method GET.
Anda bisa melihat detail service yang akan digunakan dengan cara klik service tersebut dan Swagger akan menampilkan beberapa informasi mengenai penggunaan service seperti parameter yang harus ditambahkan dan response yang akan didapatkan.
Terdapat juga tombol Try it out untuk mencoba service tersebut. Sebelumnya klik tombol dengan icon gembok, kemudian masukan username dan password Anda.
Klik tombol Try it out dan masukkan beberapa parameter yang dibutuhkan. Terdapat 2 pilihan Response content type, yaitu application/json untuk menampilkan data berupa JSON dan aplication/xml untuk menampilkan data dalam bentuk XML.
Klik tombol execute maka Swagger akan menampilkan respon beserta response code. Jika berhasil maka akan ditampilkan data yang diminta.
Jika Anda ingin mencoba dengan Postman, buka Postman, pilih method GET dan masukkan Request Url, pilih Authentication Basic dan masukkan username beserta password Anda, klik tombol send maka Postman akan melakukan permintaan ke Ericsson Developer Portal, jika berhasil data akan ditampilkan dengan response code 200.
Implementasi ke dalam aplikasi Android
Sebelum masuk ke pembahasan project Android, pastikan Anda sudah menginstall Android Studio versi terbaru. Terdapat beberapa kelas rekomendasi yang bisa Anda pelajari diantaranya adalah Menjadi Android Developer Expert, dan Belajar Membangun Aplikasi Android Native. Langsung saja ikuti langkah – langkah berikut dengan teliti :
- Buat project baru di Android Studio, beri nama project misalnya Asian Games Schedule.
- Tambahkan beberapa library pada build.gradle, disini kita akan menggunakan Retrofit sebagai networking library dan Google Maps API untuk menampilkan maps pada aplikasi (Anda harus membuat credentials untuk aplikasi yang akan dikembangkan. Silahkan ikuti caranya pada link berikut).
123456789101112131415161718//support librariescompile 'com.android.support:appcompat-v7:26.+'compile 'com.android.support:design:26.+'compile 'com.android.support:recyclerview-v7:26.+'compile 'com.android.support:cardview-v7:26.+'//networkingcompile 'com.squareup.retrofit2:retrofit:2.3.0'compile 'com.squareup.retrofit2:converter-gson:2.3.0'compile 'com.squareup.okhttp3:okhttp:3.8.1'compile 'com.google.code.gson:gson:2.7'provided 'org.glassfish:javax.annotation:10.0-b28'//othercompile 'com.github.bumptech.glide:glide:3.7.0'compile 'com.google.android.gms:play-services-maps:11.0.4'compile 'com.jakewharton:butterknife:8.8.1'apt 'com.jakewharton:butterknife-compiler:8.8.1' - Tambahkan Internet permission dan meta-data untuk Google Maps API key pada AndroidManifest.xml. Jangan lupa ganti “YOUR_API_KEY” dengan API KEY yang Anda dapatkan dari Google Maps APIs.
1234567891011121314151617181920212223242526272829303132<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.dicoding.asiangamesschedule"><uses-permission android:name="android.permission.INTERNET" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".home.HomeActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activityandroid:theme="@style/AppTheme.NoActionBar"android:name=".detail.EventDetailActivity"/><meta-dataandroid:name="com.google.android.maps.v2.API_KEY"android:value="Your_API_Key"/><meta-dataandroid:name="com.google.android.gms.version"android:value="@integer/google_play_services_version"/></application></manifest> - Buat package networking pada project Anda dan buatlah class baru dengan nama ApiService.Java yang akan diisi dengan beberapa method untuk request ke API service.
12345678910111213141516171819package com.dicoding.asiangamesschedule.networking;import com.dicoding.asiangamesschedule.model.EventResponse;import java.util.List;import retrofit2.Call;import retrofit2.http.GET;import retrofit2.http.Path;import retrofit2.http.Query;public interface ApiService {@GET("v2/program/testCustomer/events")Call<List<EventResponse>> getEventList();@GET("v2/program/testCustomer/events/{eventid}")Call<EventResponse> getEventById(@Path("eventid") int eventid);} - Masih didalam package networking, buat class baru dengan nama ApiBuilder.Java. Class ini berisi Retrofit Builder dengan menggunakan Interceptor dari OkHttp.
12345678910111213141516171819202122232425262728293031323334package com.dicoding.asiangamesschedule.networking;import java.io.IOException;import okhttp3.Interceptor;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.Response;import retrofit2.Retrofit;import retrofit2.converter.gson.GsonConverterFactory;public class ApiBuilder {public static ApiService call(){OkHttpClient.Builder httpClient = new OkHttpClient.Builder().addInterceptor(new Interceptor() {@Overridepublic Response intercept(Chain chain) throws IOException {Request original = chain.request();Request request = original.newBuilder().header("Content-Type", "application/json").header("Authorization", "Basic YOUR_TOKEN").removeHeader("Pragma").build();return chain.proceed(request);}});Retrofit retrofit = new Retrofit.Builder().baseUrl("http://ene-dicoding.asiangamesdigitalchallenge2017.kemkominfo-ericsson.com/api/").addConverterFactory(GsonConverterFactory.create()).client(httpClient.build()).build();return retrofit.create(ApiService.class);}}
Anda harus memasukan header Authorization dan Base Url dari Ericsson Developer Portal. Header Authorization memiliki format “Authorization : Basic token Anda”. Untuk mengetahui token dari akun Ericsson Developer Portal, buka history API request Anda pada Postman yang sudah dicontohkan diatas dan pilih Headers, maka akan terlihat token Anda. - Buat package baru dengan nama model dan tambahkan beberapa class baru berisi POJO (Plain Old Java Object) berikut :
EventResponse.Java
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465package com.dicoding.asiangamesschedule.model;import java.util.List;import com.google.gson.annotations.Expose;import com.google.gson.annotations.SerializedName;public class EventResponse {@SerializedName("arenas")@Exposeprivate List<Arena> arenas = null;@SerializedName("description")@Exposeprivate String description;@SerializedName("endTime")@Exposeprivate String endTime;@SerializedName("id")@Exposeprivate int id;@SerializedName("imageUrl")@Exposeprivate Object imageUrl;@SerializedName("name")@Exposeprivate String name;@SerializedName("startTime")@Exposeprivate String startTime;@SerializedName("subEvents")@Exposeprivate List<SubEvent> subEvents = null;public List<Arena> getArenas() {return arenas;}public String getDescription() {return description;}public String getEndTime() {return endTime;}public int getId() {return id;}public Object getImageUrl() {return imageUrl;}public String getName() {return name;}public String getStartTime() {return startTime;}public List<SubEvent> getSubEvents() {return subEvents;}}
Arena.Java
1234567891011121314151617181920212223242526272829package com.dicoding.asiangamesschedule.model;import com.google.gson.annotations.Expose;import com.google.gson.annotations.SerializedName;public class Arena {@SerializedName("address")@Exposeprivate String address;@SerializedName("id")@Exposeprivate int id;@SerializedName("name")@Exposeprivate String name;public String getAddress() {return address;}public int getId() {return id;}public String getName() {return name;}}
SubEvent.Java
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657package com.dicoding.asiangamesschedule.model;import java.util.List;import com.google.gson.annotations.Expose;import com.google.gson.annotations.SerializedName;public class SubEvent {@SerializedName("arenas")@Exposeprivate List<Arena> arenas = null;@SerializedName("description")@Exposeprivate String description;@SerializedName("endTime")@Exposeprivate String endTime;@SerializedName("id")@Exposeprivate int id;@SerializedName("imageUrl")@Exposeprivate Object imageUrl;@SerializedName("name")@Exposeprivate String name;@SerializedName("startTime")@Exposeprivate String startTime;@SerializedName("subEvents")@Exposeprivate List<Object> subEvents = null;public List<Arena> getArenas() {return arenas;}public String getEndTime() {return endTime;}public int getId() {return id;}public Object getImageUrl() {return imageUrl;}public String getName() {return name;}public String getStartTime() {return startTime;}} - Buat package baru dengan nama home dan tambahkan activity baru dengan nama HomeActivity didalamnya. Buka activity_home.xml dan rancang layout dengan menambahkan ProggressBar dan RecyclerView untuk menampilkan list data.
12345678910111213141516171819202122232425<?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:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/colorGrey"tools:context="com.dicoding.asiangamesschedule.home.HomeActivity"android:orientation="vertical"><ProgressBarandroid:id="@+id/progressBar"style="?android:attr/progressBarStyleInverse"android:layout_gravity="center"android:layout_width="wrap_content"android:layout_height="wrap_content"/><android.support.v7.widget.RecyclerViewandroid:id="@+id/list_event"android:layout_width="match_parent"android:layout_height="wrap_content"android:divider="#00000000"android:layout_margin="16dp"/></LinearLayout> - Buat layout baru dengan nama event_list.xml untuk merancang desain CardView.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.CardViewxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="8dp"android:background="?android:selectableItemBackground"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><ImageViewandroid:id="@+id/event_image"android:layout_width="match_parent"android:layout_height="150dp"android:src="@drawable/bg"android:scaleType="centerCrop"android:tint="@color/bgTint"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:padding="10dp"android:orientation="vertical"><TextViewandroid:id="@+id/event_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textStyle="bold"android:textSize="18sp"/><TextViewandroid:id="@+id/time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center"android:maxLines="1"android:ellipsize="end"android:drawableStart="@drawable/ic_date_range"android:drawableLeft="@drawable/ic_date_range" /><TextViewandroid:id="@+id/arena"android:layout_width="wrap_content"android:layout_height="wrap_content"android:drawableLeft="@drawable/ic_place"android:drawableStart="@drawable/ic_place"android:gravity="center"/></LinearLayout></LinearLayout></android.support.v7.widget.CardView> - Buat class EventAdapter.Java pada package home untuk implementasi RecyclerView Adapter yang berguna untuk menampilkan data pada RecyclerView.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889package com.dicoding.asiangamesschedule.home;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.ImageView;import android.widget.TextView;import com.bumptech.glide.Glide;import com.bumptech.glide.load.engine.DiskCacheStrategy;import com.dicoding.asiangamesschedule.R;import com.dicoding.asiangamesschedule.model.EventResponse;import java.util.List;public class EventAdapter extends RecyclerView.Adapter<EventAdapter.ViewHolder> {private final OnItemClickListener listener;private List<EventResponse> data;private Context context;public EventAdapter(Context context, List<EventResponse> data, OnItemClickListener listener) {this.data = data;this.listener = listener;this.context = context;}@Overridepublic EventAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.event_list, parent, false);return new ViewHolder(view);}@Overridepublic void onBindViewHolder(EventAdapter.ViewHolder holder, int position) {holder.click(data.get(position), listener);holder.textEventName.setText(data.get(position).getName());holder.textArena.setText(data.get(position).getArenas().get(0).getName());Timestamp startStamp = new Timestamp(Long.parseLong(data.get(position).getStartTime()));Timestamp endStamp = new Timestamp(Long.parseLong(data.get(position).getEndTime()));Date startDate = new Date(startStamp.getTime());Date endDate = new Date(endStamp.getTime());SimpleDateFormat formatDate = new SimpleDateFormat("EEE, dd MMM yyyy, hh:mm");holder.textTime.setText(formatDate.format(startDate) + " - " + formatDate.format(endDate));Object images = data.get(position).getImageUrl();Glide.with(context).load(images).diskCacheStrategy(DiskCacheStrategy.SOURCE).skipMemoryCache(true).into(holder.imageEvent);}@Overridepublic int getItemCount() {return data.size();}public interface OnItemClickListener {void onClick(EventResponse Item);}public class ViewHolder extends RecyclerView.ViewHolder {TextView textEventName;TextView textTime;TextView textArena;ImageView imageEvent;public ViewHolder(View itemView) {super(itemView);textEventName = itemView.findViewById(R.id.event_name);textTime = itemView.findViewById(R.id.time);textArena = itemView.findViewById(R.id.arena);imageEvent = itemView.findViewById(R.id.event_image);}public void click(final EventResponse eventResponseData, final OnItemClickListener listener) {itemView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {listener.onClick(eventResponseData);}});}}} - Buat interface HomeView.Java pada package home.
123456789101112package com.dicoding.asiangamesschedule.home;import com.dicoding.asiangamesschedule.model.EventResponse;import java.util.List;import retrofit2.Response;public interface HomeView {void setVisibilityProgressBar(int visibility);void getEventListSuccess(Response<List<EventResponse>> response);} - Buat class HomePresenter.Java pada package home berisi logic untuk memanggil API Service dengan method getEventList().
123456789101112131415161718192021222324252627282930313233343536373839404142package com.dicoding.asiangamesschedule.home;import android.content.Context;import android.util.Log;import android.view.View;import com.dicoding.asiangamesschedule.model.EventResponse;import com.dicoding.asiangamesschedule.networking.ApiBuilder;import com.dicoding.asiangamesschedule.networking.ApiService;import java.util.List;import retrofit2.Call;import retrofit2.Callback;import retrofit2.Response;public class HomePresenter {private final HomeView homeView;private final Context context;public HomePresenter(Context context, HomeView homeView) {this.context = context;this.homeView = homeView;}public void getEventList() {ApiService service = ApiBuilder.call();service.getEventList().enqueue(new Callback<List<EventResponse>>() {@Overridepublic void onResponse(Call<List<EventResponse>> call, Response<List<EventResponse>> response) {homeView.setVisibilityProgressBar(View.GONE);homeView.getEventListSuccess(response);}@Overridepublic void onFailure(Call<List<EventResponse>> call, Throwable t) {homeView.setVisibilityProgressBar(View.GONE);}});}} - Buka HomeActivity.Java dan implementasikan HomeView serta inisialisasikan HomePresenter, sehingga kode lengkapnya seperti berikut.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071package com.dicoding.asiangamesschedule.home;import android.content.Context;import android.content.Intent;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;import android.widget.ProgressBar;import com.dicoding.asiangamesschedule.R;import com.dicoding.asiangamesschedule.detail.EventDetailActivity;import com.dicoding.asiangamesschedule.model.EventResponse;import java.util.List;import butterknife.BindView;import butterknife.ButterKnife;public class HomeActivity extends AppCompatActivity implements HomeView {@BindView(R.id.list_event)RecyclerView eventList;@BindView(R.id.progressBar)ProgressBar progressBar;private HomePresenter presenter;private Context context;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_home);ButterKnife.bind(this);initializePresenter();}private void initializePresenter() {context = this;presenter = new HomePresenter(context, this);presenter.getEventList();}@Overridepublic void setVisibilityProgressBar(int visibility) {switch (visibility) {case View.GONE:progressBar.setVisibility(visibility);eventList.setVisibility(View.VISIBLE);eventList.scrollToPosition(0);break;case View.VISIBLE:progressBar.setVisibility(visibility);eventList.setVisibility(View.GONE);break;}}@Overridepublic void getEventListSuccess(final retrofit2.Response<List<EventResponse>> response) {EventAdapter adapter = new EventAdapter(getApplicationContext(), response.body(), new EventAdapter.OnItemClickListener() {@Overridepublic void onClick(EventResponse Item) {Intent intent = new Intent(HomeActivity.this, EventDetailActivity.class);intent.putExtra("id", Item.getId());startActivity(intent);}});eventList.setLayoutManager(new LinearLayoutManager(this));eventList.setAdapter(adapter);}} - Buat package baru dengan nama detail dan tambahkan activity baru dengan nama EventDetailActivity didalamnya. Buka activity_event_detail.xml dan rancang layout dengan kode xml berikut.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170<?xml version="1.0" encoding="utf-8"?><android.support.design.widget.CoordinatorLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"android:id="@+id/coordinatorLayout"android:background="@color/colorBackgroundLight"tools:context=".detail.EventDetailActivity"><android.support.design.widget.AppBarLayoutandroid:layout_width="match_parent"android:layout_height="256dp"android:fitsSystemWindows="true"android:id="@+id/appbarLayout"android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"><android.support.design.widget.CollapsingToolbarLayoutandroid:id="@+id/collapsingToolbar"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"app:collapsedTitleGravity="start"app:contentScrim="?attr/colorPrimary"app:layout_scrollFlags="scroll|exitUntilCollapsed"><ImageViewandroid:id="@+id/headerImage"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"android:scaleType="centerCrop"app:layout_collapseParallaxMultiplier="0.7"app:layout_collapseMode="parallax"/><Viewandroid:layout_gravity="bottom"android:background="@color/colorGrey600"android:alpha="0.5"android:fitsSystemWindows="true"android:layout_width="fill_parent"android:layout_height="70dip" /><android.support.v7.widget.Toolbarandroid:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:id="@+id/toolbar"app:popupTheme="@style/ThemeOverlay.AppCompat.Light"app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" /></android.support.design.widget.CollapsingToolbarLayout></android.support.design.widget.AppBarLayout><android.support.v4.widget.NestedScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="@string/appbar_scrolling_view_behavior"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:clipToPadding="false"android:paddingLeft="10dp"android:paddingRight="10dp"android:paddingBottom="20dp"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:paddingBottom="5dp"android:text="@string/when"android:textSize="18sp"android:textColor="@color/primaryText"/><Viewandroid:layout_width="20dp"android:layout_height="2dp"android:background="@color/colorPrimary"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/time"android:layout_marginTop="10dp"android:textSize="16sp"android:textColor="@color/secondaryText"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:paddingBottom="5dp"android:text="@string/description"android:textSize="18sp"android:textColor="@color/primaryText"/><Viewandroid:layout_width="20dp"android:layout_height="2dp"android:background="@color/colorPrimary"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/description"android:layout_marginTop="10dp"android:textSize="16sp"android:textColor="@color/secondaryText"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="25dp"android:paddingBottom="5dp"android:text="@string/arena"android:textSize="18sp"android:textColor="@color/primaryText"/><Viewandroid:layout_width="20dp"android:layout_height="2dp"android:background="@color/colorPrimary"/><fragmentandroid:layout_width="match_parent"android:layout_height="240dp"android:layout_marginTop="16dp"android:id="@+id/map_view"tools:context=".destination.detail.DestinationDetailActivity"android:name="com.google.android.gms.maps.SupportMapFragment" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="25dp"android:paddingBottom="5dp"android:text="@string/sub_event"android:textSize="18sp"android:textColor="@color/primaryText"/><Viewandroid:layout_width="20dp"android:layout_height="2dp"android:background="@color/colorPrimary"/><TextViewandroid:id="@+id/text_no_data"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:text="@string/no_data"android:textColor="@color/secondaryText"/><android.support.v7.widget.RecyclerViewandroid:id="@+id/list_sub_event"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:divider="#00000000"/></LinearLayout></android.support.v4.widget.NestedScrollView></android.support.design.widget.CoordinatorLayout> - Buat layout baru dengan nama sub_event_list.xml yang akan digunakan untuk menampilkan data sub event.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.CardViewxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="250dp"android:layout_height="wrap_content"android:layout_marginRight="5dp"android:layout_marginEnd="5dp"android:background="?android:selectableItemBackground"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><ImageViewandroid:id="@+id/event_image"android:layout_width="match_parent"android:layout_height="100dp"android:src="@drawable/bg"android:scaleType="centerCrop"android:tint="@color/bgTint"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:padding="5dp"android:orientation="vertical"><TextViewandroid:id="@+id/event_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textStyle="bold"android:textSize="16sp"/><TextViewandroid:id="@+id/time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:maxLines="1"android:ellipsize="end"android:gravity="center"android:textSize="14sp"android:drawableStart="@drawable/ic_date_range"android:drawableLeft="@drawable/ic_date_range" /><TextViewandroid:id="@+id/arena"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="14sp"android:drawableLeft="@drawable/ic_place"android:drawableStart="@drawable/ic_place"android:gravity="center"/></LinearLayout></LinearLayout></android.support.v7.widget.CardView> - Buat class SubEventAdapter.Java pada package detail untuk implementasi RecyclerView Adapter yang berguna untuk menampilkan data sub event pada RecyclerView.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091package com.dicoding.asiangamesschedule.detail;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.ImageView;import android.widget.TextView;import com.bumptech.glide.Glide;import com.bumptech.glide.load.engine.DiskCacheStrategy;import com.dicoding.asiangamesschedule.R;import com.dicoding.asiangamesschedule.model.EventResponse;import com.dicoding.asiangamesschedule.model.SubEvent;import java.util.ArrayList;import java.util.List;public class SubEventAdapter extends RecyclerView.Adapter<SubEventAdapter.ViewHolder> {private final OnItemClickListener listener;private List<SubEvent> data;private Context context;public SubEventAdapter(Context context, List<SubEvent> data, OnItemClickListener listener) {this.data = data;this.listener = listener;this.context = context;}@Overridepublic SubEventAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.sub_event_list, parent, false);return new ViewHolder(view);}@Overridepublic void onBindViewHolder(SubEventAdapter.ViewHolder holder, int position) {holder.click(data.get(position), listener);holder.textEventName.setText(data.get(position).getName());holder.textArena.setText(data.get(position).getArenas().get(0).getName());Timestamp startStamp = new Timestamp(Long.parseLong(data.get(position).getStartTime()));Timestamp endStamp = new Timestamp(Long.parseLong(data.get(position).getEndTime()));Date startDate = new Date(startStamp.getTime());Date endDate = new Date(endStamp.getTime());SimpleDateFormat formatDate = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm");holder.textTime.setText(formatDate.format(startDate) + " - " + formatDate.format(endDate));Object images = data.get(position).getImageUrl();Glide.with(context).load(images).diskCacheStrategy(DiskCacheStrategy.SOURCE).skipMemoryCache(true).into(holder.imageEvent);}@Overridepublic int getItemCount() {return data.size();}public interface OnItemClickListener {void onClick(SubEvent Item);}public class ViewHolder extends RecyclerView.ViewHolder {TextView textEventName;TextView textTime;TextView textArena;ImageView imageEvent;public ViewHolder(View itemView) {super(itemView);textEventName = itemView.findViewById(R.id.event_name);textTime = itemView.findViewById(R.id.time);textArena = itemView.findViewById(R.id.arena);imageEvent = itemView.findViewById(R.id.event_image);}public void click(final SubEvent subEventData, final OnItemClickListener listener) {itemView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {listener.onClick(subEventData);}});}}} - Buat interface EventDetailView.Java pada package detail.
123456789101112131415161718package com.dicoding.asiangamesschedule.detail;import com.dicoding.asiangamesschedule.model.EventResponse;import java.util.List;import retrofit2.Response;public interface EventDetailView {void showProgressDialog();void hideProgressDialog();void setVisibilityNoData (int visibility);void getEventDetail(Response<EventResponse> response);} - Buat class EventDetailPresenter.Java pada package detail berisi logic untuk memanggil API Service dengan method getEventDetail().
1234567891011121314151617181920212223242526272829303132333435363738394041424344package com.dicoding.asiangamesschedule.detail;import android.content.Context;import android.util.Log;import android.view.View;import com.dicoding.asiangamesschedule.model.EventResponse;import com.dicoding.asiangamesschedule.networking.ApiBuilder;import com.dicoding.asiangamesschedule.networking.ApiService;import retrofit2.Call;import retrofit2.Callback;import retrofit2.Response;public class EventDetailPresenter {private final EventDetailView view;private final Context context;public EventDetailPresenter(Context context, EventDetailView view) {this.context = context;this.view = view;}public void getEventDetail(int id) {view.showProgressDialog();ApiService service = ApiBuilder.call();service.getEventById(id).enqueue(new Callback<EventResponse>() {@Overridepublic void onResponse(Call<EventResponse> call, Response<EventResponse> response) {view.hideProgressDialog();view.getEventDetail(response);if (response.body().getSubEvents().size() != 0){view.setVisibilityNoData(View.GONE);}}@Overridepublic void onFailure(Call<EventResponse> call, Throwable t) {view.hideProgressDialog();}});}} - Buka EventDetailActivity.Java dan implementasikan EventDetailView serta inisialisasikan EventDetailPresenter, sehingga kode lengkapnya seperti berikut.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156package com.dicoding.asiangamesschedule.detail;import android.app.Activity;import android.app.ProgressDialog;import android.content.Context;import android.content.Intent;import android.support.design.widget.CollapsingToolbarLayout;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.Toolbar;import android.util.Log;import android.view.MenuItem;import android.view.View;import android.widget.ImageView;import android.widget.TextView;import com.bumptech.glide.Glide;import com.bumptech.glide.load.engine.DiskCacheStrategy;import com.dicoding.asiangamesschedule.R;import com.dicoding.asiangamesschedule.home.EventAdapter;import com.dicoding.asiangamesschedule.home.HomeActivity;import com.dicoding.asiangamesschedule.model.EventResponse;import com.dicoding.asiangamesschedule.model.SubEvent;import com.google.android.gms.maps.CameraUpdateFactory;import com.google.android.gms.maps.GoogleMap;import com.google.android.gms.maps.OnMapReadyCallback;import com.google.android.gms.maps.SupportMapFragment;import com.google.android.gms.maps.model.LatLng;import com.google.android.gms.maps.model.MarkerOptions;import butterknife.BindView;import butterknife.ButterKnife;import retrofit2.Response;public class EventDetailActivity extends AppCompatActivity implements EventDetailView, OnMapReadyCallback {private EventDetailPresenter presenter;private Context context;private int id;private String[] latLng;private String arenaName;private ProgressDialog progressDialog;@BindView(R.id.list_sub_event)RecyclerView subEventList;@BindView(R.id.headerImage)ImageView headerImage;@BindView(R.id.description)TextView textDescription;@BindView(R.id.toolbar)Toolbar mToolbar;@BindView(R.id.collapsingToolbar)CollapsingToolbarLayout collapsingToolbarLayout;@BindView(R.id.text_no_data)TextView textNoData;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_event_detail);ButterKnife.bind(this);progressDialog = new ProgressDialog(this);setSupportActionBar(mToolbar);id = getIntent().getIntExtra("id", 0);initializePresenter();}private void initializePresenter() {context = this;presenter = new EventDetailPresenter(context, this);presenter.getEventDetail(id);}@Overridepublic void showProgressDialog() {progressDialog = loadingDialog(this);}@Overridepublic void hideProgressDialog() {progressDialog.dismiss();}protected static ProgressDialog loadingDialog(Activity activity) {final ProgressDialog dialog = new ProgressDialog(activity);dialog.setMessage("Loading. Please wait...");dialog.setCancelable(false);dialog.show();return dialog;}@Overridepublic void setVisibilityNoData (int visibility) {switch (visibility) {case View.GONE:textNoData.setVisibility(visibility);break;case View.VISIBLE:textNoData.setVisibility(visibility);break;}}@Overridepublic void getEventDetail(Response<EventResponse> response) {latLng = response.body().getArenas().get(0).getAddress().split(",");arenaName = response.body().getArenas().get(0).getName();collapsingToolbarLayout.setTitle(response.body().getName());collapsingToolbarLayout.setExpandedTitleMargin(50,50,250,50);Glide.with(context).load(response.body().getImageUrl()).diskCacheStrategy(DiskCacheStrategy.SOURCE).skipMemoryCache(true).into(headerImage);Timestamp startStamp = new Timestamp(Long.parseLong(response.body().getStartTime()));Timestamp endStamp = new Timestamp(Long.parseLong(response.body().getEndTime()));Date startDate = new Date(startStamp.getTime());Date endDate = new Date(endStamp.getTime());SimpleDateFormat formatDate = new SimpleDateFormat("EEE, dd MMM yyyy, hh:mm");textTime.setText(formatDate.format(startDate) + " - " + formatDate.format(endDate));textDescription.setText(response.body().getDescription());SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map_view);mapFragment.getMapAsync(EventDetailActivity.this);SubEventAdapter adapter = new SubEventAdapter(getApplicationContext(), response.body().getSubEvents(), new SubEventAdapter.OnItemClickListener() {@Overridepublic void onClick(SubEvent Item) {Intent intent = new Intent(EventDetailActivity.this, EventDetailActivity.class);intent.putExtra("id", Item.getId());startActivity(intent);}});subEventList.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));subEventList.setAdapter(adapter);}@Overridepublic void onMapReady(GoogleMap googleMap) {if (latLng!=null){LatLng location = new LatLng(Double.parseDouble(latLng[0]), Double.parseDouble(latLng[1]));googleMap.addMarker(new MarkerOptions().position(location).title(arenaName));googleMap.moveCamera(CameraUpdateFactory.newLatLng(location));googleMap.animateCamera( CameraUpdateFactory.zoomTo( 13.0f ) );}}} - Jalankan project Anda pada Android device atau emulator.
Anda telah belajar bagaimana cara memanfaatkan ENE API dengan mengimplementasikannya kedalam sebuah aplikasi Android. Untuk source code dari tutorial ini bisa diunduh pada link berikut. Silahkan kembangkan aplikasi versi Anda sendiri untuk Asian Games 2018 dengan kreatifitas dan jangan lupa submit aplikasi Anda pada challenges Sport Digital Experience atau Smart City Digital Service.
Jika ada pertanyaan silahkan tulis di kolom komentar. Goodluck dan semoga Anda lah salah satu pemenang dan berhak mendapatkan 1 hadiah utama berupa perjalanan ke Ericsson Studio dan Ericsson Garage di Swedia.