https://www.baeldung.com/kotlin-sealed-classes
Sealed Classes in Kotlin

.

.

.

.

https://youtu.be/o1Occux4qR8

.

.

.

.

https://youtu.be/o1Occux4qR8./

.

.

.

.

https://www.charlezz.com/?p=43886

.

.

.

.

https://youtu.be/E-yXefhLjNU

https://www.journaldev.com/18688/kotlin-enum-class

가장 좋은 설명

Enumerations in Kotlin are data types that hold a set of constants. Enums are defined by adding the modifier enum in front of a class as shown below. Yes, in Kotlin, Enums are classes.


enum class Months{
    January,
    February,
    March
}

Here are some important points about enum classes in kotlin.

  • Each enum constant is an object. Enum constants are separated by commas.
  • Each of the enum constants acts as separate instances of the class.
  • Enums are useful in enhancing the readability of your code since it assigns pre-defined names to constants.
  • Unlike classes, an instance of enum classes cannot be created using constructors.
  • Hence, we can assert that enum classes are abstract.

Let’s see how the enum class is initialized in the main function of our class.


fun main(args: Array<String>) {

    println(Months.January) //prints January
    println(Months.values().size) //prints 3
    println(Months.valueOf("March")) //prints March

    for (enum in Months.values()) {
        println(enum.name)
    }

    println(Months.valueOf("Mar")) //throws java.lang.IllegalArgumentException: No enum constant Months.Mar
}

Few inferences from the above code:

Let’s see how to tackle this scenario.


fun enumContains(name: String): Boolean {
    return enumValues<Months>().any { it.name == name }
}

fun main(args: Array<String>) {

    if (enumContains("")) {
        println(Months.valueOf(""))
    } else {
        println("The string value does not match with any of the enum constants.") //this gets printed.
    }

}

enumContains is a function that calls the lambda function any which iterates over the enum constants to check if any of them matches the string and returns a boolean.

Enum Properties

Every enum constant has properties: name, ordinal to retrieve the name and position of the constant.


fun main(args: Array<String>) {
    
    println(Months.January.name) //prints January
    println(Months.March.ordinal) // prints 2
    for (enum in Months.values()) {
        println(enum.name)
    }
}

Enum toString()

We can override the toString() function in the enum class as shown below.


enum class Months {
    January,
    February,
    March;

    override fun toString(): String {
        return super.toString().toUpperCase()
    }
}

fun main(args: Array<String>) {
    println(Months.January) //prints JANUARY
    println(Months.January.name) //prints January
     println(Months.valueOf("March")) //prints MARCH
}

Enums are classes. So besides defining the constants we can define other things as well that can be present in a class. To do so we need to first end the enum part with a semi colon.
Note: Month.January invokes the toString() method of the class whereas Month.January.name directly prints the enum constant’s name.

Enum Initialisation

Enum constants can be initialized using primary constructors as shown below.


enum class Months(var shorthand: String) {
    January("JAN"),
    February("FEB"),
    March("MAR");
}

fun main(args: Array<String>) {

    var x = Months.January
    println(x.shorthand) //prints JAN
    x.shorthand = "Shorthand changed to J."
    println(Months.January.shorthand) //prints Shorthand changed to J.
}

Enums as Anonymous classes

Enum constants can behave as anonymous classes be implementing their own functions along with overriding base functions from the class as shown below.


enum class Months(var shorthand: String) {
    January("JAN"){
        override fun printSomething() {
            println("First month of the year.")
        }
    },
    February("FEB"){
        override fun printSomething() {
            println("Second month of the year.")
        }
    },
    March("MAR"){
        override fun printSomething() {
            println("Third month of the year.")
        }
    };
    var a: String = "Hello, Kotlin Enums"
    abstract fun printSomething()
}

fun main(args: Array<String>) {
    Months.February.printSomething() //prints Second month of the year.
    println(Months.February.a) //prints Hello, Kotlin Enums
}

Each of the enum constants must override

Enum inside an Enum

It’s possible to define another enum class in the current enum class as shown below.


enum class Months {
    January,
    February,
    March;

    enum class Day{
        Monday,
        Tuesday,
        Wednesday
    }
}

fun main(args: Array<String>) {
    println(Months.Day.Tuesday) //prints Tuesday
}

Only an enum class can invoke another one. The inner class Day cannot be invoked from the enum constants.

Enums and when

when is Kotlin equivalent of switch in Java. We’ve covered the workings of it in the Control Flow tutorial.
An example showing how when statements are used with enums is given below.


enum class Months {
    January,
    February,
    March;
}

fun main(args: Array<String>) {

    var m = Months.February

    when (m) {
        Months.January  -> print("Matches with Jan")
        Months.February -> print("Matches with Feb") //prints this.
        Months.March -> print("Matches with Mar")
    }
}

This brings an end to kotlin enum tutorial.

References: Kotlin Docs

.

.

.

.

https://youtu.be/or_HJ6NGLxc
kotlin enum basic 설명

image
image

.

.

.

.

https://youtu.be/jc9AZfZs7kY

enum class

image
image
image

.

image
image

.

image
image

.

.

.

.

https://www.baeldung.com/kotlin-enum
Working with Enums in Kotlin

.

.

.

.

내가 정리한 enum class

  • child class는 parent constructor 를 그대로 구현해야 한다. 
  • parent constructor가 없으면 child에도 constructor는 없다.
  • parent class안에 abstract로 정의된 func은 모든 child 가 구현해야 한다.
  • parent class안에 abstract로 정의되지 않은 함수를 child안에 새로 만들수 있다.
  • child class는 각각 , 로 구분한다. child class정의 마지막은 ;를 사용한다. 
  • parent class는 abstract method, abstract property를 가질수 있다. (sealed class도 같다)


sealed class의 경우 parent constructor가 정의되어있지 않더라도 child class 는 constructor를 가질수 있다. 각 class 정의 사이에 구분자는 없다. (정의부분 뒤에 enum의 경우 , 가 붙는데 sealed class의 경우는 없다는 이야기)

sealed class BasicGarment2(){
   class CLEAN_PRESS(var name:String, var price:BigDecimal): BasicGarment2()
   class CLEAN_ONLY(): BasicGarment2()
}

 

enum class BasicGarment(val na: String, val price:BigDecimal){
   CLEAN_PRESS("a",10.toBigDecimal()){
       override fun calculatePrice(): BigDecimal {
           return 10.toBigDecimal()
       }

       fun foo(){
           println("test func")
       }

       override var testVar: String
           get() = TODO("Not yet implemented")
           set(value) {}
   },
   CLEAN_ONLY("nam", 10.toBigDecimal()){
       override fun calculatePrice(): BigDecimal {
           return 10.toBigDecimal()
       }

       override var testVar: String
           get() = TODO("Not yet implemented")
           set(value) {}
   };
   abstract fun calculatePrice():BigDecimal
   abstract var testVar :String
}

.

.

.

.

https://www.geeksforgeeks.org/enum-classes-in-kotlin/

original source : https://medium.com/incwell-innovations/passing-data-in-android-navigation-architecture-component-part-2-5f1ebc466935

navigation에서 fragment간 이동시 data를 전달하는 2가지 방법 


1. Type Unsafe Way

app_nav.xml 

<?xml version="1.0" encoding="utf-8"?>
<navigation 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/app_nav"
   app:startDestination="@id/nav_main">
   <fragment
       android:id="@+id/nav_main"
       android:name="com.smartmobe.navigation.MainFragment"
       android:label="Main"
       tools:layout="@layout/fragment_main" >
       <action
           android:id="@+id/action_nav_main_to_nav_dashboard"
           app:destination="@id/nav_dashboard" />
   </fragment>
   <fragment
       android:id="@+id/nav_dashboard"
       android:name="com.smartmobe.navigation.DashboardFragment"
       android:label="Dashboard"
       tools:layout="@layout/fragment_dashboard" >
       <argument
           android:name="username"
           app:type="string" />
   </fragment>
</navigation>

To use the bundleOf() is the extension method of androidx. For that we need the dependency:

implementation 'androidx.core:core-ktx:1.0.0-alpha3'

Receive data in destination fragment as :

.

.

.

2. Type Safe Way

https://developer.android.com/training/data-storage/room/accessing-data

@Dao
interface MyDao {
   @Insert(onConflict = OnConflictStrategy.REPLACE)
   fun insertUsers(vararg users: User)

   @Insert
   fun insertBothUsers(user1: User, user2: User)

   @Insert
   fun insertUsersAndFriends(user: User, friends: List<User>)
}

.

update

@Dao
interface MyDao {
   @Update
   fun updateUsers(vararg users: User)
}

.

delete

@Dao
interface MyDao {
   @Delete
   fun deleteUsers(vararg users: User)
}

.

query

@Dao
interface MyDao {
   @Query("SELECT * FROM user")
   fun loadAllUsers(): Array<User>
}
@Dao
interface MyDao {
   @Query("SELECT * FROM user WHERE age > :minAge")
   fun loadAllUsersOlderThan(minAge: Int): Array<User>
}
@Dao
interface MyDao {
   @Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
   fun loadAllUsersBetweenAges(minAge: Int, maxAge: Int): Array<User>

   @Query("SELECT * FROM user WHERE first_name LIKE :search " +
          "OR last_name LIKE :search")
   fun findUserWithName(search: String): List<User>
}

.

더 많은 내용이 있는데 web page 참조

https://youtu.be/v4XO_y3RErI

40분 분량 java coding with mitch

image

product는 xml안에서 사용할 변수 이름이고 보통 obj, data class obj를 담게 된다. type은 obj의 class

.

.

image

.

.

image

.

.

image

일반 함수를 사용할수 있다. (정확히 어떤 함수가 일반 함수에 해당하는지는 확인요망)

.

.

image

외부의 class를 xml내로 가져와 사용하고자 하는 경우

.

.

image

이 강의에서는 StringUtil이라는 helper class를 xml에 가져와 사용하는 것을 가정한다.

.

.

image

 xml안 변수로 사용하게될 class Product 의 내부함수를 xml에서 사용하는 것을 보여준다.

.

.

image

xml안 변수로 사용하게될 class Product 의 내부함수를 xml에서 사용하는 것을 보여준다.

.

.

image

xml내로 android view class를 import 해서 가져와 view의 속성을 변경하는 것을 보여준다.

.

.

image

클릭 이벤트 처리를 위한 interface

.

.

image

클릭이벤트를 이 강의에서는 activity가 처리한다고 가정한다.

.

.

image

클릭이벤트를 위한 interface를 implement한다.

.

.

image

클릭이벤트를 처리하는 class를 변수로 가져온다.

.

.

image

.

.

image

클릭이벤트 처리를 외부로 보낸다.

.

.

image

binding adapter를 통해 view를 외부로 보내 추가 처리를 하는 것을 보여준다. 이강의에서는 glide를 사용하는 것을 보여준다.

.

.

image

app:바인딩어댑터이름   즉 @BindingAdapter() 안에 들어간 이름

.

.

.

.

========================================================================================================================

https://medium.com/androiddevelopers/no-more-findviewbyid-457457644885

android {
   …
   dataBinding.enabled = true
}

<layout xmlns:android=“http://schemas.android.com/apk/res/android”
       xmlns:tools=“http://schemas.android.com/tools”>
   <RelativeLayout
           android:layout_width=“match_parent”
           android:layout_height=“match_parent”
           android:paddingLeft=“@dimen/activity_horizontal_margin”
           android:paddingRight=“@dimen/activity_horizontal_margin”
           android:paddingTop=“@dimen/activity_vertical_margin”
           android:paddingBottom=“@dimen/activity_vertical_margin”
           tools:context=“.MainActivity”>

       <TextView
               android:id=“@+id/hello”
               android:layout_width=“wrap_content”
               android:layout_height=“wrap_content”/>

   </RelativeLayout>
</layout>

HelloWorldBinding binding =
   DataBindingUtil.setContentView(this, R.layout.hello_world);
binding.hello.setText(“Hello World”); // you should use resources!

.

.

https://medium.com/androiddevelopers/android-data-binding-that-include-thing-1c8791dd6038

hello_world.xml<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <LinearLayout
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:orientation="vertical">

       <TextView
               android:id="@+id/hello"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"/>
       <include
               android:id="@+id/included"
               layout="@layout/included_layout"/>
   </LinearLayout>
</layout>
included_layout.xml<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <TextView
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:id="@+id/world"/>
</layout>
HelloWorldBinding binding =
   HelloWorldBinding.inflate(getLayoutInflater());
binding.hello.setText(“Hello”);
binding.included.world.setText(“World”);

.

.

https://medium.com/google-developers/android-data-binding-adding-some-variability-1fe001b3abcc

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable
           name="user"
           type="com.example.myapp.model.User"/>
   </data>
   <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
       <ImageView
               android:src="@{user.image}"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"/>
       <TextView
               android:text="@{user.firstName}"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"/>

       <TextView
               android:text="@{user.lastName}"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"/>
   </LinearLayout>
</layout>

You can see in the layout above that the Views no longer have IDs. (above)


private void setUser(User user, ViewGroup root) {
   UserInfoBinding binding =
       UserInfoBinding.inflate(getLayoutInflater(), root, true);
   binding.setUser(user);
}

——————————————————————————————-


user_name.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable
               name="user"
               type="com.example.myapp.model.User"/>
   </data>

   <LinearLayout
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:orientation="horizontal">
       <TextView
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.firstName}"/>

       <TextView
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:app="http://schemas.android.com/apk/res-auto">
   <data>
       <variable
               name="user"
               type="com.example.myapp.model.User"/>
   </data>
   <LinearLayout
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:orientation="vertical">
       <ImageView
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:src="@{user.image}"/>
       <include
               layout="@layout/user_name"
               app:user="@{user}"/>
   </LinearLayout>
</layout>

.

.

https://medium.com/androiddevelopers/android-data-binding-express-yourself-c931d1f90dfe

The expression parser automatically tries to find the Java Bean accessor name (getXxx() or isXxx()) for your property. The same expression will work fine when your class has accessor methods. (기본적으로 xml에 @{a.bbb}가 있다고 한다면 parser가 알아서 a 클래스에서 getbbb()를 찾고 없다면 bbb()를 사용한다는 이야기 이다.)

If it can’t find a method named like getXxx(), it will also look for a method named xxx(), so you can use user.hasFriend to access method hasFriend().

Android Data Binding expression syntax also supports array access using brackets, just like Java:

android:text="@{user.friends[0].firstName}"

It also allows almost all java language expressions, including method calls, ternary operators, and math operations.

there is a null-coalescing operator ?? to shorten the simple ternary expressions:(즉 ?? 사용가능하다는 이야기)

android:text=”@{user.firstName ?? user.userName}”

which is essentially the same as:

android:text=”@{user.firstName != null ? user.firstName : user.userName}”

One really cool thing you can do with binding expressions is use resources:

android:padding=”@{@dim/textPadding + @dim/headerPadding}

You can also use string, quantity, and fraction formatting following the syntax from Resources methods getString, getQuantityString, and getFraction. You just pass the parameters as arguments to the resource:

android:text=”@{@string/nameFormat(user.firstName, user.lastName)}”

One very convenient thing is that data binding expressions always check for null values during evaluation. That means that if you have an expression like:

android:text=”@{user.firstName ?? user.userName}”

If user is null, user.firstName and user.userName will evaluate to null and the text will be set to null. No NullPointerException.

This doesn’t mean that it is impossible to get a NullPointerException. If, for example, you have an expression:

android:text=”@{com.example.StringUtils.capitalize(user.firstName)}”

And your StringUtils had:

public static String capitalize(String str) {
   return Character.toUpperCase(str.charAt(0)) + str.substring(1);
}

You’ll definitely see a NullPointerException when a null is passed to capitalize.

Importing

In the example above, the expression to capitalize the name was very long. What we really want is to be able to import types so that they can be used as a shortened expression. You can do that by importing them in the data section:

<data>
   <variable
       name="user"
       type="com.example.myapp.model.User"/>
   <import
       type="com.example.StringUtils"/>
</data>

Now our expression can be simplified to:

android:text=”@{StringUtils.capitalize(user.firstName)}”

(본래는 android:text=”@{com.example.StringUtils.capitalize(user.firstName)}” 이렇게 쓸것을 줄인결과)

Expressions are pretty much Java syntax with the few exceptions mentioned above. If you think it will work, it probably will, so just give it a go.

.

.

https://medium.com/androiddevelopers/android-data-binding-the-big-event-2697089dd0d7

data binding에서 listener를 view에 덧붙이는 방법은 아래와 같이3가지가 있다. 

1. Listener Objects

<View android:onClickListener="@{callbacks.clickListener}" .../>

간단하게 줄여서 아래와 같이 할수도 있다.

<View android:onClick="@{listeners.clickListener}" .../>
public class Callbacks {
   public View.OnClickListener clickListener;
}

2. Method References


<EditText
   android:afterTextChanged="@{callbacks::nameChanged}" .../>

public class Callbacks {
   public void nameChanged(Editable editable) {
       //...
   }
}

아래와 같이 논리구조를 추가해서 상황에 따라 다른 리스너를 이용할수도 있다.

<EditText android:afterTextChanged=
   "@{user.hasName?callbacks::nameChanged:callbacks::idChanged}"
   .../>

3. Lambda Expressions

https://developer.android.com/reference/android/text/TextWatcher#afterTextChanged(android.text.Editable)

본래 afterTextChanged는 Editable 를 parameter로 받는다. 아래서 e는 Editable이다.

<EditText
android:afterTextChanged="@{(e)->callbacks.textChanged(user, e)}"
... />
public class Callbacks {
public void textChanged(User user, Editable editable) {
if (user.hasName()) {
//...
} else {
//...
}
}
}

.

.

https://medium.com/androiddevelopers/android-data-binding-lets-flip-this-thing-dc17792d6c24

@={}


<EditText
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@={user.firstName}"/>

아래에서는 xml에 있는 다른 view의 id를 이용 접근하는 것을 보여주고 있다.

<CheckBox
   android:id="@+id/showName"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/> <TextView
   android:text="@{user.firstName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:visibility="@{showName.checked ? View.VISIBLE : View.GONE}"
   />


<CheckBox
   android:id="@+id/showName"
   android:focusableInTouchMode="@{model.allowFocusInTouchMode}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/> <TextView
   android:text="@{user.firstName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:focusableInTouchMode="@{showName.focusableInTouchMode}"
   />

<EditText
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:id="@+id/firstName"
   android:text="@={user.firstName}" /> <CheckBox
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:onCheckedChanged="@{()->handler.checked(firstName)}" />