[Late Post] Update ke Android Studio 4.1: Ubah Style ke Theme, KAE ke ViewBinding, AsyncTask ke Executor
Goal:
Ubah semua project ke format 4.1
- Ubah styles ke theme & ubah tampilan GIF ke material design
- Ubah KAE ke ViewBinding
- Jika butuh Parcelize tambahkan kotlin-parcelize
Step Update Theme MaterialComponent :
1. Tambahkan Library Material sekalian Update versi library
- Gradle 6.5
- AGP 4.1.0
- Kotlin 1.4.10
- compileSdkVersion & targetSdkVersion 30
- Library lain yg butuh update
- Sesuaikan format build.gradle baru
Kotlin
//format plugin menggunakan DSL
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
...
//tambahan options
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
// hapus filetree
//hapus -jdk7 di library kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.13.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
Java
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
defaultConfig {
applicationId "com.dicoding.myjavaapplication"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.13.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
2. Ubah Colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>
3. Buat themes : Klik kanan values -> new -> values resource file -> file name : themes
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.MyViewAndViews" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>
Note: Sesuaikan style name dengan nama project
Tips: Jika sudah pernah bikin sekali, bisa copy paste aja.
4. Buat themes (night) : Klik kanan values -> new -> values resource file -> file name : themes -> pilih Night Mode -> klik >> -> Pilih Night -> OK
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.MyViewAndViews" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>
Note: Sesuaikan style name dengan nama project
Tips: Jika sudah pernah bikin sekali, bisa copy paste aja. pada folder values-night
5. Hapus Styles.xml
6. Ganti theme di AndroidManifest.xml
HTML/XML
<application
...
android:theme="@style/Theme.MyViewAndViews">
...
</application>
7. Jalankan dan buat GIF
8. Update GIF dan Kode pada platform. ex: https://www.dicoding.com/academies/51/tutorials/1221
Sample commit : https://github.com/dicodingacademy/a165-android-expert-labs/commit/3df8f8930ab7a0c831305ed5010d3405b8328918
Step Update KAE ke ViewBinding (Kotlin & Java) :
1. Hapus plugin kotlin-android-android
plugins {
id 'com.android.application'
id 'kotlin-android'
}
2. enable view binding
android {
...
buildFeatures {
viewBinding = true
}
}
3. Tambahkan ViewBinding di Activity
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
}
4. Ganti misal ed_email jadi binding.edEmail
Tips: Gunakan replace untuk langsung ganti semua
Sample commit : https://github.com/dicodingacademy/a165-android-expert-labs/commit/dec307ff603e0ec7b561690f5093063ca908fcb2
Warn:
Kalu di Frament pastikan di destroy, caranya seperti ini:
private var _binding: FragmentFavoriteBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentFavoriteBinding.inflate(inflater, container, false)
return binding.root
}
...
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Sample Commit : https://github.com/dicodingacademy/a165-android-expert-project/commit/ab0f667d5ff30dcac79267abac54a45db762709f
You might feel a bit uneasy about the double bangs !!
, but all we are saying here is that we are sure this field will not be null when we use it (in the lifecycle between onCreateView
and onDestroyView
), which is exactly the same we are saying when we use lateinit var
. https://proandroiddev.com/avoiding-memory-leaks-when-using-data-binding-and-view-binding-3b91d571c150
3. Kotlin-Parcelize
ternyata kotlin-parcelize harus pakai kotlin 1.4.20-M2.. ndak bisa kalau pakai1.4.10.. Jadi untuk sementara android-extensionnya dibiarin dulu aja (ndak dihapus) kalau butuh parcelize, tapi syntetic-nya tetap diganti ke Viewbinding
Update : Sekarang sudah ada 1.4.20 Jadi kotlin-android-extension bisa dihapus dan ganti dengan kotlin-parcelize
Lalu ganti import
import kotlinx.android.parcel.Parcelize
jadi
import kotlinx.parcelize.Parcelize
4. Binding di Adapter
tinggal tambahkan binding di ViewHolder, dan kalau butuh akses setOnclickListener bisa pakai binding.root
Kotlin
inner class ListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val binding = ItemListTourismBinding.bind(itemView)
fun bind(data: TourismEntity) {
with(binding) {
Glide.with(itemView.context)
.load(data.image)
.into(ivItemImage)
tvItemTitle.text = data.name
tvItemSubtitle.text = data.address
}
}
init {
binding.root.setOnClickListener {
onItemClick?.invoke(listData[adapterPosition])
}
}
}
Sample commit : https://github.com/dicodingacademy/a165-android-expert-project/commit/6fa3042e8e77921a68ae48a7a8d992d3c868aa1a
5. Binding untuk includes layout
Layout includes harus diberi id
<include
android:id="@+id/content"
layout="@layout/content_detail_main" />
Untuk mengambil id yang di dalam content_detail_tourism bisa dengan cara
binding.content.tvDetailDescription.text = …
Sample commit: https://github.com/dicodingacademy/a165-android-expert-project/commit/d76379e1889e7d3a6f441a034f5d39f13a0919ef
6. AsyncTask to Executor
ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(new Runnable() {
@Override
public void run() {
//do background process
handler.post(new Runnable() {
@Override
public void run() {
//do ui update
}
});
}
});
Lambda Java 8 version
ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
//do background process
handler.post(() -> {
//do ui update
});
});
7. Switch dan Interface ganti langsung
- stepnya hapus implement View.OnClickListener,
- ganti setOnClickListener() jadi
setOnClickListener{ //kode } (Kotlin)
setOnClickListener ( v-> {//kode }); (Java)
- pindah kode yg di dalam onClick ke {},
- hapus onClick
Misal
class HomeFragment : Fragment(), View.OnClickListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val btnCategory: Button = view.findViewById(R.id.btn_category)
btnCategory.setOnClickListener(this)
}
override fun onClick(v: View?) {
when (v?.id){
R.id.btn_category -> {
val mCategoryFragment = CategoryFragment()
val mFragmentManager = parentFragmentManager
mFragmentManager.commit {
addToBackStack(null)
replace(R.id.frame_container, mCategoryFragment, CategoryFragment::class.java.simpleName)
}
}
}
}
}
Jadi
class HomeFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val btnCategory: Button = view.findViewById(R.id.btn_category)
btnCategory.setOnClickListener {
val mCategoryFragment = CategoryFragment()
val mFragmentManager = parentFragmentManager
mFragmentManager.commit {
addToBackStack(null)
replace(R.id.frame_container, mCategoryFragment, CategoryFragment::class.java.simpleName)
}
}
}
}
Other:
- setDrawerLayout udah deprecated, cukup ganti dengan setOpenableLayout
- ganti warna background material button belum bisa pakai backgroundColor, tapi bisa pake backgroundColorTint, tapi minSdkVersion diganti 21
- Viewbindingdelegate https://proandroiddev.com/make-android-view-binding-great-with-kotlin-b71dd9c87719
Untuk yg menggunakan Spinner:
https://blog.usejournal.com/there-is-no-material-design-spinner-for-android-3261b7c77da8