---
# System prepended metadata

title: 答案來

---

# 答案來
是這個嗎

## Question:
1. How to achieve Coroutines?
2. How to use Jetpack Navigation?
3. How to implement RecyclerView & Adapter?
4. What's Data Binding? What's the difference between Data Binding and View Binding?
5. What's the difference between each passing data case in the sample code?
6. What's annotation in Kotlin? What annotations are used in the sample code?
7. How to handle RESTful API?
8. What's MVVM architecture? What are M, V and VM in the sample code?

## Answer:
### 1.
Coroutine 分主線程副線程
- cooperation 合作 + routine 作業
- Dispatchers.Main：跑在 Main Thread (=UI Thread ) 
- Dispatchers.IO (Input & Output): 用在耗時操作，會將 launch 的程序跑在 worker thread 上，通常會用來跑耗時作業，意思等同於用比較簡易的方式決定 Coroutines 執行的 context

- 宣告為suspend的function只能在coroutine裡面使用
- 原則上，在 Kotlin 裡頭使用任何標記 suspend 的 method(後面會提)都會在 Scope 裡面，這樣才可以控制 Coroutines 的行進與存活與否。
- 避免主線程跑太久 程式掛掉
- [https://medium.com/jastzeonic/kotlin-coroutine-%E9%82%A3%E4%B8%80%E5%85%A9%E4%BB%B6%E4%BA%8B%E6%83%85-685e02761ae0]
- Job( ) 是單一個Coroutine的生命週期
```kotlin=
private var viewModelJob = Job()

    private val coroutineScope = CoroutineScope(viewModelJob + Dispatchers.Main)
```

- onCleared( ) 清除Job程序
```kotlin=
override fun onCleared() {
        super.onCleared()
        viewModelJob.complete()
    }
```
所以沒寫onCleared會????

以前是GlobalScope 爲了防止UI銷燬時異步任務仍然在進行所導致的內存泄露，我們都會在onCleared()方法中去取消異步任務。
現行的viewModelScope已經寫入onCleared()在內部

* suspend fuction 一定要寫在 coroutine 裡面
* coroutine 裡面不一定要放 suspend fuction

```kotlin=
class MyViewModel: ViewModel() {
    init {
        viewModelScope.launch {
            // Coroutine that will be canceled when the ViewModel is cleared.
        }
    }
}
```

操作database 需要再子線程（scope）操作，避免開關太久，主線程等太久．


---

### 2.
Jetpack 是一套元件、工具和架構指南
由四個部分組成，分別是架構、介面、基礎和行為
包含以前在使用的 support library 也已納入Jetpack裡面 (androidx)
基礎的層面裡 Kotlin Extensions（KTX）通過利用 Kotlin 自身特性，例如：擴充套件函式、屬性等，簡潔化Kotlin程式碼。
LifeCycle、LiveData、ViewModel、Room 等等都是 Jetpack 的架構組件。

navigation:
圖形化介面產生action
即可在fragment中使用findNavController()跳轉頁面
若要傳值就使用Direction+


---

### 3.
使用ListAdapter，需要一個DiffCallBack，用途是當第二次submit資料時，會去比對先前的資料
只替換掉資料有更動的地方，比較省效能。
* ViewHolder
* DiffCallback
* onCreateViewHolder
* onBindViewHolder

如有很多不一樣的View:
* getItemViewType
* 在onCreateViewHolder判定viewType


跟我們不一樣的地方:
1. 把 recyclerView submitList 寫在 Binding Adapter 直接綁定在xml
2. 轉圈圈 -> 使用 SwipeRefreshLayout 物件更新 recyclerView 的狀態 
3. onBindViewHolder拿到holder後可以用holder.itemView拿到整個holder去setClickListenser，寫在ViewHolder的bind裡等同於binding.root拿到整個view。




---

## 4.What's Data Binding? What's the difference between Data Binding and View Binding?

DataBinding 取代 findViewById
ViewBinding 又比 DataBinding 快

![](https://i.imgur.com/6ovHRLW.png)




**Data Binding vs View Binding**
* 只有佈局文件的根標籤是 <layout> 時, Data Binding 才會生成對應的 binding class, View Binding 沒有這樣的要求
* Data Binding 會影響構建的速度. Data Binding 底層其實是通過 annotation processor 實現的, 對構建速度是有負面影響的. 而 View Binding 並不是通過 annotation processor 實現的, 因此解決了 Data Binding 的性能問題.
* Data Binding可以自定義binding的類名，viewbinding不可以。
* Data Binding可以將view和界面上的數據進行雙向綁定， View Binding不行
* View Binding只是節省了你findviewbyid的過程，避免了findviewbyid會由於當前綁定xml中沒有找到view造成空指針的問題，以及查找是強轉時類型錯誤問題


* With view binding, the layouts do not need a layout tag

* You can't use viewbinding to bind layouts with data in xml (No binding expressions, no BindingAdapters nor two-way binding with viewbinding)

* The main advantages of viewbinding are speed and efficiency. It has a shorter build time because it avoids the overhead and performance issues associated with databinding due to annotation processors affecting databinding's build time.

```kotlin=
//DataBinding
binding = DataBindingUtil.setContentView(this, R.layout.activity_main) as ActivityMainBinding
//ViewBinding
binding = ActivityMainBinding.inflate(layoutInflater)
```


---

## 5. What's the difference between each passing data case in the sample code?

* Fragment - Bundle 打包並使用 Arguments 傳遞資料
補充:以往如果要給pass資料給Fragment，通常要為他寫一個Instance function定義arguments，不是很直覺。Navigation Safe Args這個Gradle Plugin可以幫助你解決這個問題，在用Navigation navigate時就可以用自動產生的Class來傳遞資料，而且保證型態安全

* viewModel 透過 factory 向 fragment 取得資料
* fragment xml 透過 data binding 向 viewModel 取得資料
viewMode 到view  於View裡面宣告viewModel去拿取viewModel的值

```xml=
<data>
        <variable name="xmlViewModel" type="app.appworks.school.stylish.xxx.ViewModel"/>
</data>
```
```kotlin=
val viewModel: xxxViewModel ...
binding.xmlViewModel = viewModel
```
* 透過singleton 用 sharedPreference 存取資料，使在所有地方都可以提出singleton資料。

問?
為何StylishRepository & StylishDataSource 要同時存在? DefaultStylishRepository 要放在 constructor & 繼承


---

### 6. 
用來註解
@Parcelize 搭配 :Parcelable 打包帶走
序列化 :  https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/647008/
@JSON 從api轉換資料名稱
@Embedded
去認裡面的欄位
@Volatile 加上 volatile 是為了可見性和禁止重排序，這樣就可以保證把參數傳遞進去的同時，確保線程安全。 避免不同的執行序拿到不同步的資料。變數會改為不使用各執行緒的working memory，永遠從主記憶體做存取與讀寫。
@JvmOverloads:
@InverseMethod:可以把Kotlin的方法轉成java可使用的overload 這樣在java裡就可以call到kotlin裡面參數帶預設值的function/class/建構方法
![](https://i.imgur.com/Unc9TsI.png)

@GlideModule: 
@Suppress 關掉一個一直提醒你的東西
@JvmStatic:就是java的static (為了某天轉到java不會爆掉，因為java沒有companion object)
@FormUrlEncoded 轉網址的
@TypeConverter
TypeConverter基本的用法是轉換資料型態，官方文件的舉例是想要儲存Date時，因為Android SQLite並不支援Date欄位，所以改成儲存Long並透過TypeConverter轉換。
這樣我們存取的時候可以直接用Date型態的欄位，TypeConverter會處理好轉換成Long的過程。
應用在資料關聯時，我們可以利用TypeConverter把物件轉成Json字串存起來，並在取出時轉回物件的型態。


@InverseMethod
原文網址：https://kknews.cc/code/jkg6k4y.html

@volitile 
https://www.tpisoftware.com/tpu/articleDetails/1753
http://amitmason.blogspot.com/2018/08/kotlin-annotation.html


https://ithelp.ithome.com.tw/articles/10230223
https://www.jianshu.com/p/7687365aa946
@Path：所有在网址中的参数（URL的问号前面），如：
>http://102.10.10.132/api/Accounts/{accountId}

@Query：URL问号后面的参数，如：
>http://102.10.10.132/api/Comments?access_token={access_token}

@QueryMap：相当于多个@Query
@Field：用于POST请求，提交单个数据
@Body：相当于多个@Field，以对象的形式提交
Tips

Tips1
使用@Field时记得添加@FormUrlEncoded
Tips2
若需要重新定义接口地址，可以使用@Url，将地址以参数的形式传入即可。
```kotlin=
@GET
    Call<List<Activity>> getActivityList(
            @Url String url,
            @QueryMap Map<String, String> map);
```
```kotlin=
    Call<List<Activity>> call = service.getActivityList(
                "http://115.159.198.162:3001/api/ActivitySubjects", map);

```

---

### 7.
REST，全名 Representational State Transfer( 表現層狀態轉移)

需要注意的是，REST是設計風格而不是標準。
REST通常基於HTTP、URI、XML以及HTML這些現有的廣泛流行的協定和標準。

資源是由URI來指定。
對資源的操作包括取得、建立、修改和刪除，這些操作正好對應HTTP協定提供的GET、POST、PUT和DELETE方法。
通過操作資源的表現形式來操作資源。
資源的表現形式則是XML或者HTML，取決於讀者是機器還是人、是消費Web服務的客戶軟體還是Web瀏覽器。當然也可以是任何其他的格式，例如JSON。

符合這六條件，才叫做真正的 REST
這六條件的順序不影響，前五條是必須遵守才叫做真正的 REST，而第六條可視情況選擇。

1. Uniform interface (介面一致，API 邏輯一致)
例:用一個唯一的URL定位資源，將動作藏在HTTP的method裡面，執行不同的操作。

    一般的API:
    獲得資料GET    /getData
    新增資料POST   /createData
    刪除資料DELETE /deleteData/1

    RESTful的API:
    獲得資料GET     /data
    新增資料POST    /data
    刪除資料DELETE  /data/1

2. Stateless (無狀態的 Server 端)
例:前置操作不成功，後續操作就無法執行，是有狀態的; 如果輸入一個URL就可以直接得到需要的東西，可以單獨運作，就是無狀態。
3. Client-server (Client端和Server端分離)
只要中間的 API 沒有變，Server 和 Client 可以個別開發，相互不受影響 
4. Cachable (可暫存的資源(快取))
暫存Data 不用每次需要都去Server取一次
5. Layered System (分層的系統架構)
6. Code on demand (Optional) (視情況決定要不要遵守，Server端 可以傳送可執行的程式碼給 Client端)。



/////////////////////////////////////

建立retrofit
retrofit.create service = api object
service內放call Api的suspend function
宣告result sealed class <out R> 裝回傳值做error handle

REMOTE:
repository -> dataSource -> api

LOCAL:
repository -> dataSource -> dao -> api

StylishRemoteDataSource : StylishDataSource
DefaultStylishRepository : StylishRepository

DAO : Data access object 聯絡資料庫取得資料
Repository : 負責物件持久化管理(簡單來說取到資料庫資料加入商業邏輯轉成物件)
Repository – 專職管理 Object 生命週期的物件。

//////////////////////////////////////



---

### 8.
Model View ViewModel
==View==是Activity、Fragment或custom view，本身不做邏輯處理，當使用者跟UI有互動時將指令傳給ViewModel處理，透過其獲得所需的資料並顯示。

==ViewModel==接收View的指令並對Model請求資料，將取得的資料保存起來供View使用。

==Model==管理所有的資料來源，例如API、資料庫和SharedPreference，當ViewModel來請求資料時從正確的來源取得資料並回傳。

![](https://i.imgur.com/9MQLshg.png)


![](https://i.imgur.com/yjCWetH.png)


![](https://i.imgur.com/gi5G6YC.png)
