首页 > 其他分享 >kotlin中ViewModel + ViewBinding使用实例

kotlin中ViewModel + ViewBinding使用实例

时间:2022-11-08 10:56:42浏览次数:43  
标签:String title url kotlin ViewModel binding var ViewBinding fun

android使用androidx后可以使用viewbinding了,因为是内生库,也蛮好用的。

butterknife感觉已经在退环境了。

文章列出ViewModel + ViewBinding,是MVVM模式的简单使用,没有涉及到太复杂的环境,如果要在复杂环境下使用,还有待研究。

在Kotlin中使用ViewBinding需要的在build.gradle(APP)中启用:

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

这里使用的是一个使用Fragment载入网页的例子,使用ViewModel来给Fragment提供数据。涉及到的数据简单的认为有2个,一个是网页的URL,另外一个是网页的Title。我们用一个java bean来存放该数据,如下:

data class DataWeb(var title: String, var url: String)

接下来是用ViewMod提供数据的实现类:

class WebViewModel : ViewModel() {

    private val _general = MutableLiveData<Constants>().apply {
        value = DataWeb("baidu", "https://www.baidu.com")
    }
    val general get() = _general

    /** 改变*/
    fun update(title: String?, url: String, showActionBar: Boolean = false) {
        val constants = general.value
        constants?.title = title ?: ""
        constants?.url = url
        general.value = constants
    }
}

接下来是使用Fragment载入数据:

// 布局layout_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <RelativeLayout
            android:id="@+id/actionBar"
            android:layout_width="match_parent"
            android:layout_height="56dp"
            android:background="@color/actionBarBackground"
            android:elevation="4dp">

            <TextView
                android:id="@+id/tvActionBarTitle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginStart="20dp"/>
        </RelativeLayout>

        <com.scwang.smartrefresh.layout.SmartRefreshLayout
            android:id="@+id/refreshLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <android.webkit.WebView
                android:id="@+id/webView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
        </com.scwang.smartrefresh.layout.SmartRefreshLayout>
    </LinearLayout>
</layout>

// Fragment实现
class WebViewFragment2 : Fragment(), TheWebViewClientCallback, TheWebViewChromeClientCallback {

    companion object {
        const val TAG = "WebViewFragment"
    }

    private var _binding: LayoutFragmentBinding? = null

    // This property is only valid between onCreateView and
    // onDestroyView.
    val binding get() = _binding!!

    private lateinit var webViewModel: WebViewModel

    private var loadService: LoadService<Any>? = null

    /** 是否记载出错*/
    private var isLoadError = false

    /** 支持下拉刷新*/
    var canNativeRefresh = true

    /** 是否需要重新载入URL*/
    var isNeedLoadUrl = true

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        webViewModel = ViewModelProvider(this).get(WebViewModel::class.java)
        _binding = LayoutFragmentBinding.inflate(inflater, container, false)
        val webView = binding.webView.apply {
            // 监控WebView载入的过程
            webViewClient = TheWebViewClient().apply {
                callback = this@WebViewFragment2
            }
            // 仅接受Title
            webChromeClient = TheWebViewChromeClient().apply {
                callback = this@WebViewFragment2
            }
            settings.javaScriptEnabled = true
        }
        binding.refreshLayout.apply {
            // 无需加载更多
            setEnableLoadMore(false)
            // 支持下拉刷新
            setEnableRefresh(canNativeRefresh)
            setOnRefreshListener {
                webView.reload()
            }
        }
        webViewModel.general.observe(viewLifecycleOwner) {
            binding.tvActionBarTitle.text = it.title
            if (isNeedLoadUrl) {
                isNeedLoadUrl = false
                webView.loadUrl(it.url)
            }
            Log.d(TAG, "<---->observe called<---->")
        }
        loadService = LoadSir.getDefault().register(binding.refreshLayout) {
            // 用户点击按钮的reload事件
            loadService?.showCallback(LoadingCallback::class.java)
            Log.d(TAG, "<>register loadService<>")
            webView.reload()
        }
        return binding.root
    }

    override fun pageStarted(url: String?) {
        Log.d(TAG, "<>pageStarted<>")
        isLoadError = false
        loadService?.showCallback(LottieLoadingCallback::class.java)
    }

    override fun pageFinished(url: String?) {
        Log.d(TAG, "<>pageFinished<>")
        if (!isLoadError) {
            loadService?.showSuccess()
        }
        binding.refreshLayout.setEnableRefresh(canNativeRefresh)
        binding.refreshLayout.finishRefresh()
    }

    override fun one rror() {
        Log.e(TAG, "<>onError<>")
        isLoadError = true
        loadService?.showCallback(ErrorCallback::class.java)
    }

    override fun onReceivedTitle(title: String?) {
        Log.d(TAG, "onReceivedTitle : $title")
        webViewModel.update(title, "")
    }
}

ViewModel对数据的监控使用的是观察者模式,代码中webViewModel.general.observe()就是启用观察者,而且加入了lifecycle中来保证在生命周期中能够接受到数据的变更,初始数据的载入,也在general.observe()方法中实现。而实时数据的变更使用的是model中的我们自己写的update()方法。

以上就是本文要介绍的内容。

最后提出其他边角的代码:

interface TheWebViewClientCallback {
    fun pageStarted(url: String?)
    fun pageFinished(url: String?)
    fun one rror()
}

class TheWebViewClient : WebViewClient() {

    var callback: TheWebViewClientCallback? = null

    override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
        super.onPageStarted(view, url, favicon)
        if (null != callback) {
            callback!!.pageStarted(url)
        } else {
            Log.e("TAG", "onPageStarted callback is null")
        }
    }

    override fun onPageFinished(view: WebView?, url: String?) {
        super.onPageFinished(view, url)
        callback?.pageFinished(url)
    }

    override fun onReceivedError(
        view: WebView?,
        request: WebResourceRequest?,
        error: WebResourceError?
    ) {
        callback?.onError()
        super.onReceivedError(view, request, error)
    }
}

interface TheWebViewChromeClientCallback {
    fun onReceivedTitle(title: String?)
}

class TheWebViewChromeClient : WebChromeClient() {

    var callback: TheWebViewChromeClientCallback? = null

    override fun onReceivedTitle(view: WebView?, title: String?) {
        super.onReceivedTitle(view, title)
        callback?.onReceivedTitle(title)
    }
}

//三方框架

// loadSir
implementation 'com.kingja.loadsir:loadsir:1.3.8'
// lottie
implementation 'com.airbnb.android:lottie:5.2.0'
// 下拉刷新
implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-andx-11'

 

标签:String,title,url,kotlin,ViewModel,binding,var,ViewBinding,fun
From: https://www.cnblogs.com/swalka/p/16868876.html

相关文章

  • kotlin用于注解处理kapt配置
    使用场景:为了使用 @AutoService(xx::class)AndroidStudio版本:AndroidStudioBumbleBee2021.1.1Patch3build.gradle(Project)载入插件:plugins{...id"o......
  • Kotlin-null安全
    null安全是java空指针异常调优方案,kotlin将变量分为Nullable(可为空类型)和Non-Null(不可为空类型)。两种变量声明方式:Non-Nullvara:String="hello"不支持的写法var......
  • Kotlin常用函数 let,with,apply,also,run
    前言kotlin开发中常用的几个函数,let,with,run,apply,also,他们都是范围函数,具体使用场景迷糊,开发中不知道如何使用。这里罗列出来泛型表达式,反编译之后字节码进行对比,方便记忆......
  • kotlin 注解声明与使用
    前言函数的调用需要知道函数所在的类,函数的入参个数和参数类型,注解和反射可以跳过这个限制,注解和反射可以编写事先未知的任意类代码。注解可以为类库赋予特定的语义,反射可以......
  • Android kotlin泛型知识点梳理
    前言学习知识需要提前设立目标,带着问题学习才能有的放矢。无论是java的泛型还是kotlin语言的泛型均是写框架,写通用工具类神器。如果不熟悉泛型语法,开发过程中将会遇到很多奇......
  • Android kotlin 类委托 by,by lazy关键
    前言接触kotlin语言也有几年时间了。日常开发工作中也推荐使用kotlin,但是对于一些kotlin语言语法的细节没有进行系统学习。碎片的知识点让工作中屡屡碰壁,前些天开始学习comp......
  • kotlin协程小记
    例子一:GlobalScope.launch(Dispatchers.Main){//开启子协程withContext(Dispatchers.IO){for(iin0until1000){}Log.d("Ma......
  • Kotlin DSL 学习
    之前在《EffectiveKotlin》一书中,有一条专门讲解DSL的:​​考虑为复杂的对象创建定义DSL​​,让我对DSL有了一定的了解。为了能够更熟悉掌握Kotlin上的DSL,用这篇Blog......
  • Kotlin的语法糖太甜啦——开发MC插件遇到的坑
    最近在学习使用Kotlin开发PaperMC插件,遇到了一个大坑,不吐不快。PersistentDataType<T,Z>接口我们可以给物品或方块添加自定义的BNT标签,而这个接口定义的自定义标签的数......
  • Mockito使用方法(Kotlin)
    一、为什么要使用Mockito1.实际案例1.1遇到的问题对于经常维护的项目,经常遇到一个实际问题:需求不停改变,导致架构经常需要修改某些概念的定义。对于某些十分基础又十分......