美文网首页我收藏的Android开发文章Android学习Android应用开发那些事
安卓MVVM开发:基于AAC架构玩安卓客户端(Databindi

安卓MVVM开发:基于AAC架构玩安卓客户端(Databindi

作者: showMethe | 来源:发表于2019-11-06 14:25 被阅读0次

    一、开篇

    全篇内容将简单介绍AAC的在我个人开发上的应用, AAC即Android Architecture Components,一个处理UI的生命周期与数据的持久化的架构。

    核心使用:LiveData、ViewModel、Databinding 、Lifecycles

    辅助:Room、WorkManager 、Glide等等常用框架

    全篇大部分内容都围绕Kotlin,这门Google强推的语言上,加上协程这个工具的出现,使得Kotlin对于网络请求,异步操作变得更加方便。所以网络部分我已经不再使用Retrofit2 + Rxjava2了。

    首先、本客户端借助玩安卓的API实现网络功能,非常感谢鸿洋大神玩安卓,给我们提供了分享知识和技术的地方

    玩安卓:https://www.wanandroid.com/

    接着本客户端使用了来自github的第三方库为:

    1、live-event-bus github地址:https://github.com/JeremyLiao/LiveEventBus 一款很优秀的消息总线。

    2、Activity返回侧滑动画SlideBack github地址:https://github.com/ParfoisMeng/SlideBack 项目中下载了源码并进行了部分修改。

    非常感谢所有作者

    二、玩安卓部分预览图

    image image

    三、图片墙部分预览图:

    本部分采用Room实现基本登录注册,点赞,下单(假功能,仅效果显示)的操作

    image

    四、从网络开始讲起

    在使用的API方法上加上suspend

        @FormUrlEncoded
    
        @POST("user/login")
    
        suspend fun login(@Field("username") username:String,@Field("password") password:String) : Response<JsonResult<Auth>>
    
    

    处理请求的逻辑封装了另一个类CallResult,只显示关键部分

       fun hold(result: suspend () -> Response<JsonResult<T>>): CallResult<T> {
           var response: Response<JsonResult<T>>?
           var netJob: Job? = null
           owner?.apply {
               netJob = lifecycleScope.launchWhenStarted {
                   __________ 处理loading状态 ————————————————
                   response  = withContext(Dispatchers.IO) {
                       withTimeoutOrNull(10000){//超时处理
                           result.invoke() //网络请求
                       }
                   }
                   if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
                       withContext(Dispatchers.Main) {
                           __________ 处理超时和返回结果的逻辑————————————————
                       }
                   } else {
                       netJob?.cancel()
                   }
               }
           }
           return this
       }
    
    

    使用时候如下:

      fun login(username:String,password:String,call:MutableLiveData<Result<Auth>>){
          CallResult<Auth>(owner)
              .loading {
                   __________ 处理读取————————————————
              }.success { result, message ->
                  __________ 处理成功————————————————
                  call.value = result
              }.error { result, code, message ->
                   __________ 处理错误————————————————
                  call.value = result
              }.outTime {
                    __________ 处理超时————————————————
                  call.value = it
              }.hold {
                  api.login(username, password)//登录
              }
      }
    

    五、架构细讲

    由于着重在AAC上,所以采用了MVVM的设计模式,利用DataBinding的优势,把数据和交互的简单操作,都能在xml上完成
    以下拉加载和读取更多为例子

    xml如下

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
                    android:id="@+id/refresh"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
                    onRefresh="@{Home::loadRefresh}"
                    refreshing="@{Home.refreshing}"
                    >
    
    
                    <showmethe.github.core.widget.common.AutoRecyclerView
                        android:id="@+id/rv"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:requiresFadingEdge="vertical"
                        android:fadingEdge="vertical"
                        android:fadingEdgeLength="@dimen/px20dp"
                        loadMore="@{Home::loadMore}"
                        />
    
                </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    

    请勿直接复制,省略databinding的set操作和初始化

    class HomeFragment : LazyFragment<FragmentHomeBinding, MainViewModel>() {
         val refreshing = MutableLiveData<Boolean>()   //不能private
          private val pagerNumber = MutableLiveData<Int>()
    
    override fun observerUI() {
    
     pagerNumber.observe(this, Observer {
                it?.apply {
                    router.toTarget("getHomeArticle",this) //这个待会讲,利用注解调用viewModel中的方法
                }
            })
    }
           //___________省略无关代码_________
        fun loadMore(){//不能private
            pagerNumber.value =  pagerNumber.value!! + 1
        }
        fun loadRefresh(){
            pagerNumber.value = 0
        }
      }
    }
    
    

    对应的BindingAdapter拓展方法,利用了Kotlint的特性

    @BindingAdapter("loadMore")
    fun AutoRecyclerView.loadMore(loadingMore: (()->Unit)?){
        setOnLoadMoreListener {
            loadingMore?.invoke()
        }
    }
    
    @BindingAdapter("onRefresh")
    fun SwipeRefreshLayout.onRefresh(onRefreshListener: SwipeRefreshLayout.OnRefreshListener?){
        setOnRefreshListener(onRefreshListener)
    }
    
    @BindingAdapter("refreshing")
    fun SwipeRefreshLayout.refreshing(newValue: Boolean) {
        if(isRefreshing != newValue)
        isRefreshing = newValue
    }
    
    

    5.1 VMRouter的使用

    在上面代码中有一段router.toTarget("getHomeArticle",this)的代码,是用来调用ViewModel中的方法,ViewModel中使用注解VMPath 和一个在该ViewModel中唯一的路径,如下:

     /**
         * 登录
         */
        @VMPath("login")
        fun login(username:String,password:String){
            repository.login(username, password, auth)
        }
    

    通过反射拿到对应方法,并缓存起来。其实这里是因为存在反射,其实是会有性能的问题,但是这个消耗很低。

    5.2 RecyclerViewAdapter的封装

    既然使用了Databinding,那不可不提ObservableArrayList,这个类可以让你对数组的变化进行刷新处理,不在需要每次新数据都自己调用Adapter的刷新,减少漏调时候出现的奇怪问题。实现OnListChangedCallback即可,

     /**
         * The callback that is called by ObservableList when the list has changed.
         */
        abstract class OnListChangedCallback<T extends ObservableList> {
    
            /**
             * Called whenever a change of unknown type has occurred, such as the entire list being
             * set to new values.
             *
             * @param sender The changing list.
             */
            public abstract void onChanged(T sender);
    
            /**
             * Called whenever one or more items in the list have changed.
             * @param sender The changing list.
             * @param positionStart The starting index that has changed.
             * @param itemCount The number of items that have changed.
             */
            public abstract void onItemRangeChanged(T sender, int positionStart, int itemCount);
    
            /**
             * Called whenever items have been inserted into the list.
             * @param sender The changing list.
             * @param positionStart The insertion index
             * @param itemCount The number of items that have been inserted
             */
            public abstract void onItemRangeInserted(T sender, int positionStart, int itemCount);
    
            /**
             * Called whenever items in the list have been moved.
             * @param sender The changing list.
             * @param fromPosition The position from which the items were moved
             * @param toPosition The destination position of the items
             * @param itemCount The number of items moved
             */
            public abstract void onItemRangeMoved(T sender, int fromPosition, int toPosition,
                    int itemCount);
    
            /**
             * Called whenever items in the list have been deleted.
             * @param sender The changing list.
             * @param positionStart The starting index of the deleted items.
             * @param itemCount The number of items removed.
             */
            public abstract void onItemRangeRemoved(T sender, int positionStart, int itemCount);
        }
    

    再结合Databinding的特性,不再需要ButterKnife和findviewbyId找到view中对应的id,而且利用数据绑定,而且数据绑定使得有时候连Id也不再需要书写了,当然有些场景还是需要的,代码更加的简洁和方便了,但是也有人觉得这样不好维护,但我觉得数据绑定减少了不少代码的书写,再加上kotlin更加简洁了。

    项目github地址:https://github.com/ShowMeThe/WanAndroid

    相关文章

      网友评论

        本文标题:安卓MVVM开发:基于AAC架构玩安卓客户端(Databindi

        本文链接:https://www.haomeiwen.com/subject/oweubctx.html