news

Tampilkan postingan dengan label android studio. Tampilkan semua postingan
Tampilkan postingan dengan label android studio. Tampilkan semua postingan

Senin, 15 Juni 2020

Belajar Membuat Aplikasi Android Studi Kasus Proyek Akademi : Layouting


Codelab Layouting Proyek Academy

Setelah menyediakan asset-asset yang dibutuhkan, Anda perlu mengubah tampilan dari masing-masing Activity atau Fragment. Ubahlah satu per satu:

  1. activity_course_reader.xml
    Bukalah dan ubah ConstraintLayout menjadi FrameLayout:
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/frame_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
  2. activity_detail_course.xml
    Hapus FloatingActionButton dan tambahkan NestedScrollView:
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/AppTheme.AppBarOverlay">

    <androidx.appcompat.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    app:popupTheme="@style/AppTheme.PopupOverlay" />

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <include layout="@layout/content_detail_course" />

    </androidx.core.widget.NestedScrollView>

    </androidx.coordinatorlayout.widget.CoordinatorLayout>
    Dengan mengubah kode di atas, maka akan terjadi error di kelas DetailCourseActivity. Hapuslah FloatingActionButton pada kelas tersebut, sehingga kode pada kelas DetailCourseActivity menjadi seperti ini:
    Kotlin
    class DetailCourseActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_detail_course)

    setSupportActionBar(toolbar)
    supportActionBar?.setDisplayHomeAsUpEnabled(true)
    }
    }
    Java
    public class DetailCourseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_detail_course);

    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }
    }
  3. activity_home.xml
    Ubah ConstraintLayout menjadi LinearLayout dan tambahkan TabLayout dan ViewPager:
    <?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:orientation="vertical"
    tools:context=".ui.home.HomeActivity">

    <com.google.android.material.tabs.TabLayout
    android:id="@+id/tabs"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/colorPrimary"
    app:tabTextColor="@android:color/white" />

    <androidx.viewpager.widget.ViewPager
    android:id="@+id/view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
    </LinearLayout>
  4. content_detail_course.xml
    Ubahlah isi layout tersebut menjadi seperti ini:
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:descendantFocusability="blocksDescendants">

    <ImageView
    android:id="@+id/image_poster"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:src="@color/colorImage"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    tools:ignore="ContentDescription" />

    <TextView
    android:id="@+id/text_title"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginEnd="8dp"
    android:gravity="start"
    android:textColor="@color/colorAccent"
    android:textSize="18sp"
    android:textStyle="bold"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toEndOf="@+id/image_poster"
    app:layout_constraintTop_toTopOf="@+id/image_poster"
    tools:text="@string/title" />

    <TextView
    android:id="@+id/text_date"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginBottom="8dp"
    android:gravity="start"
    android:textColor="@color/colorTextSecondary"
    android:textSize="12sp"
    android:textStyle="italic"
    app:layout_constraintBottom_toBottomOf="@+id/image_poster"
    app:layout_constraintEnd_toEndOf="@+id/text_title"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="@+id/text_title"
    app:layout_constraintTop_toBottomOf="@+id/text_title"
    app:layout_constraintVertical_bias="0.0"
    tools:text="@string/dateline" />

    <Button
    android:id="@+id/btn_start"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    android:background="@drawable/bg_button"
    android:text="@string/start_learn"
    android:textColor="@android:color/background_light"
    android:textSize="12sp"
    app:layout_constraintBottom_toBottomOf="@+id/image_poster"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="1.0"
    app:layout_constraintStart_toEndOf="@+id/text_date"
    app:layout_constraintTop_toBottomOf="@+id/text_title"
    app:layout_constraintVertical_bias="1.0" />

    <TextView
    android:id="@+id/text_desc"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="16dp"
    android:layout_marginEnd="8dp"
    android:text="@string/description_module"
    android:textColor="@color/colorText"
    android:textSize="16sp"
    android:textStyle="bold"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/image_poster" />


    <View
    android:id="@+id/line1"
    android:layout_width="match_parent"
    android:layout_height="0.5dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="4dp"
    android:layout_marginEnd="8dp"
    android:background="#000000"
    app:layout_constraintTop_toBottomOf="@+id/text_desc" />

    <TextView
    android:id="@+id/text_description"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    android:textColor="@color/colorText"
    android:textSize="16sp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/line1"
    tools:text="@string/description" />

    <TextView
    android:id="@+id/text_list_module"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="16dp"
    android:layout_marginEnd="8dp"
    android:text="@string/list_module"
    android:textColor="@color/colorText"
    android:textSize="16sp"
    android:textStyle="bold"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/text_description" />

    <View
    android:id="@+id/line2"
    android:layout_width="match_parent"
    android:layout_height="0.5dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="4dp"
    android:layout_marginEnd="8dp"
    android:background="#000000"
    app:layout_constraintTop_toBottomOf="@+id/text_list_module" />

    <androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rv_module"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="4dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="4dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/line2"
    tools:listitem="@layout/items_module_list" />

    <ProgressBar
    android:id="@+id/progress_bar"
    style="?android:attr/progressBarStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:visibility="gone"
    app:layout_constraintBottom_toBottomOf="@+id/rv_module"
    app:layout_constraintEnd_toEndOf="@+id/rv_module"
    app:layout_constraintStart_toStartOf="@+id/rv_module"
    app:layout_constraintTop_toTopOf="@+id/rv_module"
    tools:visibility="visible" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    Akan ada eror di bagian tools:listitem="@layout/items_module_list", ini terjadi karena dalam proyek belum ada items_module_list. Anda bisa klik ALT + Enter, kemudian pilih Create layout resource file ‘items_module_list.xml’ dan pilih OK.
    Lb_o_Den6oSB3YDN-kCQ0ov3rM8dOoM-zkX_YU-xDViYl3DJLtqS65IAyPnEz1sE97Uat6udtgqG__-jtlod4OLE1D4EuiKpu5tPqC2iD9m9MuPqOShjhIJFWgYGQQrQic8C5dJc
    Dengan itu Anda sudah membuat satu resource file baru dengan nama items_module_list.xml.
  5. fragment_academy.xml
    Tambahkan RecyclerView dan ProgressBar di dalam layout tersebut:
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">

    <androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rv_academy"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    tools:listitem="@layout/items_academy">

    </androidx.recyclerview.widget.RecyclerView>

    <ProgressBar
    android:id="@+id/progress_bar"
    style="?android:attr/progressBarStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginBottom="8dp"
    android:visibility="gone"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
    Akan ada eror di bagian tools:listitem="@layout/items_academy", ini terjadi karena dalam proyek belum ada items_academy. Anda bisa klik ALT + Enter, kemudian pilih Create layout resource file items_academy.xml’ dan pilih OK.
    A01cTiGWEqgzIJ3_B9jZ99SjexShj3Z96d-yOPeYdOI_0JJ0pZ7iXPYoD1xJNLu19dGhZyJk89o_dUUYSNQG-jFbWNN8RvBLsVD4AOvDUROHV7p3YW3-pv-pdw3UPHdhevC1qkhV
    Dengan itu Anda sudah membuat satu resource file baru dengan nama items_academy.xml.
  6. fragment_bookmark.xml
    Tambahkan RecyclerView dan ProgressBar di dalam layout tersebut:
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">

    <androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rv_bookmark"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    tools:listitem="@layout/items_bookmark">

    </androidx.recyclerview.widget.RecyclerView>

    <ProgressBar
    android:id="@+id/progress_bar"
    style="?android:attr/progressBarStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:visibility="gone"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    Akan ada eror di bagian tools:listitem="@layout/items_bookmark", ini terjadi karena dalam proyek belum ada items_bookmark. Anda bisa klik ALT + Enter, kemudian pilih Create layout resource file items_bookmark.xml’ dan pilih OK.
    b3ak-DtIJW9l6bkc2uWHTvhYKYngBnkXufWY08yFhv4w9H2dedf8q5dwKjWwOevam1uxUy4YcGOkBFJSItlDYBiCmIWS4QuS_aI9EjoooR-Ut8iN_5Jw5Ou3XthL6-vsj7LXo-0d
    Dengan itu Anda sudah membuat satu resource file baru dengan nama items_bookmark.xml.
  7. fragment_module_content.xml
    Tambahkan WebView ke dalamnya:
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">

    <WebView
    android:id="@+id/web_view"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginBottom="8dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

    <ProgressBar
    android:id="@+id/progress_bar"
    style="?android:attr/progressBarStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:visibility="gone"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
  8. fragment_module_list.xml
    Tambahkan RecyclerView dan ProgressBar ke dalam layout tersebut:
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ProgressBar
    android:id="@+id/progress_bar"
    style="?android:attr/progressBarStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginBottom="8dp"
    android:visibility="gone"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="@+id/rv_module" />

    <androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rv_module"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    tools:listitem="@layout/items_module_list" />
    </androidx.constraintlayout.widget.ConstraintLayout>
  9. items_academy.xml
    Bukalah dan tambahkan kode pada layout tersebut menjadi seperti ini:
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/cv_item_course"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="8dp"
    android:layout_marginRight="8dp"
    android:orientation="vertical"
    app:cardCornerRadius="4dp"
    app:cardElevation="4dp"
    app:cardMaxElevation="4dp"
    app:cardUseCompatPadding="true">

    <androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/item_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
    android:id="@+id/img_poster"
    android:layout_width="120dp"
    android:layout_height="120dp"
    android:layout_alignParentStart="true"
    android:layout_alignParentTop="true"
    android:src="@color/colorImage"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    tools:ignore="ContentDescription" />

    <TextView
    android:id="@+id/tv_item_title"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    android:ellipsize="end"
    android:gravity="start"
    android:textColor="@color/colorAccent"
    android:textSize="16sp"
    android:textStyle="bold"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@+id/img_poster"
    app:layout_constraintTop_toTopOf="parent"
    tools:text="@string/title" />

    <TextView
    android:id="@+id/tv_item_date"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginTop="2dp"
    android:gravity="start"
    android:textColor="@color/colorTextSecondary"
    android:textSize="12sp"
    android:textStyle="italic"
    app:layout_constraintEnd_toEndOf="@+id/tv_item_description"
    app:layout_constraintStart_toStartOf="@+id/tv_item_description"
    app:layout_constraintTop_toBottomOf="@+id/tv_item_description"
    tools:text="@string/dateline" />

    <TextView
    android:id="@+id/tv_item_description"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginTop="2dp"
    android:ellipsize="end"
    android:gravity="start"
    android:maxLines="1"
    android:textColor="@color/colorText"
    android:textSize="14sp"
    app:layout_constraintEnd_toEndOf="@+id/tv_item_title"
    app:layout_constraintStart_toStartOf="@+id/tv_item_title"
    app:layout_constraintTop_toBottomOf="@+id/tv_item_title"
    tools:text="@string/description" />

    </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.cardview.widget.CardView>
  10. items_bookmark.xmlBukalah dan tambahkan kode pada layout tersebut menjadi seperti ini:
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/cv_item_course"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="8dp"
    android:layout_marginRight="8dp"
    android:orientation="vertical"
    app:cardCornerRadius="4dp"
    app:cardElevation="4dp"
    app:cardMaxElevation="4dp"
    app:cardUseCompatPadding="true">

    <androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/item_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
    android:id="@+id/img_poster"
    android:layout_width="120dp"
    android:layout_height="120dp"
    android:layout_alignParentStart="true"
    android:layout_alignParentTop="true"
    android:src="@color/colorImage"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    tools:ignore="ContentDescription" />

    <TextView
    android:id="@+id/tv_item_title"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    android:ellipsize="end"
    android:gravity="start"
    android:textColor="@color/colorAccent"
    android:textSize="16sp"
    android:textStyle="bold"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@+id/img_poster"
    app:layout_constraintTop_toTopOf="parent"
    tools:text="@string/title" />

    <TextView
    android:id="@+id/tv_item_date"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginTop="2dp"
    android:gravity="start"
    android:textColor="@color/colorTextSecondary"
    android:textSize="12sp"
    android:textStyle="italic"
    app:layout_constraintEnd_toEndOf="@+id/tv_item_description"
    app:layout_constraintStart_toStartOf="@+id/tv_item_description"
    app:layout_constraintTop_toBottomOf="@+id/tv_item_description"
    tools:text="@string/dateline" />

    <TextView
    android:id="@+id/tv_item_description"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginTop="2dp"
    android:ellipsize="end"
    android:gravity="start"
    android:maxLines="1"
    android:textColor="@color/colorText"
    android:textSize="14sp"
    app:layout_constraintEnd_toEndOf="@+id/tv_item_title"
    app:layout_constraintStart_toStartOf="@+id/tv_item_title"
    app:layout_constraintTop_toBottomOf="@+id/tv_item_title"
    tools:text="@string/description" />

    <ImageButton
    android:id="@+id/img_share"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="2dp"
    android:layout_marginEnd="8dp"
    android:layout_marginBottom="8dp"
    android:background="@android:color/transparent"
    android:scaleType="fitXY"
    android:src="@drawable/ic_share_blue"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/tv_item_date"
    app:layout_constraintVertical_bias="1.0"
    tools:ignore="ContentDescription" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.cardview.widget.CardView>
  11. items_module_list.xml
    Bukalah dan tambahkan kode pada layout tersebut menjadi seperti ini:
    <?xml version="1.0" encoding="utf-8"?>
    <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:layout_margin="4dp"
    android:orientation="vertical">

    <TextView
    android:id="@+id/text_module_title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="4dp"
    android:textColor="@color/colorText"
    tools:text="@string/example" />

    </LinearLayout>
  12. items_module_list_custom.xml
    Lakukan duplicate layout items_module_list.xml dengan cara klik kanan, pilih copy, klik kanan kembali dan pilih paste. Ubahlah namanya menjadi items_module_list_custom.xml dan klik OK.
    5q9XW_FDuUDJnuTjB9c85iwYkrlKpvWwqCrrcCT-bbZ_hrX9tsl_fhy0olp9Dcx_7pT9Y9Tbv24ydJVqqxIg1TqSNGlMX_nbOpPTPsoGd_Ag-7LLMz9sEXksD6q64XREq1-PbxoB
    Buka dan ubahlah kode di dalam layout tersebut menjadi seperti ini:
    <?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="wrap_content"
    android:layout_margin="4dp"
    android:orientation="vertical"
    tools:ignore="UseCompoundDrawables">

    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginBottom="4dp"
    android:orientation="horizontal"
    tools:ignore="UseCompoundDrawables">

    <ImageView
    android:id="@+id/imageView"
    android:layout_width="8dp"
    android:layout_height="8dp"
    android:layout_gravity="center"
    app:srcCompat="@drawable/ic_circle_black"
    tools:ignore="ContentDescription" />

    <TextView
    android:id="@+id/text_module_title"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_marginStart="8dp"
    android:layout_weight="2"
    android:ellipsize="end"
    android:textColor="@color/colorText"
    android:textSize="14sp"
    android:textStyle="bold"
    tools:text="@string/example" />

    </LinearLayout>
    </LinearLayout>
Dengan ini, semua asset layout sudah Anda persiapkan. Selanjutnya apa lagi ya? Tentu menghubungkan semua asset-asset dan komponen yang ada di layout ke Activity dan Fragment. Tetap semangat ya!

Belajar Membuat Aplikasi Android Studi Kasus Proyek Akademi : Persiapan Asset


Codelab Persiapan Asset

Pada modul ini, Anda akan menyiapkan asset-asset yang digunakan di proyek Academy seperti gambar, warna, menu dan teks.

  1. Kita akan menyiapkan asset-asset yang akan digunakan selama proses pembuatan proyek Academy. Bukalah res/values/colors.xml, ubah dan tambahkan warna-warna berikut:
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    <color name="colorPrimary">#3B526B</color>
    <color name="colorPrimaryDark">#FF2F3F51</color>
    <color name="colorAccent">#FF5584</color>
    <color name="colorImage">#13C5C6</color>
    <color name="colorText">#3E3E3E</color>
    <color name="colorTextSecondary">#6D767E</color>
    <color name="colorTextTertiary">#EFEFEF</color>
    <color name="colorAccentSecondary">#FF8FAF</color>

    </resources>
  2. Bukalah res/values/strings.xml, ubah dan tambahkan beberapa string berikut:
    <resources>
    <string name="app_name">Proyek Academies</string>
    <string name="title">Title</string>
    <string name="description">Description</string>
    <string name="dateline">Dateline</string>
    <string name="description_module">Deskripsi Modul</string>
    <string name="example">Example</string>
    <string name="start_learn">Mulai Belajar</string>
    <string name="list_module">Daftar Modul</string>
    <string name="home">Home</string>
    <string name="bookmark">Bookmark</string>
    <string name="menu_bookmark">bookmark</string>
    <string name="next">Next</string>
    <string name="previous">Previous</string>
    <string name="last_seen">Terakhir dilihat</string>
    <string name="message_undo">Batalkan menghapus item sebelumnya?</string>
    <string name="message_ok">OK</string>

    <string name="deadline_date">Deadline %s</string>
    <string name="share_text">Segera daftar kelas %s di dicoding.com</string>
    </resources>

  3. Kemudian tambahkan beberapa gambar berikut:
    • Gambar Bookmarked
      Klik kanan di drawable → new → Vector Asset. Klik Clip Art, pilihlah gambar bookmark, ubah warnanya menjadi putih atau masukkan #FFFFFF dan beri nama ic_bookmarked_white.
      GA-xRd4HK-DJrrIdBnxGVOf69BzQS664M77rh6MaYnOJieEu-hodUuTCEASlbXKX1rJgM_wdGgtezAIhCZ9ESrXNypufxN3fPuZlU7Twyqj5em4uglgiHJI_C1bpDfBT-WKB8cAj
    • Gambar Bookmark
      Klik kanan di drawable → new → Vector Asset. Klik Clip Art, pilihlah gambar bookmark border, ubah warnanya menjadi putih atau masukkan #FFFFFF dan beri nama ic_bookmark_white.
      S5vkOzLN9R9sfcWQ3uPSOG5k-xeHWCoBcUGHBa950wwPv_BuvNO6uVzGuat2MjPJj8vGbgYbd--c2jkyEeC28uWj9rL8drnUyHTMKOrO90JL_ssoPa5wL0eOmozckGH0IBa9s355
    • Gambar Bookmark Selector
      Klik kanan di drawable → new → Drawable resource file dan beri nama ic_bookmark_selector. Bukalah berkas tersebut dan ubah kodenya jadi seperti ini:
      <?xml version="1.0" encoding="utf-8"?>
      <selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="@android:integer/config_mediumAnimTime">
      <item android:drawable="@drawable/ic_bookmarked_white" android:state_selected="true" />
      <item android:drawable="@drawable/ic_bookmark_white" />

      </selector>
    • Gambar Circle
      Klik kanan di drawable → new → Vector Asset. Klik Clip Art, pilihlah gambar brightness1, ubah warnanya menjadi hitam atau masukkan #000000 dan beri nama ic_circle_black.
      IouTaTRijPecyrLw1j_5wvFgJBHd_XmSAnZ0ngClm3z1fot0zM0hN_XB0oKXdyl2VoQ6STnenWSq4FNg3Rg7vk2AUJhPxkUP75V4xKmqVCODmFHIUgpJ8ZGrAkjSwyCnNgQZ_Mdo
    • Gambar RefreshKlik kanan di drawable → new → Vector Asset. Klik Clip Art, pilihlah gambar refresh dan beri nama ic_refresh_black.
      kvCDZZeLwy1imzm_0bzCgozUGwl7BzAPoDp4U6I9F2lNFRQaMAtbMrL21H9YIEZVyZgpsm8oyYJrqYqhc3WwXk_z2ibAe0IUK0ZpV7QDH1PVl_Co7W2_Vu_OxJpPagRKAC81rWoU
    • Gambar Broken Image
      Klik kanan di drawable → new → Vector Asset. Klik Clip Art, pilihlah gambar broke image dan beri nama ic_broken_image_black.
      TkIItcLYJ9of3q3NyxiUm05cv6rD33GZvOsHCXedKozVwt8bPgqnY7uZScCDZPvgPf4QXAUJrCkJwXX8d9Xs5VOrBhpH_mSdbj3uYHy5hF5mHsADo6fMBd9AP4jf9HNtR2C-ZTwV
    • Gambar LoadingKlik kanan di drawable → new → Drawable resource file dan beri nama ic_loading. Bukalah berkas tersebut dan ubah kodenya jadi seperti ini:
      <?xml version="1.0" encoding="utf-8"?>
      <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
      <item
      android:bottom="-1dp"
      android:drawable="@color/colorTextTertiary"
      android:left="1dp"
      android:right="1dp"
      android:top="1dp" />


      <item
      android:bottom="10dp"
      android:drawable="@drawable/ic_broken_image_black"
      android:left="10dp"
      android:right="10dp"
      android:top="10dp" />
      </layer-list>
    • Gambar LoadingKlik kanan di drawable → new → Drawable resource file dan beri nama ic_error. Bukalah berkas tersebut dan ubah kodenya jadi seperti ini:
      <?xml version="1.0" encoding="utf-8"?>
      <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
      <item
      android:bottom="0dp"
      android:drawable="@color/colorTextTertiary"
      android:left="0dp"
      android:right="0dp"
      android:top="0dp" />


      <item
      android:bottom="10dp"
      android:drawable="@drawable/ic_broken_image_black"
      android:left="10dp"
      android:right="10dp"
      android:top="10dp" />
      </layer-list>
    • Gambar Share
      Klik kanan di drawable → new → Vector Asset. Klik Clip Art, pilihlah gambar share dan beri nama ic_share_blue.
      9wQ-STiRRUd1gbwbfUaA64SagvR4Ch2In2JdqAiSIK8VOAAqTtQxXbW1nL_JkoKENH1AOgg16c7B2sBCg6hI8Nj3vjcnwFeQ7X-pKCCG1qnnYMHVzebGHM0ni0dOAivywR8yJNdF
      Kemudian bukalah berkas tersebut dan ubah warnanya menjadi biru. Dari:
      android:tint="#FFFFFF"
      menjadi:
      android:tint="@color/colorPrimary"
    • Background ButtonKlik kanan di drawable → new → Drawable resource file dan beri nama bg_button. Bukalah berkas tersebut dan ubah kodenya jadi seperti ini:
      <selector xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:state_pressed="true">
      <shape>
      <solid android:color="@color/colorAccent" />
      <corners android:radius="6dp" />
      <padding android:left="4dp" android:right="4dp" />
      </shape>
      </item>
      <item>
      <shape>
      <solid android:color="@color/colorAccent" />
      <corners android:radius="8dp" />
      <padding android:left="4dp" android:right="4dp" />
      </shape>
      </item>
      </selector>
    • Background Button Disable
      Klik kanan di drawable → new → Drawable resource file dan beri nama bg_button_disable. Bukalah file tersebut dan ubah kodenya jadi seperti ini:
      <selector xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:state_pressed="true">
      <shape>
      <solid android:color="@color/colorAccentSecondary" />
      <corners android:radius="6dp" />
      <padding android:left="4dp" android:right="4dp" />
      </shape>
      </item>
      <item>
      <shape>
      <solid android:color="@color/colorAccentSecondary" />
      <corners android:radius="8dp" />
      <padding android:left="4dp" android:right="4dp" />
      </shape>
      </item>
      </selector>

      Setelah membuat asset gambar tersebut, maka seperti ini file drawable yang ada di proyek Academy:20200114171941c265ddc9670d7a1043d62f419626c482.png

Bagaimana? Dengan ini Anda sudah menyiapkan asset-asset yang digunakan untuk proyek Academy. Sudah siap untuk ke tahap selanjutnya? Modul selanjutnya akan lebih seru lagi, tetap semangat!

Belajar Membuat Aplikasi Android Studi Kasus Proyek Akademi : Dasar

Belajar Membuat Aplikasi Android Studi Kasus Proyek Akademi

Pada kelas ini, Anda akan berlatih bagaimana mengimplementasikan Android Jetpack yang dikemas dalam sebuah aplikasi Academy. 

Lalu bagaimana konsep, atau gambaran hasil akhir dari aplikasi proyek Academy? Seperti inilah skema yang akan dibuat:

fs_ZUwaoPA1CXo8rr2nfUlynil8jz2yg6GTqyRlX4BctY4AGqtv8oXwgC20UqhX1PG9R5y2twQPIC4gOUckHD821UtVVItTlKUSEBP5rMbvWFUMEblx0MQjmnLsKf5Efc9SaAs0L
Anda akan bermain ViewModel, LiveData, Repository, Injection sederhana, Room, Paging dan masih banyak lagi. Selain itu, Anda akan belajar konsep offline-online dalam pembuatan aplikasi. 
Untuk pembuatan proyek Academy akan dibagi sesuai dengan materi pada modul tersebut. Selain itu, Anda akan dilatih untuk melakukan pengujian setiap ada penambahan atau perubahan fitur baik dengan Unit Test atau Instrumental Test. 
Seperti ini nanti pembagiannya:

Modul 1:
1. Proyek Academy - View Model

Modul 2:
2. Proyek Academy - Repository dan Injection
3. Proyek Academy - LiveData
4. Proyek Academy - Idling Resource

Modul 3:
5. Proyek Academy - Room
6. Proyek Academy - Pagination



Tujuan

Pada Kelas Jetpack, akan ada latihan membuat Aplikasi Academy menggunakan berbagai komponen Android Jetpack yang dibagi berdasarkan materi tiap modulnya. Oleh karena itu, pada modul ini Anda akan mempersiapkan segala asset yang akan digunakan, seperti layout, gambar, warna dan resource lainnya. Ini semua akan mempermudah pembuatan Aplikasi Academy.


Codelab Persiapan Project

Anda dapat melewati codelab ini sampai "Persiapan Menghubungkan Activity dan Fragment" dengan mengunduh project starter melalui link di bawah ini:

Anda juga dapat mengikuti langkah-langkah di bawah ini jika ingin membuat project dari awal:

  1. Buat proyek baru di Android Studio dengan kriteria sebagai berikut :
    Nama ProjectAcademy
    Target & Minimum Target SDKPhone and Tablet, API Level 21
    Tipe Activity Empty Activity
    Activity Name MainActivity

  2. Selanjutnya ubah MainActivity menjadi HomeActivity dengan cara klik kanan di MainActivity Refactor Rename.
    OOH6dB0Ev3x1KqEShyIpA9ypeXeEJuWU3G11EvSU5cBNrf5RrHf8NMb0imI_BTQiaaYZVwewH7iW06hNraY5ZzDd3IBQ5Mg6tkycfhRj877eh6XEI8P0qdjieSGugMmZssSnA2pR
    Ubah juga layout-nya dari activity_main.xml menjadi activity_home.xml dengan cara klik kanan di activity_main Refactor Rename.
    _ezZkGNPVUFpTsH7mDnxm2StBsMe79gNsOqiyBxWZT8eYYZVVjSdHWiHlT28jpDv2CcELhmTosabZTMsCVG4XbuvM4RZzZdGbxULvaYSRV__z9BhrO1L5Cd7ac5J2nJE8vUsAJvH

  3. Selanjutnya, buka build.gradle level project dan tambahkan versi untuk library berikut:
    Kotlin
    ext {
    //dependencies version
    appCompatVersion = '1.1.0'
    coreVersion = '1.1.0'
    constraintLayoutVersion = '1.1.3'
    junitVersion = '4.12'
    espressoVersion = '3.1.0'
    archLifecycleVersion = '2.1.0'

    materialVersion = '1.0.0'
    recyclerViewVersion = '1.1.0'
    glideVersion = '4.10.0'
    }
    Java
    ext {
    //dependencies version
    appCompatVersion = '1.1.0'
    constraintLayoutVersion = '1.1.3'
    junitVersion = '4.12'
    espressoVersion = '3.1.0'
    archLifecycleVersion = '2.1.0'

    materialVersion = '1.0.0'
    recyclerViewVersion = '1.1.0'
    glideVersion = '4.10.0'
    }
    Versi-versi di atas kita gunakan untuk mempermudah pemeliharan library yang Anda gunakan. Setelah itu, buka build.gradle level module: app dan tambahkan library-library berikut:

    Kotlin
    dependencies {
    //kotlin
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "androidx.core:core-ktx:$coreVersion"

    //ui
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "androidx.appcompat:appcompat:$appCompatVersion"
    implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion"

    implementation "androidx.recyclerview:recyclerview:$recyclerViewVersion"
    implementation "com.google.android.material:material:$materialVersion"
    implementation "com.github.bumptech.glide:glide:$glideVersion"

    //testing
    testImplementation "junit:junit:$junitVersion"
    androidTestImplementation "junit:junit:$junitVersion"
    androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
    }
    Java
    dependencies {
    //ui
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "androidx.appcompat:appcompat:$appCompatVersion"
    implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion"

    implementation "androidx.recyclerview:recyclerview:$recyclerViewVersion"
    implementation "com.google.android.material:material:$materialVersion"
    implementation "com.github.bumptech.glide:glide:$glideVersion"

    //testing
    testImplementation "junit:junit:$junitVersion"
    androidTestImplementation "junit:junit:$junitVersion"
    androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
    }
    Library-library di atas akan digunakan selama pembuatan aplikasi Academy. Jika dilihat, library di atas jadi lebih mudah dilihat dan dipelihara. Jika biasanya Anda memanggil sebuah library ke dalam proyek Android, kini Anda menuliskan beserta versinya, contohnya ketika Anda membutuhkan librarytesting seperti ini:
    testImplementation "junit:junit:4.12"
    androidTestImplementation "junit:junit:4.12"
    Jika library mengalami update, maka Anda perlu meng-update ke versi terbaru dan mengubah versi library satu-satu. Dengan memisahkan versi library, Anda akan dimudahkan ketika terjadi perubahan versi library.

  4. Aktifkan Java 8 Lambda Expressions pada proyek dengan cara menambahkan kode berikut di build.gradle (module:app).
    android {
    ...

    compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
    }

    }

  5. Aktifkan juga vectorDrawable pada proyek dengan cara menambahkan kode berikut di build.gradle (module:app).
    android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
    applicationId "com.dicoding.academies"
    minSdkVersion 17
    targetSdkVersion 29
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    vectorDrawables.useSupportLibrary = true
    }
  6. Setelah menambahkan library, tambahkan Activity dengan tipe Empty Activity dan berilah nama CourseReaderActivity.
    2019121611035435d23e2d0761cab3edceddc2c4dae1ad.png
  7. Buatlah sebuah Activity lagi namun dengan tipe Basic Activity dan beri nama DetailCourseActivity. Ubah title-nya menjadi “Detail Course”.
    202003021117535a4f7527d47da1869869c239d30da9ab.pngKemudian tambahkan Hierarchical Parent ke kelas HomeActivity. Hierarchical Parent berfungsi untuk menentukan induk(parent) dari suatu Activity. Sehingga ketika tombol up ditekan, ia akan menuju ke parent activity-nya. Cara untuk mengaturnya yaitu dengan menambahkan kode berikut pada AndroidManifest.xml:
    ...
    <activity
    android:name=".DetailCourseActivity"
    android:label="@string/title_activity_detail_course"
    android:parentActivityName=".HomeActivity"
    android:theme="@style/AppTheme.NoActionBar">
    <meta-data
    android:name="android.support.PARENT_ACTIVITY"
    android:value=".HomeActivity" />

    </activity>
    ...
    Kemudian pada DetailCourseActivity tambahkan kode berikut untuk menampilkan tombol up berupa tanda panah di kiri atas halaman detail.
    Kotlin
    class DetailCourseActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_detail_course)
    setSupportActionBar(toolbar)

    supportActionBar?.setDisplayHomeAsUpEnabled(true)
    }
    }
    Java
    public class DetailCourseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_detail_course);
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    if (getSupportActionBar() != null) {
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    }
    }

  8. Setelah itu, buatlah sebuah blank fragment dan berilah nama AcademyFragment. Jangan lupa untuk hilangkan checklist di Include fragment factory method dan Include interface callbacks.20191216112838ac295af031493c61dc5ef3c1cad69345.png
    Lakukan kembali langkah di atas untuk membuat 3 Fragment lagi. Berilah nama ketiga fragment tersebut dengan BookmarkFragment, ModuleListFragment dan ModuleContentFragment. Sehingga tampilan package-nya menjadi seperti ini.
    20191216162248594f14d0d4dfded9c5c147dd01d97ba3.pngAgar strukturnya menjadi lebih rapi, kelompokkan kelas-kelas di atas sesuai dengan fungsinya. Buatlah sebuah package baru dengan cara klik kanan pada package utama new package dan berilah nama ui. Kemudian buat lagi package di dalam package UI dengan cara klik kanan pada package ui new package dan berilah nama academy. Buat lagi dengan langkah yang sama sehingga kelas-kelas berikut tersusun menjadi seperti ini:201912161623112688e8e62511a75a60656e197cb34efc.pngCatatan:
    Jika Anda kesulitan dalam membuat package, Anda bisa menekan tombol setting pada kanan atas, unchecklistCompact Middle Packages. Sehingga tampilannya akan menjadi seperti ini:
    201912161623341b47fdbd737ac35638b996f217476376.png
  9. Selanjutnya, buatlah package baru untuk menampung kelas model. Klik kanan pada package utama → new → package dan berilah nama data.
    qekq_RKRCcCiBrlrogdk6uBqvdbSScYWi-KiAs3HAxCqMX2QiMe9oTfmxkeM40hzyQS0biy1oTfh3bLnAhf306cgo0k6nc2bFDWFAnkqMEd311eg_VkzYuX2nxAVxyxOGAWS8i93
    Kemudian buatlah beberapa kelas Model berikut:
    • CourseEntity
      Buatlah Class baru dengan nama CourseEntity. Setelah itu, tambahkan kode berikut:
      Kotlin
      data class CourseEntity(
      var courseId: String,
      var title: String,
      var description: String,
      var deadline: String,
      var bookmarked: Boolean = false,
      var imagePath: String
      )
      Java
      public class CourseEntity {
      private String courseId;
      private String title;
      private String description;
      private String deadline;
      private boolean bookmarked = false;
      private String imagePath;
      }
      Setelah itu buatlah Constructor dan Getter and Setter-nya, sehingga menjadi seperti ini:
      public class CourseEntity {
      private String courseId;
      private String title;
      private String description;
      private String deadline;
      private boolean bookmarked = false;
      private String imagePath;

      public CourseEntity(String courseId, String title, String description, String deadline, Boolean bookmarked, String imagePath) {
      this.courseId = courseId;
      this.title = title;
      this.description = description;
      this.deadline = deadline;
      if (bookmarked != null) {
      this.bookmarked = bookmarked;
      }

      this.imagePath = imagePath;
      }

      public String getCourseId() {
      return courseId;
      }

      public void setCourseId(String mCourseId) {
      this.courseId = mCourseId;
      }

      public String getTitle() {
      return title;
      }

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

      public String getDescription() {
      return description;
      }

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

      public String getDeadline() {
      return deadline;
      }

      public void setDeadline(String mDeadline) {
      this.deadline = mDeadline;
      }

      public boolean isBookmarked() {
      return bookmarked;
      }

      public void setBookmarked(boolean mBookmarked) {
      this.bookmarked = mBookmarked;
      }

      public String getImagePath() {
      return imagePath;
      }

      public void setImagePath(String mImagePath) {
      this.imagePath = mImagePath;
      }
      }
    • ContentEntity
      Buat lagi lagi Class baru dengan nama ContentEntity. Setelah itu, tambahkan kode berikut:
      Kotlin
      data class ContentEntity(
      var content: String?
      )
      Java
      public class ContentEntity {
      private String mContent;
      }
      Setelah itu buatlah Constructor dan Getter and Setter-nya, sehingga menjadi seperti ini:
      public class ContentEntity {

      private String mContent;

      public ContentEntity(String content) {
      this.mContent = content;
      }

      public String getContent() {
      return mContent;
      }

      public void setContent(String mContent) {
      this.mContent = mContent;
      }
      }
    • ModuleEntity
      Buat sekali lagi Class baru dengan nama ModuleEntity. Setelah itu, tambahkan kode berikut:
      Kotlin
      data class ModuleEntity(
      var moduleId: String,
      var courseId: String,
      var title: String,
      var position: Int,
      var read: Boolean = false
      ){
      var contentEntity: ContentEntity? = null
      }
      Java
      public class ModuleEntity {
      public ContentEntity contentEntity;
      private String mModuleId;
      private String mCourseId;
      private String mTitle;
      private Integer mPosition;
      private boolean mRead = false;
      }
      Setelah itu buatlah Constructor dan Getter and Setter-nya, sehingga menjadi seperti ini:
      public class ModuleEntity {
      public ContentEntity contentEntity;
      private String mModuleId;
      private String mCourseId;
      private String mTitle;
      private Integer mPosition;
      private boolean mRead = false;

      public ModuleEntity(String moduleId, String courseId, String title, Integer position, Boolean read) {
      this.mModuleId = moduleId;
      this.mCourseId = courseId;
      this.mTitle = title;
      this.mPosition = position;

      if (read != null) {
      this.mRead = read;
      }

      }

      public String getModuleId() {
      return mModuleId;
      }

      public void setModuleId(String moduleId) {
      this.mModuleId = moduleId;
      }

      public String getCourseId() {
      return mCourseId;
      }

      public void setCourseId(String courseId) {
      this.mCourseId = courseId;
      }

      public String getTitle() {
      return mTitle;
      }

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

      public Integer getPosition() {
      return mPosition;
      }

      public void setPosition(Integer position) {
      this.mPosition = position;
      }

      public boolean isRead() {
      return mRead;
      }

      public void setRead(boolean read) {
      this.mRead = read;
      }
      }
  10. Seluruh asset sudah Anda siapkan. Selanjutnya, buatlah package baru untuk menampung kelas pembantu seperti untuk menampung data dummy. Klik kanan pada package utama → new → package dan berilah nama utils.
    fl1oDu4vzI1lrzO-GwZyNFKyere_zYxxmKSN9mGmcBNF1JKkuiXaA_sZ0S84zQfa_7N3vGQy9cHc0Z4pVbhw8_PtShTCTPo_K8KLk8loATZBG2lIQ01UgJHvtZC6TvOhHNfpKQ7h
    Kemudian buatlah kelas baru di dalamnya dan beri nama DataDummy. Setelah itu, tambahkan kode berikut:
    Kotlin
    object DataDummy {

    fun generateDummyCourses(): List<CourseEntity> {

    val courses = ArrayList<CourseEntity>()

    courses.add(CourseEntity("a14",
    "Menjadi Android Developer Expert",
    "Dicoding sebagai satu-satunya Google Authorized Training Partner di Indonesia telah melalui proses penyusunan kurikulum secara komprehensif. Semua modul telah diverifikasi langsung oleh Google untuk memastikan bahwa materi yang diajarkan relevan dan sesuai dengan kebutuhan industri digital saat ini. Peserta akan belajar membangun aplikasi Android dengan materi Testing, Debugging, Application, Application UX, Fundamental Application Components, Persistent Data Storage, dan Enhanced System Integration.",
    "100 Hari",
    false,
    "https://www.dicoding.com/images/small/academy/menjadi_android_developer_expert_logo_070119140352.jpg"))
    courses.add(CourseEntity("a55",
    "Kotlin Android Developer Expert",
    "Pada Google I/O 2017, Kotlin diumumkan sebagai bahasa pemrograman yang termasuk dalam bahasa kelas satu (First class) yang didukung untuk pembuatan aplikasi Android, selain Java dan C++. Kotlin adalah bahasa pemrograman yang dibuat oleh JetBrains. Google juga akan memastikan bahwa semua fitur baru di Android, framework, IDE dan keseluruhan library, akan dapat bekerja dan terintegrasi baik dengan bahasa pemrograman Kotlin serta interopable dengan fungsi-fungsi Java yang telah ada sehingga memungkinkan para engineer melakukan perubahan bagian tertentu aplikasi dari Java ke Kotlin dan sebaliknya dengan sangat mudah.",
    "50 Hari",
    false,
    "https://www.dicoding.com/images/small/academy/kotlin_android_developer_expert_logo_070119140227.jpg"))
    courses.add(CourseEntity("a47",
    "Menjadi Game Developer Expert",
    "Semua modul dalam kelas ini telah diverifikasi langsung oleh Asosiasi Game Indonesia (AGI) untuk memastikan materi yang diajarkan relevan dan sesuai dengan kebutuhan industri game saat ini. Peserta akan belajar best practice membuat game seperti Script, Sprite, UI, Gameplay, Input Method, Porting ke Android / iOS, Modul Services (Collaboration, Ads, Analytics dan Google Play Games - Update Oktober 2018), Porting ke VR - Cardboard dan Gear VR (New Mei 2018) dengan Unity 3D. Peserta juga akan belajar langsung membuat 8 game yaitu Casual (Update Agustus 2018), Pilah Sampah (New November 2018), Tower Defense (New November 2018), Arcade (Update Maret 2018), Platformer (Update Januari 2019), FPS, Multiplayer (Update Maret 2018), serta Game Interaktif dengan VR (New Mei 2018).",
    "75 Hari",
    false,
    "https://www.dicoding.com/images/small/academy/menjadi_game_developer_expert_logo_070119140532.jpg"))
    courses.add(CourseEntity("a74",
    "Membangun Progressive Web Apps",
    "Progressive Web Apps adalah aplikasi web yang memanfaatkan beragam fitur web modern sehingga dapat menyajikan pengalaman pengguna seperti aplikasi native. PWA mengubah sajian tampilan yang umumnya dibuka melalui halaman browser menjadi jendela aplikasi tersendiri. Selain itu PWA juga memungkinkan konten halaman diakses dalam mode offline, menampilkan pesan pemberitahuan, hingga akses ke hardware dari perangkat seperti halnya native app.",
    "50 Hari",
    false,
    "https://www.dicoding.com/images/small/academy/membangun_progressive_web_apps_logo_070119142922.jpg"))
    courses.add(CourseEntity("a51",
    "Belajar Membuat Aplikasi Android untuk Pemula", "Kelas ini didesain oleh Google Authorized Training Partner untuk developer Android di Indonesia. Peserta akan mempelajari materi dasar Android dalam 30 hari dan diarahkan untuk membuat aplikasi sederhana. Terdapat 27 modul yang juga merupakan bagian dari Kelas Menjadi Android Developer Expert. Peserta disarankan setidaknya memiliki pengetahuan tentang programming Java dan atau pemrograman berorientasi objek. Sistem pembelajaran adalah online (dapat diakses kapanpun dan darimanapun selama tersedia internet) dan kehadiran tatap muka tidak diperlukan. Tools yang diwajibkan untuk kelas belajar Android ini adalah Android Studio. Peserta harus submit satu proyek akhir yang akan direview oleh developer expert untuk mendapatkan sertifikat dari kelas ini. Bila menginginkan materi yang lebih komprehensif, silahkan mengikuti kelas Menjadi Android Developer Expert.",
    "30 Hari",
    false,
    "https://www.dicoding.com/images/small/academy/belajar_membuat_aplikasi_android_untuk_pemula_logo_070119140911.jpg"))

    return courses
    }

    fun generateDummyModules(courseId: String): List<ModuleEntity> {

    val modules = ArrayList<ModuleEntity>()

    modules.add(ModuleEntity(
    "{$courseId}m1",
    courseId,
    "Modul 0 : Introduction",
    0))
    modules.add(ModuleEntity("{$courseId}m2",
    courseId,
    "Modul 1 : Teori 1",
    1, false))
    modules.add(ModuleEntity("{$courseId}m3",
    courseId,
    "Latihan 1",
    2, false))
    modules.add(ModuleEntity("{$courseId}m4",
    courseId,
    "Bedah Kode 1",
    3, false))
    modules.add(ModuleEntity("{$courseId}m5",
    courseId,
    "Modul 2 : Teori 2",
    4, false))

    modules.add(ModuleEntity("{$courseId}m6",
    courseId,
    "Latihan 2",
    5, false))

    modules.add(ModuleEntity("{$courseId}m7",
    courseId,
    "Bedah Kode 2",
    6, false))

    return modules
    }
    }
    Java
    public class DataDummy {

    public static List<CourseEntity> generateDummyCourses() {

    ArrayList<CourseEntity> courses = new ArrayList<>();

    courses.add(new CourseEntity("a14",
    "Menjadi Android Developer Expert",
    "Dicoding sebagai satu-satunya Google Authorized Training Partner di Indonesia telah melalui proses penyusunan kurikulum secara komprehensif. Semua modul telah diverifikasi langsung oleh Google untuk memastikan bahwa materi yang diajarkan relevan dan sesuai dengan kebutuhan industri digital saat ini. Peserta akan belajar membangun aplikasi Android dengan materi Testing, Debugging, Application, Application UX, Fundamental Application Components, Persistent Data Storage, dan Enhanced System Integration.",
    "100 Hari",
    null,
    "https://www.dicoding.com/images/small/academy/menjadi_android_developer_expert_logo_070119140352.jpg"));
    courses.add(new CourseEntity("a55",
    "Kotlin Android Developer Expert",
    "Pada Google I/O 2017, Kotlin diumumkan sebagai bahasa pemrograman yang termasuk dalam bahasa kelas satu (First class) yang didukung untuk pembuatan aplikasi Android, selain Java dan C++. Kotlin adalah bahasa pemrograman yang dibuat oleh JetBrains. Google juga akan memastikan bahwa semua fitur baru di Android, framework, IDE dan keseluruhan library, akan dapat bekerja dan terintegrasi baik dengan bahasa pemrograman Kotlin serta interopable dengan fungsi-fungsi Java yang telah ada sehingga memungkinkan para engineer melakukan perubahan bagian tertentu aplikasi dari Java ke Kotlin dan sebaliknya dengan sangat mudah.",
    "50 Hari",
    null,
    "https://www.dicoding.com/images/small/academy/kotlin_android_developer_expert_logo_070119140227.jpg"));
    courses.add(new CourseEntity("a47",
    "Menjadi Game Developer Expert",
    "Semua modul dalam kelas ini telah diverifikasi langsung oleh Asosiasi Game Indonesia (AGI) untuk memastikan materi yang diajarkan relevan dan sesuai dengan kebutuhan industri game saat ini. Peserta akan belajar best practice membuat game seperti Script, Sprite, UI, Gameplay, Input Method, Porting ke Android / iOS, Modul Services (Collaboration, Ads, Analytics dan Google Play Games - Update Oktober 2018), Porting ke VR - Cardboard dan Gear VR (New Mei 2018) dengan Unity 3D. Peserta juga akan belajar langsung membuat 8 game yaitu Casual (Update Agustus 2018), Pilah Sampah (New November 2018), Tower Defense (New November 2018), Arcade (Update Maret 2018), Platformer (Update Januari 2019), FPS, Multiplayer (Update Maret 2018), serta Game Interaktif dengan VR (New Mei 2018).",
    "75 Hari",
    null,
    "https://www.dicoding.com/images/small/academy/menjadi_game_developer_expert_logo_070119140532.jpg"));
    courses.add(new CourseEntity("a74",
    "Membangun Progressive Web Apps",
    "Progressive Web Apps adalah aplikasi web yang memanfaatkan beragam fitur web modern sehingga dapat menyajikan pengalaman pengguna seperti aplikasi native. PWA mengubah sajian tampilan yang umumnya dibuka melalui halaman browser menjadi jendela aplikasi tersendiri. Selain itu PWA juga memungkinkan konten halaman diakses dalam mode offline, menampilkan pesan pemberitahuan, hingga akses ke hardware dari perangkat seperti halnya native app.",
    "50 Hari",
    null,
    "https://www.dicoding.com/images/small/academy/membangun_progressive_web_apps_logo_070119142922.jpg"));
    courses.add(new CourseEntity("a51",
    "Belajar Membuat Aplikasi Android untuk Pemula", "Kelas ini didesain oleh Google Authorized Training Partner untuk developer Android di Indonesia. Peserta akan mempelajari materi dasar Android dalam 30 hari dan diarahkan untuk membuat aplikasi sederhana. Terdapat 27 modul yang juga merupakan bagian dari Kelas Menjadi Android Developer Expert. Peserta disarankan setidaknya memiliki pengetahuan tentang programming Java dan atau pemrograman berorientasi objek. Sistem pembelajaran adalah online (dapat diakses kapanpun dan darimanapun selama tersedia internet) dan kehadiran tatap muka tidak diperlukan. Tools yang diwajibkan untuk kelas belajar Android ini adalah Android Studio. Peserta harus submit satu proyek akhir yang akan direview oleh developer expert untuk mendapatkan sertifikat dari kelas ini. Bila menginginkan materi yang lebih komprehensif, silahkan mengikuti kelas Menjadi Android Developer Expert.",
    "30 Hari",
    null,
    "https://www.dicoding.com/images/small/academy/belajar_membuat_aplikasi_android_untuk_pemula_logo_070119140911.jpg"));

    return courses;
    }

    public static List<ModuleEntity> generateDummyModules(String courseId) {

    ArrayList<ModuleEntity> modules = new ArrayList<>();

    modules.add(new ModuleEntity(String.format("%sm1", courseId),
    courseId,
    "Modul 0 : Introduction",
    0,
    null));
    modules.add(new ModuleEntity(String.format("%sm2", courseId),
    courseId,
    "Modul 1 : Teori 1",
    1,
    null));
    modules.add(new ModuleEntity(String.format("%sm3", courseId),
    courseId,
    "Latihan 1",
    2,
    null));
    modules.add(new ModuleEntity(String.format("%sm4", courseId),
    courseId,
    "Bedah Kode 1",
    3,
    null));
    modules.add(new ModuleEntity(String.format("%sm5", courseId),
    courseId,
    "Modul 2 : Teori 2",
    4,
    null));

    modules.add(new ModuleEntity(String.format("%sm6", courseId),
    courseId,
    "Latihan 2",
    5,
    null));

    modules.add(new ModuleEntity(String.format("%sm7", courseId),
    courseId,
    "Bedah Kode 2",
    6,
    null));

    return modules;
    }
    }
  11. Anda perlu menambahkan permission di AndroidManifest.xml. Bukalah berkas tersebut dan sesuaikan seperti berikut:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.dicoding.academies">

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

    <application
    android:allowBackup="false"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    tools:ignore="GoogleAppIndexingWarning">
    ...
    </application>

    </manifest>
  12. Sehingga keseluruhan class akan menjadi seperti ini:
    20191217133248f9c0594b1a0aa7cf297fad2d8b18aa7a.png

Pada modul selanjutnya Anda akan menyiapkan asset-asset yang dibutuhkan untuk proyek Academy. Semangatttt!!!

Belajar Pengujian ViewModel dengan Unit Testing


Tujuan

Pada Codelab kali ini Anda akan menggunakan Junit untuk melakukan testing pada aplikasi MyViewModel yang sudah dibuat. Poin penting materi ini adalah agar Anda mengerti bagaimana menggunakan JUnit untuk melakukan pengujian pada aplikasi Anda.


Logika Dasar

Menjalankan Aplikasi → menguji secara manual → menguji dengan Unit Testing → mendapat hasil pengujian secara otomatis.

Codelab Pengujian ViewModel dengan Unit Testing

  1. Anda bisa membuka proyek sebelumnya, MyViewModel atau unduh di tautan berikut:
    MyViewModel
  2. Tambahkan terlebih dahulu library Unit Testing ke dalam project Anda. Bukalah build.gradle , masukkan kode berikut di dalamnya, dan jangan lupa untuk Sync Project.
    testImplementation 'junit:junit:4.12'
    testImplementation group: 'org.mockito', name: 'mockito-core', version: '3.1.0'
  3. Selanjutnya, buat kelas baru untuk melakukan pengujian. Untuk membuatnya secara otomatis, buka kelas MainViewModel kemudian klik Alt+Enter pada MainViewModel maka akan ada banyak pilihan seperti berikut:
    Kotlin
    20191127112949de240e32d1bc8beab97382567e3fe87e.pngSetelah itu, pilih Create Test.
    201911271131112bf29738cd10bb160537adf94b817d44.png
    Java
    20191127113450491c4c751553b4674e81587fbc0dd763.pngSetelah itu, pilih Create Test.2019112711360417759d616301a5f1a1530184430ae534.png
    Anda perlu memberi checklist pada method calculate pada gambar di atas. Biarkan default nama kelas yang baru, MainViewModelTest. Klik OK untuk melanjutkan.

  4. Setelah itu, Anda diminta untuk menentukan di mana lokasi MainViewModelTest akan dibentuk. Pilihlah .../test/.... Mengapa demikian? Directory test digunakan untuk unit Testing, sedangkan directory androidTest digunakan untuk instrumental testing yang nanti akan dibahas pada modul selanjutnya. Klik OK untuk melanjutkan.
    20191127113736db2a88a288b14c589378e105a5958cf1.png
  5. Maka secara otomatis akan ada satu berkas baru seperti ini:
    2019053002141595a237c6cdbff3cc509a887c65ba8670Sesuai dengan directory yang Anda pilih sebelumnya, kelas MainViewModelTest berada pada directory test.
  6. Ok, sekarang buka kelas MainViewModelTest. Jika dilihat kode hasil generator menjadi seperti ini:

Kotlin
class MainViewModelTest {

@Test
fun calculate() {
}
}
Java
public class MainViewModelTest {

@Test
public void calculate() {
}
}
Pada kode di atas sudah ada metode calculate yang digunakan untuk menguji metode yang sama pada kelas MainViewModel.
  1. Alangkah baiknya kita buka kembali kelas MainViewModel agar Anda paham apa yang mau diuji. Seperti ini kode pada kelas MainViewModel:
    Kotlin
    class MainViewModel : ViewModel() {
    var result = 0

    fun calculate(width: String, height: String, length: String) {
    result = width.toInt() * height.toInt() * length.toInt()
    }
    }
    Java
    public class MainViewModel extends ViewModel {
    int result = 0;

    void calculate(String width, String height, String length) {
    result = Integer.parseInt(width) * Integer.parseInt(height) * Integer.parseInt(length);
    }
    }
    Di dalam MainViewModel terdapat 1 variable result dan 1 metode calculate.
  2. Pertama, kita akan uji antara apa yang Anda masukan di calculate dengan hasil dari result. Tambahkan dan ubahlah kelas MainViewModelTest menjadi seperti ini:
    Kotlin
    class MainViewModelTest {
    private lateinit var mainViewModel: MainViewModel

    @Before
    fun init() {
    mainViewModel = MainViewModel()
    }

    @Test
    fun calculate() {
    val width = "1"
    val length = "2"
    val height = "3"
    mainViewModel.calculate(width, height, length)
    assertEquals(6, mainViewModel.result)
    }
    }
    Java
    public class MainViewModelTest {
    private MainViewModel mainViewModel;

    @Before
    public void init() {
    mainViewModel = new MainViewModel();
    }

    @Test
    public void calculate() {
    String width = "1";
    String length = "2";
    String height = "3";
    mainViewModel.calculate(width, height, length);
    assertEquals(6, mainViewModel.result);
    }
    }
    Kode di atas digunakan untuk memastikan apakah hasil dari mainViewModel.result sesuai dengan yang diharapkan.
  3. Oke, Anda bisa jalankan pengujian pertama Anda. Klik bagian ini untuk melakukan pengujian.
    201905300215452204310c32a3a306b65f9f6f1023d08bKemudian pilih Run ‘MainViewModelTest’.
  4. Android Studio akan menjalankan pengujian kelas MainViewModelTest dan akan menghasilkan skenario seperti ini.
    201905300216376b77616559a674e7626ec41185fc352dGambar di atas menunjukkan bahwa pengujian yang Anda lakukan berhasil. Itu bisa dilihat dengan adanya checklist berwarna hijau pada proses pengujian.
  5. Oke, selanjutnya kita Akan coba ketika inputan berbeda dengan ekspektasi. Ubahlah kode di kelas MainViewModelTest menjadi seperti ini:
    Kotlin
    class MainViewModelTest {
    private lateinit var mainViewModel: MainViewModel

    @Before
    fun init() {
    mainViewModel = MainViewModel()
    }

    @Test
    fun calculate() {
    val width = "1"
    val length = "2"
    val height = "2"
    mainViewModel.calculate(width, height, length)
    assertEquals(6, mainViewModel.result)
    }
    }
    Java
    public class MainViewModelTest {
    private MainViewModel mainViewModel;

    @Before
    public void init() {
    mainViewModel = new MainViewModel();
    }

    @Test
    public void calculate() {
    String width = "1";
    String length = "2";
    String height = "2";
    mainViewModel.calculate(width, height, length);
    assertEquals(6, mainViewModel.result);
    }
    }
  6. Jalankan pengujian tersebut, maka akan seperti ini:
    201905300218212a72baec268c06155a26eb2d2a023802Ekspektasi dari pengujian adalah 6, namun dalam pengujian aktualnya adalah 4. Tentu tak sesuai antara aktual dengan ekspektasi, maka pengujian dianggap gagal. Oke, Anda bisa sesuaikan kembali nilai height agar aktual dengan ekspektasi sama.
  7. Selanjutnya, kita akan coba input di dalam string menjadi double bukan integer. Tambahkan kode seperti ini:

    Kotlin

    class MainViewModelTest {
    ...

    @Test
    fun doubleInputCalculateTest() {
    val width = "1"
    val length = "2.4"
    val height = "3"
    mainViewModel.calculate(width, height, length)
    }
    }

    Java

    public class MainViewModelTest {
    ...

    @Test
    public void doubleInputCalculateTest() {
    String width = "1";
    String length = "2.4";
    String height = "3";
    mainViewModel.calculate(width, height, length);
    }
    }

  8. Jalankan pengujian tersebut, maka akan menjadi seperti ini:20190530022028f639b6edb1344f06a599c7413ae4902e.pngPengujian yang dilakukan gagal, karena apa yang Anda masukan dalam string bukanlah integer melainkan double. Ini mungkin saja terjadi dalam kejadian-kejadian tertentu, namun Anda perlu mengantisipasi kejadian tersebut.

    Kotlin

    class MainViewModelTest {
    ...

    @get:Rule
    var thrown = ExpectedException.none()


    ...

    @Test
    @Throws(NumberFormatException::class)
    fun doubleInputCalculateTest() {
    val width = "1"
    val length = "2.4"
    val height = "3"
    thrown.expect(NumberFormatException::class.java)
    thrown.expectMessage("For input string: \"2.4\"")

    mainViewModel.calculate(width, height, length)
    }
    }

    Java

    public class MainViewModelTest {
    ...

    @Rule
    public ExpectedException thrown = ExpectedException.none();


    ...

    @Test
    public void doubleInputCalculateTest() throws NumberFormatException {
    String width = "1";
    String length = "2.4";
    String height = "3";

    thrown.expect(NumberFormatException.class);
    thrown.expectMessage("For input string: \"2.4\"");

    mainViewModel.calculate(width, height, length);
    }
    }
    Annotation @Rule digunakan untuk untuk menjalankan kode sebelum pengujian dilakukan. Jadi jika tidak diberi anotasi @Rule pada thrown, maka kode tersebut tidak akan berjalan.
  9. Karena eror tersebut berasal dari NumberFormatException, maka Anda bisa menambahkan itu dengan cara seperti ini:
  10. Jalankan kode tersebut, maka hasilnya akan menjadi seperti ini:
    20190530022211e9d31045197f80546fdb7580b11de4d2Lihat hasil di atas! Pengujian Anda berhasil. Sesuai Ekspektasi Anda bahwa eror tersebut terjadi karena NumberFormatException, bahkan Anda juga mencocokkan pesan dari eror yang terjadi dengan ekspektasi Anda.
    NumberFormatException akan terjadi saat Anda mencoba mengubah String menjadi nilai angka namun String tersebut tidak terformat dengan benar. Misalnya dalam kasus tersebut ekspektasi Anda adalah Integer, namun aktualnya adalah String.
  11. Selanjutnya tambahkan kode berikut untuk memberi ekspektasi eror yang terjadi saat ada input kosong dan berupa character:

    Kotlin

    class MainViewModelTest {
    ...

    @Test
    @Throws(java.lang.NumberFormatException::class)
    fun characterInputCalculateTest() {
    val width = "1"
    val length = "A"
    val height = "3"
    thrown.expect(java.lang.NumberFormatException::class.java)
    thrown.expectMessage("For input string: \"A\"")
    mainViewModel.calculate(width, length, height)
    }


    @Test
    @Throws(java.lang.NumberFormatException::class)
    fun emptyInputCalculateTest() {
    val width = "1"
    val length = ""
    val height = "3"
    thrown.expect(java.lang.NumberFormatException::class.java)
    thrown.expectMessage("For input string: \"\"")
    mainViewModel.calculate(width, height, length)
    }
    }

    Java
    public class MainViewModelTest {
    ...

    @Test
    public void characterInputCalculateTest() throws NumberFormatException {
    String width = "1";
    String length = "A";
    String height = "3";
    thrown.expect(NumberFormatException.class);
    thrown.expectMessage("For input string: \"A\"");
    mainViewModel.calculate(width, length, height);
    }


    @Test
    public void emptyInputCalculateTest() throws NumberFormatException {
    String width = "1";
    String length = "";
    String height = "3";
    thrown.expect(NumberFormatException.class);
    thrown.expectMessage("For input string: \"\"");
    mainViewModel.calculate(width, height, length);
    }
    }
  12. Anda bisa menjalankan kembali pengujian yang Anda buat, maka akan menjadi seperti ini:
    201905300225180b3da29e4d7e3bd6b6cf851418846888Tentu, pengujian di atas berhasil dilakukan karena Anda sudah memberi ekspektasi eror yang terjadi. Untuk pengujian, Anda bisa melakukan sesuai dengan kebutuhan dari aplikasi Anda.

Bedah Kode

Kita sudah melewati beberapa latihan untuk melakukan UnitTest. Pada modul sebelumnya juga Anda sudah mempelajari tentang Unit Test.

Perhatikan kode berikut:

Kotlin

private lateinit var mainViewModel: MainViewModel

@Before
fun init() {
mainViewModel = MainViewModel()
}


Java


private MainViewModel mainViewModel;

@Before
public void init() {
mainViewModel = new MainViewModel();
}

Untuk menginisialisasi ViewModel, Anda perlu melakukannya di dalam method init() dengan anotasi @Before. Anotasi ini berfungsi untuk melakukan serangkaian persiapan sebelum melakukan pengujian.

Perhatikan kode berikut:

Kotlin

@Test
fun calculate() {
val width = "1"
val length = "2"
val height = "3"
mainViewModel.calculate(width, height, length)
assertEquals(6, mainViewModel.result)
}



Java

@Test
public void calculate() {
String width = "1";
String length = "2";
String height = "3";
mainViewModel.calculate(width, height, length);
assertEquals(6, mainViewModel.result);
}


Kode assertEquals berguna untuk membandingkan antara ekspektasi dan hasil aktual perhitungan. Jika Anda masih belum paham tentang pengujian, Anda bisa cek kembali modul 0 tentang pengujian.

Perhatikan kode berikut:

Kotlin

@get:Rule
var thrown = ExpectedException.none()
...
thrown.expect(NumberFormatException::class.java)
thrown.expectMessage("For input string: \"2.4\"")


Java

@Rule
var thrown = ExpectedException.none()
...
thrown.expect(NumberFormatException.class);
thrown.expectMessage("For input string: \"2.4\"");

Kode di atas berguna untuk memastikan apakah pesan eror yang terjadi sesuai dengan ekspektasi Anda.

Pada kasus di atas, ekspektasinya yaitu variable yang dimasukkan bukan integer, melainkan double. Untuk menggunakan ExpectedException, Anda perlu menggunakan anotasi Rule untuk memberi aturan pada pengujian .

Jika Anda masih belum paham tentang pengujian, Anda bisa cek kembali modul 0 tentang pengujian.

Source code dapat Anda unduh pada tautan berikut: