Pada tutorial kali ini kita akan belajar bagaimana cara menampilkan list kontak Rainbow pada Android Apps. Tapi sebelum lanjut ke tutorial pastikan kamu sudah membaca tutorial sebelumnya tentang bagaimana Cara Integrasi Rainbow API pada Android Apps.
Di tutorial ini kita akan menggunakan Rainbow SDK untuk menampilkan list kontak Rainbow. Kenapa? Dengan Rainbow SDK, kita bisa melihat langsung perubahan pada kontak secara real time seperti berikut :
💻 Mulai Belajar Pemrograman
Belajar pemrograman di Dicoding Academy dan mulai perjalanan Anda sebagai developer profesional.
Daftar SekarangPembuatan Project
Buatlah project baru di Android Studio, lalu buka berkas (file) build.gradle dan ubah menjadi seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
apply plugin: 'com.android.application' android { compileSdkVersion 27 defaultConfig { ... } buildTypes { ... } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } allprojects { repositories { maven { url "http://maven.openrainbow.io" } } } dependencies { implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support:exifinterface:27.1.1' implementation 'com.android.support:support-v4:27.1.1' implementation 'com.android.support:recyclerview-v7:27.1.1' implementation 'com.ale:rainbowsdk:1.42.0' implementation 'de.hdodenhof:circleimageview:2.2.0' } |
Untuk menampilkan list kontak kita akan menggunakan RecyclerView. Next, lakukan sinkronisasi project dengan menekan tombol Sync Now. Setelah selesai, buatlah kelas baru yang akan digunakan untuk inisialisasi Rainbow seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class App extends Application { @Override public void onCreate() { super.onCreate(); RainbowSdk.instance().setNotificationBuilder(getApplicationContext(), MainActivity.class, R.drawable.ic_launcher_background, getString(R.string.app_name), "Connect to the app", Color.RED); RainbowSdk.instance().initialize(); } } |
Jangan lupa untuk mendaftarkan kelas tersebut dan menambahkan beberapa permission kedalam berkas (file) AndroidManifest.xml seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.dicoding.rainbowsdkx"> <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.CALL_PHONE"/> <application android:name=".App" android: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=".activity.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".activity.ContactsActivity"/> </application> </manifest> |
Struktur kelas dan package dari project kali ini akan seperti berikut :
Komponen Rainbow
Yang pertama kita buat adalah kelas untuk komponen Rainbow, pada komponen Rainbow akan ada dua kelas yang dibuat. Kelas pertama yaitu kelas RainbowConnectionListener seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class RainbowConnectionLister { public interface Connection { void onConnectionSuccess(); void onConnectionFailed(String error); } public interface Login { void onSignInSuccess(); void onSignInFailed(String error); } } |
Pada kelas RainbowConnectionListener di atas terdapat beberapa interfaces yang akan digunakan sebagai Callback Listener dari kelas berikutnya yaitu RainbowConnection. Isi dari kelas RainbowConnection adalah seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
public class RainbowConnection { public static void startConnection(RainbowConnectionLister.Connection connection) { RainbowSdk.instance().connection().start(new StartResponseListener() { @Override public void onStartSucceeded() { new Handler(Looper.getMainLooper()).post(connection::onConnectionSuccess); } @Override public void onRequestFailed(RainbowSdk.ErrorCode errorCode, String s) { new Handler(Looper.getMainLooper()).post(() -> connection.onConnectionFailed(s)); } }); } public static void startSignIn(String email, String password, RainbowConnectionLister.Login login) { RainbowSdk.instance().connection().signin(email, password, "sandbox.openrainbow.com", new SigninResponseListener() { @Override public void onSigninSucceeded() { new Handler(Looper.getMainLooper()).post(login::onSignInSuccess); } @Override public void onRequestFailed(RainbowSdk.ErrorCode errorCode, String s) { new Handler(Looper.getMainLooper()).post(() -> login.onSignInFailed(s)); } }); } public static void registerAllContact(Contact.ContactListener listener) { for (IRainbowContact contact : getRainbowContacts()) { contact.registerChangeListener(listener); } } public static void unregisterAllContact(Contact.ContactListener listener) { for (IRainbowContact contact : getRainbowContacts()) { contact.unregisterChangeListener(listener); } } public static List<IRainbowContact> getRainbowContacts(){ return RainbowSdk.instance().contacts().getRainbowContacts().getCopyOfDataList(); } public static String getUserLoginInCache(){ return RainbowSdk.instance().myProfile().getUserLoginInCache(); } public static String getUserPasswordInCache(){ return RainbowSdk.instance().myProfile().getUserPasswordInCache(); } } |
Di dalam kelas RainbowConnection terdapat beberapa static method dengan detail fungsi sebagai berikut :
- startConnection()
Menjalankan service Rainbow agar fungsi seperti Sign In bisa digunakan. - startSignIn()
Masuk / Sign In (masuk) ke platform Rainbow. - registerAllContact()
Mendaftarkan semua kontak ke dalam listener agar jika terjadi perubahan dapat langsung ditampilkan secara realtime. - unregisterAllContact()
Menghapus kontak yang terdaftar pada listener agar tidak terjadi Leaks (kebocoran) pada memory. - getRainbowContacts()
Mendapatkan seluruh kontak pengguna yang telah melakukan Sign In. - getUserLoginInCache()
Mendapatkan email pengguna yang tersimpan di dalam cache. - getUserPasswordInCache()
Mendapatkan password pengguna yang tersimpan di dalam cache.
Penggunaan komponen Handler pada fungsi start() dan fungsi sign() bertujuan agar komponen yang berjalan pada UI Thread bisa dipanggil dan dijalankan. Sebabnya, Callback Listener dari beberapa fungsi Rainbow SDK masih berada pada Background Thread.
Untuk mendapatkan list kontak kita menggunakan module Contacts pada SDK yang detailnya bisa dibaca pada tautan berikut https://hub.openrainbow.com/#/documentation/doc/sdk/android/modules/Contacts.
Komponen Common
Pada komponen common hanya terdapat satu kelas, yaitu kelas Utils yang hanya memiliki satu static method seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 |
public class Utils { public static void hideSoftKey(View view) { if (view.getContext() != null) { InputMethodManager iml = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); if (iml != null) { iml.hideSoftInputFromWindow(view.getWindowToken(), 0); } } } } |
Komponen Adapter
Pada komponen adapter yang pertama dibuat adalah sebuah layout. Ini akan digunakan untuk menampilkan data tiap kontak seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="10dp"> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <de.hdodenhof.circleimageview.CircleImageView android:id="@+id/ivBadge" android:layout_width="60dp" android:layout_height="60dp" android:layout_gravity="center_vertical" android:visibility="gone" /> <RelativeLayout android:id="@+id/rlBadge" android:layout_width="60dp" android:layout_height="60dp" android:layout_gravity="center_vertical" android:background="@drawable/bg_circle"> <TextView android:id="@+id/tvBadge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textColor="#fff" android:textSize="20sp" tools:text="AA" /> </RelativeLayout> <ImageView android:id="@+id/ivPresenceStatus" android:layout_width="15dp" android:layout_height="15dp" android:layout_alignBottom="@id/rlBadge" android:layout_alignEnd="@id/rlBadge" android:background="#ff0000"/> </RelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginStart="16sp" android:orientation="vertical"> <TextView android:id="@+id/tvUsername" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:textStyle="bold" tools:text="First & Last Name" /> <TextView android:id="@+id/tvPresence" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:textSize="15sp" android:textStyle="italic" tools:text="Presence" /> </LinearLayout> </LinearLayout> </LinearLayout> |
Layout di atas memiliki beberapa widget TextView, satu widget ImageView dan satu widget Custom ImageView.
Selanjutnya kita akan membuat kelas holder yang akan digunakan untuk merender tampilan ke aplikasi seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
public class ContactHolder extends RecyclerView.ViewHolder { private ImageView ivBagde; private ImageView ivPresenceStatus; private RelativeLayout rlBadge; private TextView tvBadge; private TextView tvUsername; private TextView tvPresense; public ContactHolder(View itemView) { super(itemView); ivBagde = itemView.findViewById(R.id.ivBadge); ivPresenceStatus = itemView.findViewById(R.id.ivPresenceStatus); rlBadge = itemView.findViewById(R.id.rlBadge); tvBadge = itemView.findViewById(R.id.tvBadge); tvUsername = itemView.findViewById(R.id.tvUsername); tvPresense = itemView.findViewById(R.id.tvPresence); } public void bindContent(IRainbowContact contact) { Bitmap userAvatar = contact.getPhoto(); String firstName = contact.getFirstName(); String lastName = contact.getLastName(); tvUsername.setText(firstName + " " + lastName); RainbowPresence presence = contact.getPresence(); switch (presence) { case ONLINE: tvPresense.setText("Online"); ivPresenceStatus.setImageDrawable(new ColorDrawable(Color.GREEN)); break; case OFFLINE: tvPresense.setText("Offline"); ivPresenceStatus.setImageDrawable(new ColorDrawable(Color.GRAY)); break; case MOBILE_ONLINE: tvPresense.setText("On Mobile"); ivPresenceStatus.setImageDrawable(new ColorDrawable(Color.BLUE)); break; case AWAY: tvPresense.setText("Away"); ivPresenceStatus.setImageDrawable(new ColorDrawable(Color.YELLOW)); break; case MANUAL_AWAY: tvPresense.setText("Away"); ivPresenceStatus.setImageDrawable(new ColorDrawable(Color.YELLOW)); break; case BUSY: tvPresense.setText("Busy"); ivPresenceStatus.setImageDrawable(new ColorDrawable(Color.CYAN)); break; case DND: tvPresense.setText("Do Not Disturb"); ivPresenceStatus.setImageDrawable(new ColorDrawable(Color.RED)); break; case DND_PRESENTATION: tvPresense.setText("Presenting"); ivPresenceStatus.setImageDrawable(new ColorDrawable(Color.RED)); break; } if (userAvatar != null) { rlBadge.setVisibility(View.INVISIBLE); ivBagde.setVisibility(View.VISIBLE); ivBagde.setImageBitmap(userAvatar); } else { rlBadge.setVisibility(View.VISIBLE); ivBagde.setVisibility(View.INVISIBLE); String first = String.valueOf(firstName.charAt(0)); String last = String.valueOf(lastName.charAt(0)); tvBadge.setText(first.toUpperCase() + last.toUpperCase()); } } } |
Fungsi switch statement di atas adalah untuk mengecek status kontak apakah sedang online, offline atau yang lainya.
Terakhir adalah pembuatan kelas adapter. Kelas adapter sendiri akan digunakan untuk menjembatani data yang akan ditampilkan dengan antarmuka aplikasi. Kode dari kelas adapter adalah seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
public class ContactAdapter extends RecyclerView.Adapter<ContactHolder> { private List<IRainbowContact> contacts; public ContactAdapter(List<IRainbowContact> contacts) { this.contacts = contacts; } @NonNull @Override public ContactHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_contact , parent , false); return new ContactHolder(view); } @Override public void onBindViewHolder(@NonNull ContactHolder holder, int position) { holder.bindContent(contacts.get(position)); } @Override public int getItemCount() { return contacts.size(); } public void updateContact(List<IRainbowContact> contacts){ this.contacts = new ArrayList<>(); this.contacts.addAll(contacts); notifyDataSetChanged(); } } |
Halaman Login
Pada halaman login terdapat dua widget EditText, satu widget ProgressBar dan satu widget Button pada layout activity_main.xml seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
<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=".activity.LoginActivity"> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:clipToPadding="false" android:orientation="vertical" android:padding="16dp"> <EditText android:id="@+id/etEmail" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Email" android:inputType="textEmailAddress|textNoSuggestions" /> <EditText android:id="@+id/etPassword" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:hint="Password" android:inputType="textPassword" /> <Button android:id="@+id/btnLogin" style="@style/Widget.AppCompat.Button.Colored" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:text="Sign In" /> <ProgressBar android:id="@+id/loading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="20dp" android:visibility="gone" /> </LinearLayout> </ScrollView> </RelativeLayout> |
Kemudian pada kelas LoginActivity terdapat pemanggilan static method dari kelas RainbowConnection seperti startConnection() dan startSignIn() yang sebelumnya sudah dibuat. Kodenya dari LoginActivity adalah seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
public class LoginActivity extends AppCompatActivity implements RainbowConnectionLister.Connection, RainbowConnectionLister.Login { private EditText etEmail; private EditText etPassword; private Button btnLogin; private ProgressBar loading; private String email; private String password; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); loading = findViewById(R.id.loading); etEmail = findViewById(R.id.etEmail); etPassword = findViewById(R.id.etPassword); if (!RainbowConnection.getUserLoginInCache().isEmpty()) { etEmail.setText(RainbowConnection.getUserLoginInCache()); } if (!RainbowConnection.getUserPasswordInCache().isEmpty()) { etPassword.setText(RainbowConnection.getUserPasswordInCache()); } btnLogin = findViewById(R.id.btnLogin); btnLogin.setOnClickListener(v -> { email = etEmail.getText().toString(); password = etPassword.getText().toString(); if (email.isEmpty()) { etEmail.setError("Email Empty"); return; } if (password.isEmpty()) { etPassword.setError("Password Empty"); return; } Utils.hideSoftKey(etEmail); RainbowConnection.startConnection(LoginActivity.this); }); } @Override public void onConnectionSuccess() { loading.setVisibility(View.VISIBLE); Toast.makeText(LoginActivity.this, "Connection Success", Toast.LENGTH_SHORT).show(); RainbowConnection.startSignIn(email, password, this); } @Override public void onConnectionFailed(String error) { loading.setVisibility(View.GONE); Toast.makeText(LoginActivity.this, "Connection " + error, Toast.LENGTH_SHORT).show(); } @Override public void onSignInSuccess() { Toast.makeText(LoginActivity.this, "Sign In Success", Toast.LENGTH_SHORT).show(); loading.setVisibility(View.GONE); startActivity(new Intent(LoginActivity.this, ContactsActivity.class)); } @Override public void onSignInFailed(String error) { loading.setVisibility(View.GONE); Toast.makeText(LoginActivity.this, "Sign In Error " + error, Toast.LENGTH_SHORT).show(); } } |
Halaman List Kontak
Pada halaman kontak hanya terdapat satu buah widget, yaitu widget RecyclerView. Ia akan digunakan untuk menampilkan daftar kontak seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<LinearLayout 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" android:orientation="vertical" tools:context=".activity.ContactsActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/listContact" android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" android:padding="10dp" tools:listitem="@layout/item_contact" /> </LinearLayout> |
Kemudian pada kelas ContactsActivity terdapat inisialisasi ContactsAdapter, RecyclerView dan pemanggilan beberapa static method dari kelas RainbowConnection yang sebelumnya sudah dibuat seperti berikut :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
public class ContactsActivity extends AppCompatActivity implements Contact.ContactListener { private List<IRainbowContact> contacts = new ArrayList<>(); private ContactAdapter contactAdapter; private IItemListChangeListener contactListener = () -> { RainbowConnection.registerAllContact(this); updateContact(); }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_contacts); contactAdapter = new ContactAdapter(contacts); RecyclerView listContact = findViewById(R.id.listContact); listContact.hasFixedSize(); listContact.setLayoutManager(new LinearLayoutManager(this)); listContact.setAdapter(contactAdapter); RainbowSdk.instance().contacts().getRainbowContacts().registerChangeListener(contactListener); RainbowConnection.registerAllContact(this); } @Override protected void onDestroy() { super.onDestroy(); RainbowSdk.instance().contacts().getRainbowContacts().unregisterChangeListener(contactListener); RainbowConnection.unregisterAllContact(this); } private void updateContact() { contacts = RainbowConnection.getRainbowContacts(); runOnUiThread(() -> contactAdapter.updateContact(contacts)); } @Override public void contactUpdated(Contact contact) { updateContact(); } @Override public void onPresenceChanged(Contact contact, RainbowPresence rainbowPresence) { /// TODO : Do Something when presence have been change } @Override public void onActionInProgress(boolean b) { /// TODO : Do Something when action in progress } } |
Setelah selesai kamu bisa langsung mencobanya. Jika tidak terjadi eror maka hasilnya adalah seperti berikut :
Jika gagal saat mencoba Sign In, pastikan akun Sandboxed Rainbow yang kamu gunakan untuk Sign In sudah aktif seperti berikut :
Hal tersebut diperlukan karena pada tutorial ini kita menggunakan host sandboxed.openrainbow.com. Jika berhasil login tapi kontak kamu kosong, pastikan kamu memiliki kontak saat Sign In (masuk) menggunakan tautan web-sandbox.openrainbow.com.
Membuat Test Account
Jika tak mau repot membuat akun baru untuk menambah kontak, gunakanlah Rainbow-CLI untuk membuat sebuah test account yang berada di dalam Rainbow Sandbox platform.
Pertama, instal Rainbow-CLI dengan perintah npm install -g rainbow-cli seperti berikut :
Sebelum menambahkan sebuah test account, Sign In (masuk) dengan menggunakan akun Developer Sandbox yang telah aktif dengan perintah rbw login ‘email’ ‘password’ tanpa tanda petik seperti berikut :
Setelah selesai, barulah kita bisa menambahkan sebuah test account dengan perintah rbw create user ‘user@email.com’ ‘password’ ‘first name’ ‘last name’ tanpa tanda petik seperti berikut :
Jika berhasil kita bisa langsung menambahkan kontak dari test account yang sudah dibuat. Jika dijalankan kembali maka hasilnya seperti berikut :
Tutorial ini berhubungan juga dengan tutorial Membuat Halaman Login dan Update User Info Rainbow Pada Android Apps. Jika kita mengupdate kontak dari project tutorial tersebut, kita bisa langsung melihat perubahannya seperti berikut :
Sekian tutorial Menampilkan List Kontak Rainbow Pada Android Apps. Semoga artikel ini bermanfaat buatmu.
Semoga artikel ini dapat membantu anda. Jika ada pertanyaan, silakan tinggalkan komentar di halaman blog ini dan kami akan membantu anda.