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)}" />

original source : https://www.youtube.com/playlist?list=PLEPZdzLLJH94Jk_Jz-cTUXYFoObPBH7KB

시애틀에 있는 수염난 안경낀 백인 청년 설명

image

.

image

.

image

.

image

.

data binding을 위해서 gradle에서 해야할 작업

image

.

data binding의 장점

image

.

image

.

image

.

3rd party image loading library들 이 강의에서는 coil을 사용

image

.

toolbar를 app bar로 사용하면서 navigation component를 사용하는 경우

image

.

tool bar를 app bar로 사용하는 경우 약간의 material 느낌을 주기위해 AppBarLayout를 이용한 경우

image

.

coil를 사용해 image loading한경우

image

.

json converting을 위해 moshi를 사용한 경우

image

.

retrofit 

image

.

.

.

민감한 data를 외부에 놓고 사용하는 방법

image
image
image

.

.

.

외부에서 전달되는 json data의 키와는 다른 field명을 쓰고 싶을때

image

.

외부와 data 통신시에 보안을 위해 usesCleartextTraffic을 사용한다.

image

.

.

.

.

1강

0:01 – Week 0 Review

1:22 – Syllabus Review

2:40 – Class Announcements

6:14 – Why Learn App Development?

9:26 – Challenges of App Development

15:34 – Types of Mobile Development

22:36 – Why Android Development?

27:42 – Setting Up Our Android Development Environment

28:34 – Installing Android Studio

36:12 – Creating Your First Android Studio Project

39:17 – Creating An Android Emulator

41:52 – Installing Your First Android App

45:14 – Sharing An Android Studio Project to GitHub

50:06 – Building An Android APK

– What are the unique benefits and challenges of Android app development?

– What are some different ways of building mobile apps?

– What makes Android the most popular mobile operating system?

– What is Android Studio?

– What is the Android Emulator?

– What is Kotlin?

– How do you create a new Android project?

– How do you share code from Android Studio to GitHub?

– How do you add a README to your GitHub repo?

.

.

.

.

2강

0:36 – Outline

1:57 – Android Framework Components

14:07 – What is generated when you create a new Android Studio project?

40:26 – Working with Android Activities

41:20 – Android Activity lifecycle

50:12 – Using the Android Studio debugger // How to set a breakpoint in Android Studio?

59:38 – Creating Interactive User Interfaces

1:01:46 – What is FrameLayout?

1:05:09 – What is LinearLayout?

1:08:34 – What is RelativeLayout?

1:14:22 – What is ConstraintLayout?

1:28:09 – Responding To User Interaction

1:29:00 – ConstraintLayout simple tutorial

1:29:37 – How to create a new Vector Asset in Android Studio?

1:38:46 – How to respond to a Button click in Android

1:40:04 – Android Button setOnClickHandler

1:45:40 – Receiving user input using an EditText

1:54:00 – Customize Material Design theme in Android Studio

– What are the Android app components?

– What is an Android Activity?

– What is generated when we create a new Android Studio project?

– What is the Android Activity lifecycle?

– What is the difference between an Android ViewGroup and a View?

– What is a FrameLayout? LinearLayout? Relative Layout? ConstraintLayout?

– How to build a simple UI using ConstraintLayout?

– How do define an Android click listener?

– How to show a Toast message in an Android Activity?

– How to enable Android developer options?

– How to use an EditText to receive user input?

.

.

.

.

3강

– How to display dynamic content in an app?

– How to display large collections of data?

– How to architect your app to provide data to your Activity?

– What is MVVM?

– What is LiveData?

– How to model data with Kotlin data classes?

– How to create a RecyclerView Adapter?

– How to bind data using a RecyclerView ViewHolder?

– How to define an onClickHandler for your RecyclerView?

– How to format String resources?

.

0:25 – Outline

2:17 – Project Demo

3:56 – Displaying Dynamic Data

5:05 – Dynamic view containers // ScrollView, ListView, ViewPager

6:57 – RecyclerView

7:50 – Why RecyclerView?

16:47 – Defining A Data Model

20:00 – Modeling data with Kotlin data classes

24:25 – What is LiveData?

28:08 – Implementing A RecyclerView

29:23 – Creating a data class to model daily weather forecasts

31:50 – Creating a data repository

32:04 – Using LiveData to expose data from a repository

49:54 – Adding a RecyclerView to your layout xml file

52:37 – How to use Logcat to understand why your app crashed

54:58 – Add RecyclerView dependency to your build.gradle file

57:52 – How to add margin to your RecyclerView using ConstraintLayout design view?

1:01:57 – How to implement a RecyclerView Adapter using Kotlin?

1:30:38 – Add touch feedback to RecyclerView list items

1:40:00 – How to format String resources?

.

.

.

.

4강

– How to create a new Android Activity?

– How to use an Intent to open a new Activity when a button is clicked?

– How to display an options Menu

– How to respond to a Menu item click?

– How to display an AlertDialog?

– How to save a value using SharedPreferences?

.

.

.

.

5강

– How to create a new Fragment

– How to migrate UI/logic from an Activity to a Fragment

– How to communicate between a Fragment and an Activity

– How to add a FloatingActionButton to your UI

.

.

.

.

6강

– What is the Android Navigation Architecture Component?

– What problems is it trying to solve?

– How to create a navigation graph?

– How to add new destinations and actions to your navigation graph?

– How to navigate to a new Fragment using the NavController?

– How to update your AppBar based on navigation changes?

– How to implement a BottomNavigationView?

.

.

.

.

7강

– How to load data from a remote api using Retrofit; an HTTP client library for Android/JVM?

– How to listen to changes in SharedPreferences values?

– How to load and display remote images using the Coil image loading library

.

.

.

.

original source : https://kotlinlang.org/docs/reference/properties.html#backing-fields

https://codelabs.developers.google.com/codelabs/kotlin-android-training-recyclerview-fundamentals/index.html?index=..%2F..android-kotlin-fundamentals#3

var data =  listOf<SleepNight>()
   set(value) {
       field = value
       notifyDataSetChanged()
   }

이를 보다가 찾아 보게된 자료이다.

.

.

Backing Fields

Fields cannot be declared directly in Kotlin classes. However, when a property needs a backing field, Kotlin provides it automatically. This backing field can be referenced in the accessors using the   field   identifier:

var counter = 0 // Note: the initializer assigns the backing field directly
   set(value) {
       if (value >= 0) field = value
   }

The field identifier can only be used in the accessors of the property.

A backing field will be generated for a property if it uses the default implementation of at least one of the accessors, or if a custom accessor references it through the   field   identifier.

For example, in the following case there will be no backing field:

val isEmpty: Boolean
   get() = this.size == 0

kotlin android codelab 강좌에서 본적이 있음.

LiveData를 사용하기 위해서 MutableLiveData를 사용했음. 그와 비슷한 원리이다.

Backing Properties

If you want to do something that does not fit into this “implicit backing field” scheme, you can always fall back to having a backing property:

private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
   get() {
       if (_table == null) {
           _table = HashMap() // Type parameters are inferred
       }
       return _table ?: throw AssertionError(“Set to null by another thread”)
   }

On the JVM: The access to private properties with default getters and setters is optimized so no function call overhead is introduced in this case.

java의 field와 kotlin에서의 property의 개념 차이

https://blog.kotlin-academy.com/kotlin-programmer-dictionary-field-vs-property-30ab7ef70531

This is an example of a Java field:

public String name = "Marcin";

Here is an example of a Kotlin property:

var name: String = "Marcin"

They both look very similar, but these are two different concepts. Direct Java equivalent of above Kotlin property is following:

private String name = "Marcin";
public String getName() {
   return name;
}public void setName(String name) {
   this.name = name;
}

The default implementation of Kotlin property includes field and accessors (getter for val, and getter and setter for var). Thanks to that, we can always replace accessors default implementation with a custom one. For instance, if we want to accept only non-blank values, then we can define the following setter:

var name: String = "Marcin"
   set(value) {
       if (value.isNotBlank())
           field = value
   }name = "Marcin"
name = ""
print(name) // Prints: Marcin

If we want to be sure that the returned property value is capitalized, we can define a custom getter which capitalizes it:

var name: String = "Marcin"
   get() = field.capitalize()name = "marcin"
print(name) // Prints: Marcin

The key fact regarding properties is that they actually are defined by their accessors. A property does not need to include any field at all. When we define custom accessors that are not using any field, then the field is not generated:

var name: String
   get() = "Marcin"

This is why we can use property delegation. See example of property delegate below:

var name: String by NameDelegate()

Above code is compiled to the following implementation:

val name$delegate = NameDelegate()
var name: String
   get() = name$delegate.getValue(this, this::name)
   set(value) { name$delegate.setValue(this, this::name, value) }

Moreover, while a property is defined by its accessors, we can specify it in the interface:

interface Person {
   val name: String
}

Such declaration means that there must be a getter defined in classes that implement interface Person.

As you can clearly see, Kotlin properties give developers much bigger possibilities than Java fields. Yet, they look nearly the same and Kotlin properties can be used exactly the same as Java fields. This is a great example, how Kotlin hides complexity under the carpet and gives us possibilities even if some developers remain unaware of them.

This post is the fourth part of the Kotlin programmer dictionary. To stay up-to-date with new parts, just follow this medium or observe me on Twitter.

If you need some help then remember that I am open for consultations.

If you like it, remember to clap. Note that if you hold the clap button, you can leave more claps.

original source : https://medium.com/@cs.ibrahimyilmaz/viewlifecycleowner-vs-this-a8259800367b

ViewModel은 아래와 같이 onCreate() 후에 생성되어서 activity에 연결된 ViewModel의 경우 onDestory() 후에 사라지게 된다. fragment에 연결된 ViewModel의 경우는 onDestroy()바로 이전에 사라지게 된다. 거칠게 이야기 하면 activity, fragment의 수명과 그에 연결된 ViewModel의 수명이 비슷하다고 할수 있다. 그렇다면 그안에서 생성된 LiveData 도 같은 수명을 가지게 된다. 다만 LiveData에 observe 에 전달되는  viewlifecycleowner나 this는 언제 값을 들여다 볼지를 결정한다.(여기서는 LiveData의 값이 변할때를 말하는 것이 아니다.) activity나 fragment의 주기에 따라 언제 값을 들여다볼지를 결정하는 것이다. this의 경우 onCreate() 될때 마다 들여다 본다. viewlifecycleowner의 경우는 onCreateView() 될때 마다 들여다 본다.

결과적으로 viewlifecycleowner를 사용하면 좀더 자주 확인한다는 이야기이다. 한 fragment에서 다른 fragment로 전환된 사이에 변경되었을수 있는 값을 가져와야 하는 경우 viewlifecycleowner를 사용한다.

참조) https://stackoverflow.com/a/59521748/3151712

image

As we can see from the diagram onCreate and onDestroy called once. These are Fragment mainly life cycle methods. onCreateView and onDestroyView are called according to state of Fragment because they are mainly life cycle methods of the View in Fragment.

So If we use onCreate method for binding our LiveData. Yes we register once and it seems very good and lean:

liveData.observe(this, observer)

But what will happen when we navigate to another fragment and change the value of LiveData there and get back our previous fragment

In going back to the Fragment, we cannot get recent data in LiveData and we should request it.

So it seems that using Views’s LifeCycle methods are much more useful. But in that condition. Common mistake that we do is to use Fragment as a LifeCycle owner.

//in onViewCreated, onCreateView,onActivityCreatedliveData.observe(this, observer) // Mistake!!! It can cause double observation or other problems.

we should use viewLifecycleOwner.

//in onViewCreated, onCreateView,onActivityCreatedliveData.observe(viewLifecycleOwner, observer) 

original source : https://proandroiddev.com/view-model-creation-in-android-android-architecture-components-kotlin-ce9f6b93a46b

https://codelabs.developers.google.com/codelabs/kotlin-android-training-live-data/index.html?index=..%2F..android-kotlin-fundamentals#7

이를 읽으면서 생각하게 된 내용을 정리한다.

https://developer.android.com/topic/libraries/architecture/viewmodel

ViewModel의 수명 주기

ViewModel 객체의 범위는 ViewModel을 가져올 때 ViewModelProvider에 전달되는 Lifecycle로 지정됩니다. ViewModel은 범위가 지정된 Lifecycle이 영구적으로 경과될 때까지, 즉 활동에서는 활동이 끝날 때까지 그리고 프래그먼트에서는 프래그먼트가 분리될 때까지 메모리에 남아 있습니다.

.

.

.

https://medium.com/@BladeCoder/ondetach-has-a-misleading-name-it-is-not-called-when-you-detach-a-fragment-using-d96a2fec90b5#:~:text=detach()%20%2C%20but%20only%20when,%2C%20onViewCreated()%20%2C%20onActivityCreated()%20.

Fragment의 수명주기

onDetach() has a misleading name, it is not called when you detach a fragment using FragmentTransaction.detach(), but only when the fragment is definitely removed from its containing activity as you can see in the horrific fragments lifecycle illustration.

.

.

.

나의생각)

ViewModel이 Fragment에서 생성되서 variable에 assign 되어 있는 경우 fragment가 없어질때까지 ViewModel의 수명이 유지 된다고 이해했다. 또한 fragment의 경우 fragment가 생성된 activity의 수명주기 까지 그 수명이 유진된다. 그렇다면 ViewModel에서 만들어진 LiveData의 생명주기도 fragment와 동일하게 되고 또 activity의 주기가 유질 될때 까지 유지된다. 

또한 그렇다면 하나의 activity에서 여러개의 fragment를 이용해 개발하는 경우 ViewModel간의 LiveData 의 수명주기가 같고 각 ViewModel간에 교차 사용가능하게 된다. 또한 observer를 이용 실시간 업데이트가 될수 있다.

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

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

위와 같이 생각했었지만 사실은 아니었다. 아래 참조
https://developer.android.com/topic/libraries/architecture/viewmodel.html#sharing

Share data between fragments

It’s very common that two or more fragments in an activity need to communicate with each other. Imagine a common case of master-detail fragments, where you have a fragment in which the user selects an item from a list and another fragment that displays the contents of the selected item. This case is never trivial as both fragments need to define some interface description, and the owner activity must bind the two together. In addition, both fragments must handle the scenario where the other fragment is not yet created or visible.

This common pain point can be addressed by using ViewModel objects. These fragments can share a ViewModel using their activity scope to handle this communication, as illustrated by the following sample code:

KOTLIN

JAVA

class SharedViewModel : ViewModel() {
   val selected = MutableLiveData<Item>()

   fun select(item: Item) {
       selected.value = item
   }
}

class MasterFragment : Fragment() {

   private lateinit var itemSelector: Selector

   // Use the 'by activityViewModels()' Kotlin property delegate
   // from the fragment-ktx artifact
   private val model: SharedViewModel by activityViewModels()

   override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
       super.onViewCreated(view, savedInstanceState)
       itemSelector.setOnClickListener { item ->
           // Update the UI
       }
   }
}

class DetailFragment : Fragment() {

   // Use the 'by activityViewModels()' Kotlin property delegate
   // from the fragment-ktx artifact
   private val model: SharedViewModel by activityViewModels()

   override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
       super.onViewCreated(view, savedInstanceState)
       model.selected.observe(viewLifecycleOwner, Observer<Item> { item ->
           // Update the UI
       })
   }
}

Notice that both fragments retrieve the activity that contains them. That way, when the fragments each get the ViewModelProvider, they receive the same SharedViewModel instance, which is scoped to this activity.

This approach offers the following benefits:

  • The activity does not need to do anything, or know anything about this communication.
  • Fragments don’t need to know about each other besides the SharedViewModel contract. If one of the fragments disappears, the other one keeps working as usual.
  • Each fragment has its own lifecycle, and is not affected by the lifecycle of the other one. If one fragment replaces the other one, the UI continues to work without any problems.