【问题标题】:Implementing two way data-binding WebView using MVVM in Kotlin在 Kotlin 中使用 MVVM 实现两种方式的数据绑定 WebView
【发布时间】:2020-05-08 13:18:00
【问题描述】:

我正在尝试在我的所有应用程序中实现 MVVM,我对此很陌生,所以我想通过我的 ViewModel 加载 webview,但我不知道如何做到这一点的最佳方法,如果也有加载我的网络视图时显示的进度条。

代码如下:

    class NewWebViewFragment : Fragment() {

    private lateinit var viewModel: NewWebViewViewModel

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        val binding: FragmentWebViewBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_web_view, container, false)

        val webViewModelo = ViewModelProviders.of(this).get(NewWebViewViewModel::class.java)

        binding.webViewModel = webViewModelo
        binding.lifecycleOwner = this


        return binding.root
    }

}

现在是我的 ViewModel:

class NewWebViewViewModel : ViewModel() {

//Implement in MVVM

private fun showWebView(webView: WebView, progressBar: ProgressBar) {

        webView.webViewClient = WebViewClient()
        webView.webChromeClient = WebChromeClient()

        val webSettings = webView.settings
        webSettings.javaScriptEnabled = true

        webView.loadUrl("https://brand.randombrand.com/en/")

        webView.webViewClient = object : WebViewClient() {
            override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                progressBar.visibility = View.VISIBLE
                super.onPageStarted(view, url, favicon)
            }

            override fun onPageFinished(view: WebView?, url: String?) {
                progressBar.visibility = View.GONE
                super.onPageFinished(view, url)
            }
        }
    }
}

还有我的 XML:

<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">


    <data>
        <variable
            name="webViewModel"
            type="com.example.navigations.viewmodel.webview.NewWebViewViewModel" />
    </data>

    <FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".fragments.WebViewFragment">


    <!-- TODO: Update blank fragment layout -->
        <WebView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/webView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">


    </WebView>

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/progressBar"
        android:layout_gravity="center"/>


    </FrameLayout>
</layout>

我得到的错误是nullpointerexception,因为我传递的 webview 为空。 对实现这一点的最佳方法有什么想法吗?

【问题讨论】:

    标签: android kotlin mvvm webview


    【解决方案1】:

    我认为对您来说最好的选择是创建一个如下所示的绑定适配器:

    @BindingAdapter("loadUrl")
    fun WebView.setUrl(url: String) {
        this.loadUrl(url)
    }
    

    在您的 ViewModel 中,您可以通过 Fragment 参数接收数据(也许它们来自另一个 Fragment),或者只是从 ViewModel 修改它们。

    在 VM 中,数据将是要加载的 url,可能像 val webViewUrl = MutableLiveData&lt;String&gt;().apply{ value = "initial url to be loaded .com" }

    在你的 xml 中:

    <WebView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/webView"
            app:loadUrl="@{viewModel.webViewUrl}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">
    

    是的,你永远不应该在 ViewModel 中做 UI 的事情,比如实例化 WebView 或类似的东西。

    【讨论】:

    • 您好,感谢您的评论!我应该在哪里实现这些 bindingAdapter?它们是否属于视图片段?
    • 你可以创建一个只有绑定适配器的 Utils 类,我通常是这样做的:)
    【解决方案2】:

    您可能不会在viewmodel 中使用webview

    https://developer.android.com/topic/libraries/data-binding/binding-adapters.html

    MVVM 规则

    第一条规则:视图中不应该有任何逻辑,根本没有!甚至不是一个简单的 if 条件。视图的所有逻辑都发生在 ViewModel 中。

    第二条规则:为了响应事件,视图除了通过调用方法通知视图模型之外什么都不做。 View 不会将任何与视图相关的类传递给视图模型。

    规则三:ViewModel 使用实时数据作为与视图通信的主要方式!

    MVVM 的一个好处是 ViewModel 不需要知道任何关于 View 的信息,也不需要引用 View 类!相反,它使用反应式编程范式,因此 View 仍然可以观察数据并收到有关更改的通知。

    规则四:视图可以在需要时调用视图模型。 ViewModel 可以为视图提供辅助方法。

    【讨论】:

    • 这是一个非常好的评论 :) 感谢您的洞察力和良好做法
    【解决方案3】:

    我找到了加载 webView 的解决方案。这是我所做的:

     import android.webkit.WebView
    import androidx.databinding.BindingAdapter
    
    object Utilities {
    
        @BindingAdapter("loadUrl")
        @JvmStatic
        fun WebView.setUrl(url: String) {
            this.loadUrl(url)
        }
    }
    

    1#为Utils创建了一个对象

    <WebView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/webView"
                app:loadUrl="@{webViewModel.webViewUrl}"
                app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
                >
    

    2 # 将 XML 更新为如下所示

    3 # val webViewUrl = MutableLiveData().apply{ value = "https://google.com/en/" }

    将此添加到我的 ViewModel 类中

    感谢 cmets 伙计们

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-01
      • 2020-07-31
      • 1970-01-01
      • 1970-01-01
      • 2016-02-27
      相关资源
      最近更新 更多