分享兩道阿裏P7究極難度算法題,想跳槽漲薪的必看

Android夢想導師 2021-09-19 02:43:38 阅读数:970

分享 p7 算法 跳槽 必看

1、MVVM架構模式概覽

這是使用MVVM架構模式+Kotlin協程+JetPack(ViewModel+LiveData)+Retrofit的架構,實現WanAndroid登錄接口的小DEMO,後續會慢慢完善WanAndroid客戶端

1、ViewModel?

為了從界面控制器Activity/Fragment邏輯中分離出視圖View數據所有權,架構組件為界面控制器提供了 ViewModel 輔助程序類,該類負責為界面准備數據。在配置更改期間會自動保留 ViewModel 對象,以便它們存儲的數據立即可供下一個 Activity 或 Fragment 實例使用。

2、LiveData?

LiveData 是一種可觀察的數據存儲器類,具有生命周期感知能力,意指它遵循其他應用組件如 Activity、Fragment 或 Service 生命周期,可確保 LiveData 僅更新處於活躍生命周期狀態的應用組件觀察者。LiveData 對象通常存儲在 ViewModel 對象中,並可通過 getter 方法進行訪問。

3、Kotlin協程?

協程依附在線程上,可以實現順序編寫异步代碼,自動進行線程切換。並且ViewModelScope為應用中的每個 ViewModel 定義了 ViewModelScope。如果 ViewModel 已清除,則在此範圍內啟動的協程都會自動取消。

4、Retrofit?

將服務接口中的網絡請求函數聲明為suspend掛起接口函數,以支持Kotlin線程,並將suspend函數結果作為 LiveData 對象傳送。

分享兩道阿裏P7究極難度算法題,想跳槽漲薪的必看_程序員

2、ViewModel

//獲取ViewModel
viewModel?=?ViewModelProvider(this).get(MainViewModel::class.java)`

  • 1.
  • 2.

ViewModel 對象存在的時間範圍是獲取 ViewModel 時傳遞給 ViewModelProvider 的 Lifecycle。ViewModel 將一直留在內存中,直到限定其存在時間範圍的 Lifecycle 永久消失:對於 Activity,是在 Activity 完成時;而對於 Fragment,是在 Fragment 分離時。

分享兩道阿裏P7究極難度算法題,想跳槽漲薪的必看_Android_02

3、LiveData

//對User數據進行觀察
viewModel.user.observe(this,?Observer?{
????//展示登錄結果
????if?(it.errorCode?==?0)?{
????????Toast.makeText(this,?it.data?.nickname,?Toast.LENGTH_SHORT).show()
????}?else?{
????????Toast.makeText(this,?it.errorMsg,?Toast.LENGTH_SHORT).show()
????}
})

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

使用 LiveData 具有以下優勢:確保界面符合數據狀態

LiveData 遵循觀察者模式。當生命周期狀態發生變化時,LiveData 會通知 Observer 對象。您可以整合代碼以在這些 Observer 對象中更新界面。觀察者可以在每次發生更改時更新界面,而不是在每次應用數據發生更改時更新界面。

  • 1.

不會發生內存泄漏

觀察者會綁定到 Lifecycle 對象,並在其關聯的生命周期遭到銷毀後進行自我清理。

  • 1.

不會因 Activity 停止而導致崩潰

如果觀察者的生命周期處於非活躍狀態(如返回棧中的 Activity),則它不會接收任何 LiveData 事件。
不再需要手動處理生命周期
界面組件只是觀察相關數據,不會停止或恢複觀察。LiveData 將自動管理所有這些操作,因為它在觀察時可以感知相關的生命周期狀態變化。

  • 1.
  • 2.
  • 3.

數據始終保持最新狀態

如果生命周期變為非活躍狀態,它會在再次變為活躍狀態時接收最新的數據。例如,曾經在後臺的 Activity 會在返回前臺後立即接收最新的數據。

  • 1.

適當的配置更改

如果由於配置更改(如設備旋轉)而重新創建了 Activity 或 Fragment,它會立即接收最新的可用數據。

  • 1.

共享資源

可以使用單一實例模式擴展 LiveData 對象以封裝系統服務,以便在應用中共享它們。

  • 1.

分享兩道阿裏P7究極難度算法題,想跳槽漲薪的必看_程序員_03

4、Kotlin協程

4.1、异步的本質

什麼是异步?

异步就是同時進行一個以上彼此目的不同的任務。

  • 1.

但是對於有前後依賴關系的任務,异步該如何處理呢?

利用异步中的回調機制處理。

  • 1.

為什麼需要异步回調機制?

因為不同的任務之間存在前後的依賴關系。

  • 1.

异步回調機制有什麼缺點?

代碼結構過分耦合,遇到多重函數回調的嵌套耦合,也就是回調地獄,代碼會難以維護。

  • 1.

解决回調地獄的方案有什麼?

鏈式調用結構。
常見方式就是使用RxJava,它是反應函數式編程在Java中的實現。
但是RxJava中流的創建、轉化與消費都需要使用到各種類和豐富的操作符,加大了RxJava的學習成本。
减少在無封裝情况下使用RxJava,因為你無法保證團隊裏面的每一個成員都能看懂它,並且在修改時都能做出正確選擇。

  • 1.
  • 2.
  • 3.
  • 4.

在串行的執行中,雖然代碼確實是順序執行的,但其實是在不同的線程上順序執行的。那為什麼在串行的執行中代碼執行順序一致,卻還要使用回調呢?

因為串行的執行中,執行是阻塞式的,主線程的阻塞會導致很嚴重的問題,所以所有的耗時操作不能在主線程中執行,所以就需要多線程並行來執行。

  • 1.

在並行的執行中,异步回調其實就是代碼的多線程順序執行。那能不能既按照順序的方式編寫代碼,又可以讓代碼在不同的線程順序執行,自動完成線程的切換工作呢?

那就是Kotlin協程。
Kotlin 的協程是一種無棧協程的實現,它的控制流轉依靠對協程體本身編譯生成的狀態機的狀態流轉來實現,變量保存也是通過閉包語法來實現的。

  • 1.
  • 2.

結論:

异步回調就是代碼的多線程順序執行,而Kotlin協程可以實現順序編寫异步代碼,自動進行線程切換。

  • 1.

那麼協程自動進行線程切換的原理是什麼?

Yield:讓出CPU,放弃調度控制權,回到上一次Resume的地方
Resume:獲取調度控制權,繼續執行程序,到上一次Yield的地方

  • 1.
  • 2.

例子:

1.?GlobalScope.launch發起了一個協程,並在IO線程上執行,
2\. 在協程裏,去調用接口獲取結果。
3.?拿到結果,使用withContext(Dispatchers.Main)切換到主線程並更新界面

  • 1.
  • 2.
  • 3.

4.2、協程的類型

是協程範圍,指的是協程內的代碼運行的時間周期範圍,如果超出了指定的協程範圍,協程會被取消執行。

  • 1.

GlobalScope

指的是與應用進程相同的協程範圍,也就是在進程沒有結束之前協程內的代碼都可以運行。

  • 1.

JetPack中提供的生命周期感知型協程範圍:

ViewModelScope,為應用中的每個 ViewModel 定義了 ViewModelScope。如果 ViewModel 已清除,則在此範圍內啟動的協程都會自動取消。
LifecycleScope,為每個 Lifecycle 對象定義了 LifecycleScope。在此範圍內啟動的協程會在 Lifecycle 被銷毀時取消。
使用 LiveData 時,可能需要异步計算值。可以使用 liveData 構建器函數調用?suspend?函數,並將結果作為 LiveData 對象傳送。

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

相關鏈接: https://developer.android.google.cn/topic/libraries/architecture/coroutines

4.3、協程的啟動

launch方法:

/**
?*?重要知識:ViewModel+協程
?*/
fun?ViewModel.launch(
????block:?suspend?CoroutineScope.()?->?Unit,
????onError:?(e:?Throwable)?->?Unit?=?{},
????onComplete:?()?->?Unit?=?{}
)?{
????viewModelScope.launch(CoroutineExceptionHandler?{?_,?e?->?onError(e)?})?{
????????try?{
????????????block.invoke(this)
????????}?finally?{
????????????onComplete()
????????}
????}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

源碼:

public?fun?CoroutineScope.launch(
????context:?CoroutineContext?=?EmptyCoroutineContext,
????start:?CoroutineStart?=?CoroutineStart.DEFAULT,
????block:?suspend?CoroutineScope.()?->?Unit
):?Job?{
????val?newContext?=?newCoroutineContext(context)
????val?coroutine?=?if?(start.isLazy)
????????LazyStandaloneCoroutine(newContext,?block)?else
????????StandaloneCoroutine(newContext,?active?=?true)
????coroutine.start(start,?coroutine,?block)
????return?coroutine
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

4.3.1、launch方法解釋

context

協程上下文,可以指定協程運行的線程。默認與指定的CoroutineScope中的coroutineContext保持一致,比如GlobalScope默認運行在一個後臺工作線程內。也可以通過顯示指定參數來更改協程運行的線程,Dispatchers提供了幾個值可以指定:Dispatchers.Default、Dispatchers.Main、Dispatchers.IO、Dispatchers.Unconfined。

  • 1.

start

協程的啟動模式。默認的CoroutineStart.DEFAULT是指協程立即執行,除此之外還有CoroutineStart.LAZY、CoroutineStart.ATOMIC、CoroutineStart.UNDISPATCHED。

  • 1.

block

協程主體。也就是要在協程內部運行的代碼,可以通過lamda錶達式的方式方便的編寫協程內運行的代碼。

  • 1.

CoroutineExceptionHandler

指定CoroutineExceptionHandler來處理協程內部的异常。

  • 1.

Job

返回值,對當前創建的協程的引用。可以通過Job的start、cancel、join等方法來控制協程的啟動和取消。

  • 1.

4.4、suspend掛起函數

suspend關鍵字只起到了標志這個函數是一個耗時操作,必須放在協程中執行的作用,而withContext方法則進行了線程的切換工作。

協程中的代碼自動地切換到其他線程之後又自動地切換回了主線程!順序編寫保證了邏輯上的直觀性,協程的自動線程切換又保證了代碼的非阻塞性。掛起函數必須在協程或者其他掛起函數中被調用,也就是掛起函數必須直接或者間接地在協程中執行。

那為什麼協程中的代碼沒有在主線程中執行呢?而且執行完畢為什麼還會自動地切回主線程呢?

協程的掛起可以理解為協程中的代碼離開協程所在線程的過程,協程的恢複可以理解為協程中的代碼重新進入協程所在線程的過程。協程就是通過的這個掛起恢複機制進行線程的切換。

4.5、async await方法

用async方法包裹了suspend方法來執行並發請求,並發結果都返回之後,切換到主線程,接著再用await方法來獲取並發請求結果。

5、Retrofit

HTTP接口suspend掛起函數:

interface?ApiService?{
[email protected]
[email protected]("user/login")
????suspend?fun?loginForm(@Field("username")??username:?String,@Field("password")??password:?String):?BaseResponse<User>
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

kotlin泛型:

data?class?BaseResponse<T>(
????val?errorCode:?Int=0,
????val?errorMsg:String??=?null,
????var?data:?T??=?null
)

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

這是使用MVVM架構模式+Kotlin協程+JetPack(ViewModel+LiveData)+Retrofit的架構,實現WanAndroid登錄接口的小DEMO,後續會慢慢完善WanAndroid客戶端

最後我想說

為什麼很多程序員做不了架構師?
1、良好健康的職業規劃很重要,但大多數人都忽略了
2、學習的習慣很重要,持之以恒才是正解。
3、編程思維沒能提昇一個臺階,局限在了編碼,業務,沒考慮過選型、擴展
4、身邊沒有好的架構師引導、培養。所處的圈子對程序員的成長影響巨大。

金九銀十面試季,跳槽季,整理面試題已經成了我多年的習慣!在這裏我和身邊一些朋友特意整理了一份快速進階為Android高級工程師的系統且全面的學習資料。涵蓋了Android初級——Android高級架構師進階必備的一些學習技能。

附上:我們之前因為秋招收集的二十套一二線互聯網公司Android面試真題(含BAT、小米、華為、美團、滴滴)和我自己整理Android複習筆記(包含Android基礎知識點、Android擴展知識點、Android源碼解析、設計模式匯總、Gradle知識點、常見算法題匯總。)

分享兩道阿裏P7究極難度算法題,想跳槽漲薪的必看_程序員_04

裏面包含不同方向的自學編程路線、面試題集合/面經、及系列技術文章等,資源持續更新中…

 CodeChina開源項目:《Android學習筆記總結+移動架構視頻+大廠面試真題+項目實戰源碼》
版权声明:本文为[Android夢想導師]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210919024337409n.html