Kotlin နဲ့ Android ရေးကြမယ် (၁)

ခုတလော Kotlin Kotlin နဲ့ ရေပန်းစားလာတော့ မကြာသေးခင်က ဘာများပါလိမ့်ဆိုပြီး လေ့လာကြည့်မိတယ်။ Kotlin ဆိုတာက JetBrains ကနေပြီး အသစ်ထုတ်လိုက်လိုက်တဲ့ programming languge တစ်ခုပါပဲ။ သူက Java နဲ့ interoperability 100% ရှိတယ်။​ ပြောချင်တာက Compiler ကနေပြီး Java Byte Code ပြန်ထုတ်ပေးလို့ Java file တွေနဲ့ တွဲရေးလို့ရတယ်။ နောက်ထပ်ကောင်းတာတွေက ဘာလဲဆိုတော့ boilerplate code တွေလျှော့သွားတယ်၊ စိတ်ညစ်ဖို့ကောင်းလောက်အောင် ဒုက္ခပေးတဲ့ NullPointer Exception တွေမရှိသလောက်နည်းသွားမယ်၊​ Code ဖတ်ရတာပိုလွယ်လာမယ်။​

ကျွန်တော်တို့ project တစ်ခုအရင်ဆုံး create လုပ်ပါမယ်။ ကျွန်တော်ကတော့ Kotlin Tutorial လို့ပဲအလွယ်တကူနာမည်ပေးထားတယ်။ Minimum SDK တွေဘာတွေ စိတ်ကြိုက်ရွေးပြီးပြီ၊ Blank Activity ကိုရွေးပြီးပြီဆိုရင်တော့ create လုပ်လိုက်ပါ။ ပြီးရင်တော့ Android Studio မှာ Kotlin setup လုပ်ရမယ်။ ဒါကလည်း ဘာမှမခက်ဘူး။​ Plugin လေးသွင်းလိုက်ရုံပဲ။

Android Studio => Preferences => Plugins => Browse Repositry မှာ “Kotlin” ဆိုတဲ့ plugin ကို install လိုက်ပါ။
တစ်ခြား plugin တွေမလိုပါဘူး။​ “Kotlin” ဆိုတာကိုပဲသွင်းပါ။

Download ပြီး/Install ပြီးပြီဆိုရင် ကျွန်တော်တို့ Kotlin ကို Configure လုပ်ရမယ်။

Tools => Kotlin ထဲက “Configure Kotlin in Project” ကိုရွေးလိုက်ပါ။

Configurator ကို ရွေးခိုင်းရင်တော့ “Android With Gradle” ဆိုတာကို ရွေးပေးလိုက်ပါ။ OK နှိပ်ပြီးရင် app module ရဲ့ build.gradle file ပြောင်းသွားပါလိမ့်မယ်။ Gradle build ပြီးရင်တော့အဆင်ပြေသွားပါပြီ။

Directory Structure

ကြည့်ရရှင်းအောင်ရယ်၊ Java နဲ့ Kotlin file တွေမရောသွားအောင်ရယ် သက်သက်ခွဲထားမယ်။ ဒီလိုလုပ်ဖို့ app/src/main ထဲမှာ “kotlin” ဆိုပြီး directory အသစ်တစ်ခုလုပ်လိုက်ပါ။​ java လိုမျိုး အပြာရောင် directory လေးတစ်ခုပေါ်လာပါလိမ့်မယ်။ Android Studio ကနေပြီး Kotlin source code တွေက ဒီထဲမှာရှိပါလားဆိုပြီး သိလို့ အပြာရောင်လေးနဲ့ပြတာပါ။ java directory ထဲကလိုပဲ package တွေဆောက်လိုက်ပါ။​​ အောက်ကပုံလိုမျိုးလေးဖြစ်နေပါလိမ်မယ်။ ဒါတွေပြီးပြီဆိုရင်တော့ ပထမဆုံး kotlin file တစ်ခုဖန်တီးကြည့်ရအောင်။

MainActivity.java ကိုဖွင့်လိုက်ပါ။ ပြီးရင် Code => Convert Java File To Kotlin File ကိုရွေးလိုက်ပါ။ OK ထပ်နှိပ်ပါ။ ပြီးရင်တော့ သင့်ရဲ့ပထမဆုံး Kotlin file တစ်ခုကိုရပါပြီ။ kotlin နဲ့ java ကွဲနေအောင်လို့ထွက်လာတဲ့ MainActivity.kt file ကို ခုနကဆောက်ခဲ့တဲ့ directory အောက်ကို ရွေ့ပေးလိုက်ပါ။
Before Conversion

After Conversion

သတိထားမိမလားတော့မသိဘူး အရင်က 18 ကြောင်းကနေပြီးတော့ 12 ကြောင်းထိကျသွားပါတယ်။​​ ဘာလို့လဲဆိုရင် အပေါ်မှာ ပြောခဲ့တဲ့အတိုင်း boilerplate code တွေမရှိတော့လို့ပါ။ အားလုံးအဆင်ပြေ သွားရင်တော့ Run ကြည့်လို့ရပါပြီ။

သင့်ရဲ့ ပထမဆုံ: Kotlin နဲ့ရေးတဲ့ App လေးရပါပြီ :D

Introduction to 1Kotlin Syntax

MainActivity က Syntax တွေကိုလိုက်ဖတ်ကြည့်ရအောင်။ Line 1 က class တစ်ခုကို declare ထားတာဖြစ်တယ်။​ extends တို့ implements တို့ရေးရမဲ့အစား semicolon လေးတစ်ခုကို ရေးပေးလိုက်တာနဲ့ လုံလောက်ပါတယ်။ ဒီမှာဆို MainActivty (Kotlin class) က AppCompatActivity(Java class) ကို extends ထားတယ်။​ Kotlin က Java file တွေနဲ့တွဲရေးလို့ရတယ်ဆိုတာကို လက်တွေ့ မြင်နိုင်မဲ့ အချက်တစ်ခုပါ။

class MainActivity : AppCompatActivity() {

အရင်ကလို public void methodName(Parameters) အစား structure အသစ်တစ်ခုကိုမြင်ရမှာပါ။​ override ဆိုတာတော့သိပြီးသားဖြစ်မှာပါ။​ “fun” ဆိုတဲ့ keyword လေးကတော့ function လို့ပြောတာပါ။ parameters ကအရင်ကလို “dataType variableName” မဟုတ်တော့ပဲ ပြောင်းပြန် “variableName : dataType” ဆိုပြီးရေးရပါတယ်။

override fun onCreate(savedInstanceState: Bundle?) {

အဲဒါတွေပြီးပြီဆိုရင်တော့ return type ကိုထည့်ပေးရပါတယ်။ onCreate method က တော့ return type မရှိလို့ ဘာမှရေးစရာမလိုပါဘူး။ Compiler က return မပြန်ဘူးဆိုတာသိတဲ့အတွက်မရေးပဲထားခဲ့လို့ရပါတယ်။​ ရေးချင်သပဆိုရင်တော့ အောက်ကအတိုင်းရေးလို့ရတယ်။ ဒီမှာ “Unit” ဆိုတာက “void” လို့ပြောတာပါ။ ဒီလောက်ဆို function တစ်ခုဘယ်လိုရေးရလဲသိလောက်ပြီထင်ပါတယ်။ မှားတတ်တဲ့နေရာ က variableName အရင်လာတယ်ဆိုတာကို မေ့မေ့သွားတာပါပဲ။

override fun onCreate(savedInstanceState: Bundle?) : Unit {

function ထဲက code တွေမှာ တစ်ခုခုလိုနေတယ်လို့ သတိထားမိလား? ဟုတ်ပါတယ်။ statement ဆုံးတိုင်း semicolon လေးတွေလိုက်ထည့်စရာ မလိုတော့ဘူး။ semicolon ကျန်ခဲ့တာမျိုးမဖြစ်တော့ပါဘူး။ ထည့်ချင်ရင်လည်း ထည့်လို့ရပါတယ်၊ မမှားပါဘူး။​ ဆက်ကြည့်မယ်ဆိုရင် toolbar ကို declare လုပ်ထားတာတွေ့ရမယ်။ ဒါကိုဆက်မသွားချင် Variable တွေဘယ်လို declare လုပ်ရလဲ ဆိုတာအရင်ပြောချင်ပါတယ်။

Value & Variables

Kotlin မှာ Value နဲ့ Variable ဆိုပြီးနှစ်မျိုးရှိတယ်။ Value ဆိုတာကတော့ constant(ကိန်းသေ တန်ဖိုး) တွေကို သတ်မှတ်တဲ့အခါမှာ သုံးတယ်။ Value ကို “val” keyword နဲ့ သုံးပြီး variable ကို “var” နဲ့သုံးတယ်။ တကယ်လို့ constant value တစ်ခုကို ထပ်ပြီး Assign လုပ်ရင် Compiler ကနေ အဲဒီ Assign လုပ်ထားတဲ့ statement ကိုကျော်သွားတယ်။ ဒီတော့ constant တစ်ခုက ဒါဆိုဒါပဲ ဖြစ်နေမှာ ကျိန်းသေတယ်။ မှားပြီး assignment လုပ်မိစရာအကြောင်းမရှိတော့ဘူး။

val x = 1 //Int
x = 3 //Does not Compile, it's a constant value
var y = x * 2 //Int
val z = "Hello, Kotlin" //String

အပေါ်မှာကြည့်မယ်ဆိုရင် variable/value တွေ declare လုပ်တဲ့အခါ DataType ကို ထည့်ရေးစရာလိုဘူး။ Compiler ကနေ ဘယ်ဟာကတော့ ဘာ type ဆိုတာ ဆုံးဖြတ်တတ်တယ်။ တကယ်လို့သေချာအောင်လို့ ဆိုရင်တော့ အောက်ကအတိုင်းရေးလို့ရတယ်။ ဒီမှာလည်း function တုန်းကလိုမျိုးပဲ Type က variable name နောက်ကနေလိုက်ပါတယ်။

val price : Int = 100

Int ကိုဘာလို့ i အသေးနဲ့မရေးတာလဲ?

Kotlin မှာ အကုန်လုံးကို object တွေနဲ့ဖွဲ့စည်းထားတာကြောင့် primitive data type ဆိုတာမရှိတော့ပါဘူး။

ဒါဆို memory ပိုကုန်တာပေါ့လို့ ပြောစရာရှိတယ်။ မပူပါနဲ့။ Compile လုပ်တဲ့အခါ ပြောင်းလို့ရသမျှကို primitve data type အဖြစ်ပြောင်းပေးလို့ memory ပိုကုန်တာမျိုးမရှိပါဘူး။

Null Safety

ကျွန်တော်အပေါ်မှာ မပြောပဲချန်ထားခဲ့တာတစ်ခုရှိပါတယ်။ onCreate Function ရဲ့ parameter မှာ Bundle? ဆိုပြီး ? လေးအပိုပါနေပါတယ်။ Kotlin မှာကောင်းတဲ့ အချက်တစ်ခုက ဘယ်အရာမှ အလိုအလျှောက် null မဖြစ်ပါဘူး၊​ ကိုယ်တိုင် null ဖြစ်နိုင်တယ်လို့ ရေးတော့မှ null assignment ကိုလက်ခံပါတယ်။ “?” ဆိုတာလေးကတော့ nullable object (null ဖြစ်နိုင်တဲ့ object) လို့ပြောချင်တဲ့အခါမှာ သုံးပါတယ်။

val a : String = null //Cannot compile
val b : String //Cannot compile, no initial value

val c: String? = null //Will compile
val d = c?.substring(1);

ဒီလိုရေးချင်းအားဖြင့် အဖြစ်များတဲ့ NullPointerException ကိုလျှောင်လျားနိုင်ပါတယ်။ အပေါ်မှာဆို c က null မဟုတ်ဘူးဆိုတာ့မှ variable “d” ထဲကို assign လုပ်မယ်။ တကယ်လို့ c က null ဆိုရင် d assign လုပ်တဲ့ line ကို ကျော်သွားပြီ ကျန်တာဆက် run သွားပါလိမ့်မယ်။​ ဒီလိုမျိုး NullPointerException တက်မဲ့နေရာကို ကျော်သွားလို့ safe ဖြစ်တယ်လို့ပြောလို့ရပါတယ်။

val c: String? = getUserInput();
val d = c?.substring(1);
val e = d?.capitalize();
val f = e?.indexOf("a");

တကယ်လို့ အပေါ်ကလို တန်ဖိုးတွေကိုဆက်ပြီး manipulate လုပ်သွားမယ်ဆိုရင် ? တွေသုံးရတာတအားများလာမယ်။​ ဒီလိုအခါမျိုးကျရင် c ကို null check လုပ်ပေးလိုက်ရင် ? တွေလိုက်ထည့်စရာမလိုတော့ပါဘူး။

val c: String? = getUserInput();
if (c != null) {
    val d = c.substring(1);
    val e = d.capitalize();
    val f = e.indexOf("a");
}

ဖတ်ရတဲ့ code တွေပိုများသွားပြီ။​ ဒီတော့ ပိုကောင်းအောင်ဘယ်လိုရေးကျမလဲ? Kotlin မှာ Elvis Opeator ဆိုတာအသစ်ပါလာပါတယ်။

Elvis Opeartor ကို ?: keyword နဲ့သုံးရပါတယ်။ သူကဘာလုပ်ပေးတာလဲဆိုတော့ null ဖြစ်နေခဲ့ရင် null အစားထိုးသုံးဖို့ value တစ်ခုသတ်မှတ်ပေးလို့ရပါတယ်။

အောက်မှာဆိုရင် တကယ်လို့ user ကဘာမှထည့်မပေးလိုက်ရင် “Hello World” ဆိုတဲ့ String ကိုပြောင်းသုံးသွားမှာပါ။

val c = getUserInput() ?: "Hello, World";
val d = c.substring(1);
val e = d.capitalize();
val f = e.indexOf("a");
Null Safety ကိုစိတ်ဝင်စားရင် https://kotlinlang.org/docs/reference/null-safety.html မှာဆက်ဖတ်ကြည့်လို့ရပါတယ်။

Variable အကြောင်းတွေပြောလိုက်တာတော်တော်လေးများသွားပြီ။ အစပြန်ကောက်ရရင် MainActivity မှာ Toolbar Decleration ကိုကြည့်မယ်ဆိုရင် as Toolbar ဆိုပြီးရေးထားပါတယ်။​ ဖတ်ကြည့်တာနဲ့ရှင်းပါတယ်။ “as” keyword က Type Casting လုပ်ရင်သုံးပါတယ်။ ဒီမှာလည်း return ပြန်လာမှာက null ဖြစ်နိုင်လို့ ? ထည့်သုံးထားတာတွေ့နိုင်ပါတယ်။

val toolbar = findViewById(R.id.toolbar) as Toolbar?

Lambda Expression

Lambda Expression ဆိုတာကတော့ နာမည်မပါပဲရေးတဲ့ function(Anonymous Function) တွေမှာ အဓိကသုံးတယ်။ ဒီလိုရေးခြင်းအားဖြင့် တစ်ခါပဲရေးပြီး ပြန်မသုံးတောမဲ့ function တွေ ပွထနေတာမျိုးမရှိတော့လို့ boilerplate code တွေလည်း နည်းသွားမယ်။ ဥပမာ FAB မှာ OnClickListener ထည့်ထားတဲ့ line ကိုကြည့်မယ်ဆိုရင် Lambda expression နဲ့ရေးထားတာကိုတွေ့ရမှာဖြစ်ပါတယ်။ ကျွန်တော်တို့ onClickListener မှာ Override လုပ်စရာ onClick တစ်ခုပဲရှိတယ်။ ဒီတော့ onClick ကိုဖျောက်ပြီးရေးလို့ရတယ်။ onClick တစ်ခုတည်းပဲရှိတဲ့အတွက် တစ်ခြား function တွေနဲ့မှားစရာအကြောင်းလည်းမရှိဘူး။ Lamda Expression အသုံးပြုပုံကိုအကြမ်းဖျင်းကြည့်မယ်ဆိုရင်

  1. Lambda Expression က လက်သည်းကွင်း နှစ်ခုကြားမှာရှိတယ်။
  2. -> ရဲ့ရှေ့မှာ function ရဲ့ parameters ကိုရေးရတယ်။
  3. -> ရဲ့နောက်မှာ ကိုယ်လုပ်မဲ့ statment တွေကိုရေးပေးရတယ်။ ဒါကိုတော့ function ရဲ့ body လို့ခေါ်တယ်။
fab?.setOnClickListener(View.OnClickListener{ view ->
   //body
});

ဒီမှာကျွန်တော်တို့ View.OnClickListener ရှေ့မှာ new keyword ကိုသုံးစရာမလိုပါဘူး။ Kotlin မှာ Object အသစ်တစ်ခုဆောက်တိုင်း new ကိုရှေ့ကထည့်ပေးစရာမလိုပါဘူး။ ဒီထက်ပိုပြီးတိုအောင်ရေးမယ်ဆိုရင် Constructor ကိုဖျောက်ပြီးတော့ ရေးလို့ရပါတယ်။ အထဲမှာ View.OnClickListener ပဲရှိနိုင်တာကို compiler ကနေပြီးသိလို့ မရေးလည်း ကိစ္စမရှိပါဘူး။

fab?.setOnClickListener({ view ->
   //body
});
Higher-Order Functions နဲ့ lambda ရေးနည်းကိုစိတ်ဝင်စားရင် https://kotlinlang.org/docs/reference/lambdas.html မှာဖတ်ကြည့်လို့ရပါတယ်။

Conclusion

ပြောချင်တာတွေလည်းများနေလို့ နောက်တစ်ပိုင်းကျရင် Extension Function တွေအကြောင်း၊ Android Extensions တွေ၊ Data Class တွေ အစရှိတာတွေ ကိုဆက်လက်ဖော်ပြသွားပါမယ်။ ကျွန်တော်လည်း စလေ့လာတာမကြာသေးလို့ အမှားပါသွားရင် ခွင့်လွှတ်ပေးကြပါလို့။ :D