Android MVVM代码规范

2022-03-02  本文已影响0人  克罗克达尔

包的划分

在包目录下应包含以下package

app架构

mvvm架构,对应关系是

UseCase编写规范

UseCase类代码如下

abstract class UseCase<in P, R>(private val coroutineDispatcher: CoroutineDispatcher) {

    /** Executes the use case asynchronously and returns a [Result].
     *
     * @return a [Result].
     *
     * @param parameters the input parameters to run the use case with
     */
    suspend operator fun invoke(parameters: P): Result<R> {
        return try {
            // Moving all use case's executions to the injected dispatcher
            // In production code, this is usually the Default dispatcher (background thread)
            // In tests, this becomes a TestCoroutineDispatcher
            withContext(coroutineDispatcher) {
                execute(parameters).let {
                    Result.Success(it)
                }
            }
        } catch (e: Exception) {
            Result.Error(e)
        }
    }

    /**
     * Override this to set the code to be executed.
     */
    @Throws(RuntimeException::class)
    protected abstract suspend fun execute(parameters: P): R
}

UseCase的作用是

ViewModel编写规范

View无法决定自己跳转页面、展示Dialog、显示加载对话框、显示一个SncakBar,View只能告诉ViewModel我的某个按钮被点击了,如

override fun openEventDetail(id: SessionId) {
        analyticsHelper.logUiEvent(
            "Home to event detail",
            AnalyticsActions.HOME_TO_SESSION_DETAIL
        )
        _navigationActions.tryOffer(FeedNavigationAction.NavigateToSession(id))
    }

ViewModel类中应该包含一个NavigationAction密封类,通过这个类,告诉View应该跳转到哪个页面或者弹出一个对话框,如

sealed class FeedNavigationAction {
    class NavigateToSession(val sessionId: SessionId) : FeedNavigationAction()
    class NavigateAction(val directions: NavDirections) : FeedNavigationAction()
    object OpenSignInDialogAction : FeedNavigationAction()
    class OpenLiveStreamAction(val url: String) : FeedNavigationAction()
    object NavigateToScheduleAction : FeedNavigationAction()
}

ViewModel和View的交互方式

不同于MVP,在MVP中,View和Presenter相互持有,P层可以直接调用V层的方法。但是在MVVM中,View可以持有ViewModel,但ViewModel不能持有View,ViewModel需要把一个可观察的数据源给View去观察,在数据变化的时候View去更新数据。可观察的数据源可分为3大类

RxJava

天生的观察者模式,但存在两个问题

LiveData

LiveData不同于RxJava,RxJava是一个数据流,你可以进行Map,Filter等数据流操作,但LiveData是一个DataHolder,帮你保存一个数据,当页面不可见的时候不会给View发送数据,当页面可见的时候把最新的数据给View。
但LiveData存在一个非常大的问题。比如我要让View去跳转到一个新的Activity要怎么做,如果用LiveData去发送这个消息的话,View收到消息后跳转页面,看起来没什么问题,但是当重新回到页面的时候,由于LiveData的机制,当页面可见的时候会发送最新的数据给View,然后我们又跳转了一次页面

Flow

kotlin才有的数据流处理方式,适合Android的MVVM项目。注意我们要暴露两种不同类型的Flow让View去观察

private val _mapVariant = MutableStateFlow<MapVariant?>(null)
    val mapVariant: StateFlow<MapVariant?> = _mapVariant
private val _navigationActions = Channel<EventInfoNavigationAction>(Channel.CONFLATED)
    val navigationActions = _navigationActions.receiveAsFlow()

NavigationAction的写法

sealed class FeedNavigationAction {
    data class NavigateToSession(val sessionId: SessionId) : FeedNavigationAction()
    object ShowSignInDialog : FeedNavigationAction()
    object NavigateToSchedule : FeedNavigationAction()
}

ViewModel中获取view中的数据方式(Activity中的Intent或Fragment中的Argument)

@HiltViewModel
class AdvertisingViewModel @Inject constructor(
    savedStateHandle: SavedStateHandle
) : ViewModel() {

    val advertising: Advertising =
        savedStateHandle.get<Advertising>(ExtraKey.ADVERTISING) !!

注意事项

View编写规范

上一篇 下一篇

猜你喜欢

热点阅读