Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ライブラリでしかお目にかかれない珍しい実装

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.
Avatar for mikan mikan
November 10, 2024

 ライブラリでしかお目にかかれない珍しい実装

Avatar for mikan

mikan

November 10, 2024
Tweet

More Decks by mikan

Other Decks in Technology

Transcript

  1. 自己紹介 object Mikan { val name = "一瀬喜弘" val company

    = "karabiner.tech" val work = Engineer.Android val hobby = listOf( "漫画", "アニメ", "ゲーム", "折り紙", "OSS開発・コントリビュート", ) }
  2. @Immutable class ButtonColors constructor( val containerColor: Color, val contentColor: Color,

    val disabledContainerColor: Color, val disabledContentColor: Color, ) { fun copy( containerColor: Color = this.containerColor, contentColor: Color = this.contentColor, disabledContainerColor: Color = this.disabledContainerColor, disabledContentColor: Color = this.disabledContentColor ) = ButtonColors( containerColor.takeOrElse { this.containerColor }, contentColor.takeOrElse { this.contentColor }, disabledContainerColor.takeOrElse { this.disabledContainerColor }, disabledContentColor.takeOrElse { this.disabledContentColor }, ) // ... override fun hashCode(): Int { var result = containerColor.hashCode() result = 31 * result + contentColor.hashCode() result = 31 * result + disabledContainerColor.hashCode() result = 31 * result + disabledContentColor.hashCode() return result
  3. Avoid using data class Why data class が生成する、 copy や

    componentN メソッドにABI互換性がないから プロパティを追加したら、コンストラクタとcopyメソッドの互換性が壊れる プロパティの順番を変えたら、conponentNの互換性が壊れる https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api How 自前で hashCode や copy を実装している
  4. Readonly implementation What MutableStateFlow を StateFlow に up cast するときに利用されている

    public fun <T> MutableStateFlow<T>.asStateFlow(): StateFlow<T> = ReadonlyStateFlow(this, null)
  5. Readonly implementation What public fun <T> MutableStateFlow<T>.asStateFlow(): StateFlow<T> = ReadonlyStateFlow(this,

    null) @OptIn(ExperimentalForInheritanceCoroutinesApi::class) private class ReadonlyStateFlow<T>( flow: StateFlow<T>, @Suppress("unused") private val job: Job? // keeps a strong reference to the job (if present) ) : StateFlow<T> by flow, CancellableFlow<T>, FusibleFlow<T> { override fun fuse(context: CoroutineContext, capacity: Int, onBufferOverflow: BufferOverflow) = fuseStateFlow(context, capacity, onBufferOverflow) }
  6. Readonly implementation Why MutableStateFlowにdown castできてしまう class MainViewModel: ViewModel() { private

    val _uiState = MutableStateFlow(MainUiState()) val uiState: StateFlow<MainUiState> = _uiState } (viewModel.uiState as MutableStateFlow<MainUiModel>).update { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // down cast to MutableStateFlow }
  7. Readonly implementation Why ClassCastException が発生して、クラッシュする より安全な実装になる class MainViewModel: ViewModel() {

    private val _uiState = MutableStateFlow(MainUiState()) val uiState = _uiState.asStateFlow() } (viewModel.uiState as MutableStateFlow<MainUiModel>).update { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // throw ClassCastException }