【问题标题】:How to bind viewmodel to SupportMapFragment如何将视图模型绑定到 SupportMapFragment
【发布时间】:2021-01-30 10:16:51
【问题描述】:

在我的 android 应用程序中,我使用 MapsFragment 类创建了地图片段

class MapsFragment : Fragment() {

    val callback = OnMapReadyCallback { googleMap ->
        val sydney = LatLng(-34.0, 151.0)
        googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
        googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
    }

    private val viewModel: MapViewModel by lazy {
        ViewModelProvider(this).get(MapViewModel::class.java)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val binding = FragmentMapsBinding.inflate(inflater)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
        mapFragment?.getMapAsync(callback)
    }
}

和fragment_maps.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<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="viewModel"
            type="com.mobile.viewmodels.MapViewModel" />
    </data>

    <fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".ui.MapsFragment" />

</layout>

我用

buildFeatures {
    dataBinding true
}

用于创建绑定的选项。然后当我尝试绑定我的 MapViewModel 时

val binding = FragmentMapsBinding.inflate(inflater)

我收到一个错误

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.mobile, PID: 331
    java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
        at androidx.databinding.ViewDataBinding.mapBindings(ViewDataBinding.java:1201)
        at androidx.databinding.ViewDataBinding.mapBindings(ViewDataBinding.java:719)
        at com.mobile.databinding.FragmentMapsBindingImpl.<init>(FragmentMapsBindingImpl.java:25)
        at com.mobile.DataBinderMapperImpl.getDataBinder(DataBinderMapperImpl.java:58)
        at androidx.databinding.MergedDataBinderMapper.getDataBinder(MergedDataBinderMapper.java:74)
        at androidx.databinding.DataBindingUtil.bind(DataBindingUtil.java:199)
        at androidx.databinding.DataBindingUtil.inflate(DataBindingUtil.java:130)
        at androidx.databinding.ViewDataBinding.inflateInternal(ViewDataBinding.java:1368)
        at com.mobile.databinding.FragmentMapsBinding.inflate(FragmentMapsBinding.java:68)
        at com.mobile.databinding.FragmentMapsBinding.inflate(FragmentMapsBinding.java:54)
        at com.mobile.ui.MapsFragment.onCreateView(MapsFragment.kt:45)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
        at androidx.fragment.app.FragmentManagerImpl.addAddedFragments(FragmentManagerImpl.java:2100)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1874)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1830)
        at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
        at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I/Process: Sending signal. PID: 331 SIG: 9

如何正确绑定viewModel类?有可能吗?

【问题讨论】:

    标签: android google-maps kotlin


    【解决方案1】:

    抱歉,我可能会迟到回答这个问题,但正如他们所说,“迟到总比没有好。”

    所以在过去的两天里,我一直在尝试做同样的事情,即同时使用 DataBinding 和 Maps Fragment。

    我尝试使用这两种方法,即DataBindingUtil 和您所做的FragmentMapsBinding

    因此,在尝试实现数据绑定时,我可能遇到很多错误,对于初学者来说,没有生成 DataBinding 类,这通常不是问题,除非在这种情况下。因此,解决方法是强制编译器通过在 XML 文件中引入变量来生成 DataBinding 类,在您的情况下为 viewModel

    现在数据绑定类终于生成了,但是我们得到了这个有趣的错误,说

    索引超出范围

    现在查看生成的最后一个错误行

    java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
            at androidx.databinding.ViewDataBinding.mapBindings(ViewDataBinding.java:1201)
    

    并进一步检查文件ViewDataBinding.java 中的代码,我们看到了这一点。

    if (isRoot && tag != null && tag.startsWith("layout")) {
                final int underscoreIndex = tag.lastIndexOf('_');
                if (underscoreIndex > 0 && isNumeric(tag, underscoreIndex + 1)) {
                    final int index = parseTagInt(tag, underscoreIndex + 1);
    //ERROR IS GENERATED HERE
                    if (bindings[index] == null) {
                        bindings[index] = view;
                    }
                    indexInIncludes = includes == null ? -1 : index;
                    isBound = true;
                } else {
                    indexInIncludes = -1;
                }
            }
    

    不是我认为的问题是我们告诉编译器强制生成的绑定文件实际上没有任何视图和绑定索引。

    数据绑定类-

    • 没有。观看次数 = 0
    • 索引 = 0

    现在尝试访问它会出错。

    但是等一下,有人可能会说存在视图,即片段。这个呢?

    <fragment
            android:id="@+id/map"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".ui.MapsFragment" />
    

    在浏览了一些 android 文档之后,我认为 Fragment 不是 View

    所以,我建议的解决方法是使用这两种方法中的任何一种。

    1. fragment 替换为androidx.fragment.app.FragmentContainerView -> 这将消除错误,正如文档所述

    FragmentContainerView 是专为 Fragments 设计的自定义 Layout。它扩展了 FrameLayout,因此它可以可靠地处理 Fragment Transactions,并且它还具有与 Fragment 行为协调的附加功能。

    1. 在您的 XML 文件中有另一个视图,例如。
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <fragment
            android:id="@+id/map"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".ui.MapsFragment" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    或者你可以同时使用,这取决于你。

    希望这能回答您的问题。祝你有美好的一天。

    更新: 根据 Android 开发者文档:

    kotlin.Any
    ↳ androidx.fragment.app.Fragment

    kotlin.Any
    ↳ android.view.View
    ↳ android.view.ViewGroup
    ↳ android.widget.FrameLayout
    ↳ androidx.fragment.app.FragmentContainerView

    很明显fragment 没有 View 作为超类。因此,抛出此错误。 以上 2 种方法是避免此错误的最佳方法,因为在 DataBinding 中它至少需要 1 个 View。

    fragment 标记更改为androidx.fragment.app.FragmentContainerView 或用另一个 View 或 ViewGroup 环绕 fragment,如 LinearLayout、FrameLayout 等。

    【讨论】:

    • 谢谢,我想如果没有解决方案你可以随时回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-05
    • 1970-01-01
    相关资源
    最近更新 更多