当前位置: 首页 > 知识库问答 >
问题:

Android kotlin数据绑定带碎片错误:找不到符号导入com。示例。***。数据绑定。碎片用户绑定impl;

咸育
2023-03-14

我对kotlin相对较新,并试图在一些片段中构建一个带有数据绑定的项目。我有一个名为UserFraank的片段,其中包含一个Recyclview,如下所示:

class UserFragment : Fragment() {
  private lateinit var binding: FragmentUserBinding
  private lateinit var viewModel: UserListViewModel
  override fun onCreateView(
      inflater: LayoutInflater, container: ViewGroup?,
      savedInstanceState: Bundle?
  ): View? {
      // Inflate the layout for this fragment
      binding=DataBindingUtil.inflate(inflater,R.layout.fragment_user, container, false)
      binding.userRecycler.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)

      viewModel = ViewModelProviders.of(this).get(UserListViewModel::class.java)
      viewModel.errorMessage.observe(this, Observer {
              errorMessage -> if(errorMessage != null) showError(errorMessage) else hideError()
      })
      binding.mViewModel=viewModel
      return binding.root
      }

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
      super.onViewCreated(view, savedInstanceState)
      //start add activity
      val i= Intent(activity,AddUserActivity::class.java)
      userFab.setOnClickListener(View.OnClickListener {
          startActivity(i)
      })
  }
  private fun showError(@StringRes errorMessage:Int){
      errorSnackbar = Snackbar.make(binding.root, errorMessage, Snackbar.LENGTH_INDEFINITE)
      errorSnackbar?.setAction(R.string.retry, viewModel.errorClickListener)
      errorSnackbar?.show()
  }

  private fun hideError(){
      errorSnackbar?.dismiss()
  }
  }

以及用户的xml布局文件片段。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="mViewModel"
                type="com.example.***.ui.User.UserListViewModel" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        <EditText
                android:id="@+id/userDateEditText"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:hint="@string/pick_date"
                android:background="@drawable/roundededittext"
                android:layout_marginEnd="8dp"
                app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginStart="8dp"
                app:layout_constraintStart_toStartOf="parent"
                android:layout_marginTop="8dp"
                app:layout_constraintTop_toTopOf="parent"/>

        <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/userRecycler"
                android:layout_width="293dp"
                android:layout_height="475dp" android:layout_marginTop="8dp"
                app:layout_constraintTop_toBottomOf="@+id/userDateEditText"
                app:adapter="@{viewModel.getUserListAdapter()}"
                app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginEnd="8dp" app:layout_constraintStart_toStartOf="parent"
                android:layout_marginStart="8dp" android:layout_marginBottom="8dp"
                app:layout_constraintBottom_toBottomOf="parent"/>

        <com.google.android.material.floatingactionbutton.FloatingActionButton
                android:id="@+id/userFab"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" android:layout_marginBottom="48dp"
                app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginEnd="8dp"/>
        <ProgressBar
                style="?android:attr/progressBarStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:mutableVisibility="@{viewModel.getLoadingVisibility()}"
                android:id="@+id/userProgressBar" app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginEnd="140dp" app:layout_constraintStart_toStartOf="parent"
                android:layout_marginStart="8dp" android:layout_marginTop="8dp"
                app:layout_constraintTop_toTopOf="parent" android:layout_marginBottom="8dp"
                app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_bias="0.804"
                app:layout_constraintVertical_bias="0.499"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

还有一个类似的适配器类和item_user.xml:

class UserListAdapter : RecyclerView.Adapter<UserListAdapter.ViewHolder>() {
    private lateinit var userModelList:List<UserModel>

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserListAdapter.ViewHolder {
        val binding: ItemUserBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.context), R.layout.item_user, parent, false)
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: UserListAdapter.ViewHolder, position: Int) {
        holder.bind(userModelList[position])
    }

    override fun getItemCount(): Int {
        return if(::userModelList.isInitialized) userModelList.size else 0
    }

    fun updateUserList(userModelList:List<UserModel>){
        this.userModelList = userModelList
        notifyDataSetChanged()
    }

    class ViewHolder(private val binding: ItemUserBinding):RecyclerView.ViewHolder(binding.root){
        private val viewModel = UserViewModel()

        fun bind(userModel: UserModel){
            viewModel.bind(userModel)
            binding.viewModel =viewModel
        }
    }
}

item-user.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">

    <data>
        <variable
                name="viewModel"
                type="com.example.***.ui.MyUser.UserViewModel" />
    </data>

    <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="16dp"
            android:paddingRight="16dp">

        <TextView
                android:id="@+id/user_title"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:textStyle="bold"
                app:mutableText="@{viewModel.getUserTitle()}"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

        <TextView
                android:id="@+id/user_description"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                app:mutableText="@{viewModel.getUserDesc()}"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/user_title" />
    </android.support.constraint.ConstraintLayout>
</layout>

请注意,gradle中已经启用了数据绑定,这里非常重要的问题是,在我的片段和适配器中,这一行:

binding.viewModel =viewModel

报告类型不匹配,如下所示:

Type mismatch.
Required:MyUser.UserListViewModel?
Found:com.example.***.ui.MyUser.UserListViewModel

当我构建我的项目时,错误如下:

error: cannot find symbol
import com.example.***.databinding.FragmentUserBindingImpl;

共有2个答案

呼延源
2023-03-14

类型不匹配。必需:MyUser。用户列表视图模型?发现:com。示例。***。用户界面。我的用户。UserListViewModel

基本上,错误是告诉你

binding.viewModel //is a nullable type and there for it expects a nullable 
//type to be assigned as well

因此,只需将您的视图模型转换为可空类型,方法是在其delacarion之后添加? simbol(注意后期init类型不允许可空类型)。试试看

private var viewModel: UserListViewModel? =  null

关于数据绑定库需要编译的第二个错误,为了自动生成绑定类,只需重建项目,这个错误就会消失。

请随意使用此模板作为基础,以避免所有样板代码

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
annotation class ContentView(@LayoutRes val id: Int)

fun ViewGroup.inflate(@LayoutRes layoutId: Int,
addContainer: Boolean = false): View {                                                     
    return LayoutInflater.from(context).inflate(layoutId,this,addContainer)      
}

@Suppress("UNCHECKED_CAST")
abstract class BaseFragment<Model : ViewModel, Binding : ViewDataBinding> : Fragment() {
/**
 * Data binding class variable all view elements declared on the
 * Xml file will be available within this instance if a view model
 * Is required for the xml to work we will need to bind it on @onBindViewModel
 */
protected lateinit var binding: WeakReference<Binding?>

/**
 * Fragments view model according to MVVM android architecture
 * Each fragment class should have one , in order to facilitate
 * Live Data and Binding library features, tho we can skip it
 */
protected lateinit var viewModel: WeakReference<Model?>

/**
 * Here is where most likely you will get not null data , both binding and
 * view model references can be destroyed by garbage collector
 * If this application reaches low memory levels
 *
 * This optional method is used to bind the required view model inside the
 * Xml file, this is optional to use tho is recommended
 * Bind them by calling the view model binding.customViewModel = viewModel
 */
protected open fun onBindViewModel(viewModel: Model?, binding: Binding?) {}

/**
 * There will be the occasion where custom params will be needed on view model's
 * Constructor in this case will want to override the default creation @see ViewModelFactory
 */
protected open fun onCreateViewModel(modelType: Class<Model>): Model? = if (modelType != ViewModel::class.java)
    ViewModelProviders.of(requireActivity()).get(modelType) else null

/**
 * Here we will inherit view model and binding values based on the class
 * Parameters and store them in global variables so any class extending
 * From Base activity has access to binding and view model instances by default
 */
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val layout = this.javaClass.annotations.find { it.annotationClass == ContentView::class } as ContentView?
        ?: throw RuntimeException("You annotate this class with @ContentView and provide a layout resource")

    container?.let { binding = WeakReference(DataBindingUtil.bind(it.inflate(layout.id))!!) }
        ?: run { binding = WeakReference(DataBindingUtil.bind(inflater.inflate(layout.id, null))) }

    viewModel = WeakReference(
        onCreateViewModel(
            (this.javaClass.genericSuperclass
                    as ParameterizedType).actualTypeArguments[0] as Class<Model>
        )
    )

    setHasOptionsMenu(true)
    onBindViewModel(viewModel.get(), binding.get())
    return binding.get()?.root
}
}

就像这样使用它(看看有多少锅炉铭牌代码消失了)

@ContentView(R.layout.fragment_user)
class UserFragment: BaseFragment<UserListViewModel, FragmentUserBinding> {

override fun onBindViewModel(viewModel: UserListViewModel?, binding: FragmentUserBinding?) {
    binding.viewModel = viewModel
}
}
壤驷泓
2023-03-14

第一个错误非常明确:绑定。viewModel需要一个可为空的UserListViewModel吗?并获得一个不可为空的UserListViewModel(参见kotlin null安全文档)。你可以尝试这样的方法来摆脱它:

将viewModel声明为

private var viewModel: UserListViewModel? = null

并按如下方式设置绑定:

viewModel?.let{binding.viewModel = it}

关于第二个错误,您的声明似乎没有问题,但有时Android Studio的缓存会损坏,请尝试使缓存无效/重新启动,这可能会有所帮助。

 类似资料:
  • 迁移到androidx后 我在编译时遇到问题 错误:找不到符号androidx。数据绑定。数据绑定组件 符号:类DataBindingComponent位置:包androidx。数据绑定 im使用的Gradle版本为5.4.1 注:androidx中的其他组件。数据绑定包工作正常。像DataBindingUtil 只有DataBindingComponent不工作

  • 我正在开始使用特性。我正面临这方面的问题。

  • 首先,我需要承认这里有一个明显非常相似但不重复的问题。在该线程中提出的解决方案都不起作用。 我的应用程序文件结构如下: 我的应用程序包含 在文本中,错误有不同的和 如果我将datamodel.java从Models包中移出并直接放入[mydomain].[myapplication],那么我会得到不同的结果。它确实在仿真程序中构建和运行,但大部分布局信息没有出现。左上角没有汉堡包菜单,页眉没有标题

  • attr绑定是用来为html元素绑定属性值的,这种绑定非常有用,例如我们需要想一个元素添加title属性,或者为img标签添加src属性。 示例代码: //.W片段 <a bind-attr="{ href: url, title: details }"> Report </a> //js片段 this.url=justep.Bind.observable("year-end.html"),

  • submit绑定只能用在form元素中,当form提交的时候被触发,并且默认阻止form的提交。因此我们通常在submit的处理函数中以ajax的方式提交form表单。 示例代码: //.W片段 <form bind-submit="doSomething"> ... form contents go here ... <button type="submit">Submit</butt

  • with绑定用来创建一个绑定上下文,在子元素内的所有绑定都在这个上下文中进行。 示例代码: //.W片段 <h1 bind-text="city"> </h1> <p bind-with="coords"> Latitude: <span bind-text="latitude"> </span>, Longitude: <span bind-text="longitude"> </span