英文:
Cannot find a setter for ~ItemBinding~ that accepts parameter type 'androidx.lifecycle.LiveData<
问题
不能找到适用于 <the_derek.dogstuff.databinding.DogItemBinding app:product> 的设置器,该设置器接受参数类型 'androidx.lifecycle.LiveData<the_derek.dogstuff.db.entity.DogEntity>'。如果绑定适配器提供了设置器,请检查适配器的注释是否正确,并且参数类型是否匹配。
我已经逐行检查了我的应用程序超过两天了。我使用了 Google 提供的“BasicSample” Android Room 应用程序来模拟我的应用程序,但是当我将它包含在我的 dog_fragment.xml 中时,出现了这个错误:
<include
layout="@layout/dog_item"
app:product="@{dogViewModel.dog}" />
“dog_item” 布局(dog_item.xml)用于显示狗的列表,当您点击它时,它会带您进入狗的详细信息屏幕(dog_fragment.xml)。没有它,一切都很正常,但是缺少“狗”图块以进入详细信息屏幕,只会显示一列咀嚼玩具。
dog_fragment.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>
<import type="android.view.View" />
<variable
name="isLoading"
type="boolean" />
<variable
name="dog"
type="the_derek.dogstuff.viewmodel.DogViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/cardview_light_background"
android:orientation="vertical">
<include
layout="@layout/dog_item"
app:product="@{dogViewModel.dog}" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_loading_chew_toys"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/loading_chew_toys"
app:visibleGone="@{isLoading}" />
<FrameLayout
android:id="@+id/chew_toys_list_wrapper"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/chew_toy_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/cd_chew_toys_list"
app:layoutManager="LinearLayoutManager"
app:visibleGone="@{!isLoading}" />
</FrameLayout>
</FrameLayout>
</LinearLayout>
</layout>
DogFragment.java
public class DogFragment extends Fragment {
private static final String TAG = "\t\tDogFragment";
private static final String KEY_DOG_ID = "dog_id";
private final ChewToyClickCallback mChewToyClickCallback =
chewToy -> {
// no-op
};
private DogFragmentBinding mBinding;
private ChewToyAdapter mChewToyAdapter;
public static DogFragment forDog(int dogId) {
DogFragment fragment = new DogFragment();
Bundle args = new Bundle();
args.putInt(KEY_DOG_ID, dogId);
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
mBinding = DataBindingUtil.inflate(inflater, R.layout.dog_fragment, container, false);
mChewToyAdapter = new ChewToyAdapter(mChewToyClickCallback);
mBinding.chewToyList.setAdapter(mChewToyAdapter);
return mBinding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
DogViewModel.Factory factory =
new DogViewModel.Factory(
requireActivity().getApplication(), requireArguments().getInt(KEY_DOG_ID));
final DogViewModel model =
new ViewModelProvider(this, factory).get(DogViewModel.class);
mBinding.setLifecycleOwner(getViewLifecycleOwner());
mBinding.setDogViewModel(model);
subscribeToModel(model);
}
private void subscribeToModel(final DogViewModel model) {
model
.getChewToys()
.observe(
getViewLifecycleOwner(),
chewToyEntities -> {
if (chewToyEntities != null) {
mBinding.setIsLoading(false);
mChewToyAdapter.submitList(chewToyEntities);
} else {
mBinding.setIsLoading(true);
}
});
}
@Override
public void onDestroyView() {
mBinding = null;
mChewToyAdapter = null;
super.onDestroyView();
}
}
DogViewModel.java
public class DogViewModel extends AndroidViewModel {
private static final String TAG = "\t\tDogViewModel";
private final LiveData<DogEntity> mObservableDog;
private final LiveData<List<ChewToyEntity>> mObservableChewToys;
public DogViewModel(
@NonNull Application application, DataRepository repository, final int dogId) {
super(application);
mObservableChewToys = repository.loadChewToysById(dogId);
mObservableDog = repository.loadDog(dogId);
}
public LiveData<List<ChewToyEntity>> getChewToys() {
return mObservableChewToys;
}
public LiveData<DogEntity> getDog() {
return mObservableDog;
}
public static class Factory extends ViewModelProvider.NewInstanceFactory {
@NonNull private final Application mApplication;
private final int mDogId;
private final DataRepository mRepository;
public Factory(@NonNull Application application, int dogId) {
mApplication = application;
mDogId = dogId;
mRepository = ((DogApp) application).getRepository();
}
@SuppressWarnings("unchecked")
@Override
@NonNull
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return (T) new DogViewModel(mApplication, mRepository, mDogId);
}
}
}
BindingAdapters.java
public class BindingAdapters {
@BindingAdapter("visibleGone")
public static void showHide(View view, boolean show) {
view.setVisibility(show ? View.VISIBLE : View.GONE);
}
}
DogClickCallback.java
public interface DogClickCallback {
void onClick(Dog dog);
}
dao 查询
@Query("select * from dog_table where id = :dogId")
LiveData<DogEntity> loadDog(int dogId);
DogAdapter.java
public class DogAdapter extends RecyclerView.Adapter<DogAdapter.DogViewHolder> {
private static final String TAG = "\t\tDogAdapter";
@Nullable private final DogClickCallback mDogClickCallback;
List<? extends Dog>
<details>
<summary>英文:</summary>
> Cannot find a setter for
> <the_derek.dogstuff.databinding.DogItemBinding app:product> that
> accepts parameter type
> 'androidx.lifecycle.LiveData<the_derek.dogstuff.db.entity.DogEntity>'
> If a binding adapter provides the setter, check that the adapter is
> annotated correctly and that the parameter type matches.
I’ve been going line-by-line through my app for over two days now. I used the Google provided “BasicSample” Android Room app to mock up my own app but am getting this error when I include this in my dog_fragment.xml
<include
layout="@layout/dog_item"
app:product="@{dogViewModel.dog}" />
The “dog_item” layout (dog_item.xml) is for showing a list of dogs, when you then click on it, it will bring you to a dog details screen (dog_fragment.xml). Without it, everything works great but it’s missing the “dog” tile to play into the details screen, and will only show a list of chew_toys.
> dog_fragment.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>
<import type="android.view.View" />
<variable
name="isLoading"
type="boolean" />
<variable
name="dog"
type="the_derek.dogstuff.viewmodel.DogViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/cardview_light_background"
android:orientation="vertical">
<include
layout="@layout/dog_item"
app:product="@{dogViewModel.dog}" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_loading_chew_toys"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/loading_chew_toys"
app:visibleGone="@{isLoading}" />
<FrameLayout
android:id="@+id/chew_toys_list_wrapper"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/chew_toy_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/cd_chew_toys_list"
app:layoutManager="LinearLayoutManager"
app:visibleGone="@{!isLoading}" />
</FrameLayout>
</FrameLayout>
</LinearLayout>
</layout>
> DogFragment.java
public class DogFragment extends Fragment {
private static final String TAG = "\t\tDogFragment";
private static final String KEY_DOG_ID = "dog_id";
private final ChewToyClickCallback mChewToyClickCallback =
chewToy -> {
// no-op
};
private DogFragmentBinding mBinding;
private ChewToyAdapter mChewToyAdapter;
public static DogFragment forDog(int dogId) {
DogFragment fragment = new DogFragment();
Bundle args = new Bundle();
args.putInt(KEY_DOG_ID, dogId);
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
mBinding = DataBindingUtil.inflate(inflater, R.layout.dog_fragment, container, false);
mChewToyAdapter = new ChewToyAdapter(mChewToyClickCallback);
mBinding.chewToyList.setAdapter(mChewToyAdapter);
return mBinding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
DogViewModel.Factory factory =
new DogViewModel.Factory(
requireActivity().getApplication(), requireArguments().getInt(KEY_DOG_ID));
final DogViewModel model =
new ViewModelProvider(this, factory).get(DogViewModel.class);
mBinding.setLifecycleOwner(getViewLifecycleOwner());
mBinding.setDogViewModel(model);
subscribeToModel(model);
}
private void subscribeToModel(final DogViewModel model) {
model
.getChewToys()
.observe(
getViewLifecycleOwner(),
chewToyEntities -> {
if (chewToyEntities != null) {
mBinding.setIsLoading(false);
mChewToyAdapter.submitList(chewToyEntities);
} else {
mBinding.setIsLoading(true);
}
});
}
@Override
public void onDestroyView() {
mBinding = null;
mChewToyAdapter = null;
super.onDestroyView();
}
}
> DogViewModel.java
public class DogViewModel extends AndroidViewModel {
private static final String TAG = "\t\tDogViewModel";
private final LiveData<DogEntity> mObservableDog;
private final LiveData<List<ChewToyEntity>> mObservableChewToys;
public DogViewModel(
@NonNull Application application, DataRepository repository, final int dogId) {
super(application);
mObservableChewToys = repository.loadChewToysById(dogId);
mObservableDog = repository.loadDog(dogId);
}
public LiveData<List<ChewToyEntity>> getChewToys() {
return mObservableChewToys;
}
public LiveData<DogEntity> getDog() {
return mObservableDog;
}
public static class Factory extends ViewModelProvider.NewInstanceFactory {
@NonNull private final Application mApplication;
private final int mDogId;
private final DataRepository mRepository;
public Factory(@NonNull Application application, int dogId) {
mApplication = application;
mDogId = dogId;
mRepository = ((DogApp) application).getRepository();
}
@SuppressWarnings("unchecked")
@Override
@NonNull
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return (T) new DogViewModel(mApplication, mRepository, mDogId);
}
}
}
> BindingAdapters.java
public class BindingAdapters {
@BindingAdapter("visibleGone")
public static void showHide(View view, boolean show) {
view.setVisibility(show ? View.VISIBLE : View.GONE);
}
}
> DogClickCallback.java
public interface DogClickCallback {
void onClick(Dog dog);
}
> dao query
@Query("select * from dog_table where id = :dogId")
LiveData<DogEntity> loadDog(int dogId);
> DogAdapter.java
public class DogAdapter extends RecyclerView.Adapter<DogAdapter.DogViewHolder> {
private static final String TAG = "\t\tDogAdapter";
@Nullable private final DogClickCallback mDogClickCallback;
List<? extends Dog> mDogList;
public DogAdapter(@Nullable DogClickCallback clickCallback) {
Log.i(TAG, "DogAdapter: public constructor");
mDogClickCallback = clickCallback;
setHasStableIds(true);
}
public void setDogList(final List<? extends Dog> dogList) {
if (mDogList == null) {
mDogList = dogList;
notifyItemRangeInserted(0, dogList.size());
} else {
DiffUtil.DiffResult result =
DiffUtil.calculateDiff(
new DiffUtil.Callback() {
@Override
public int getOldListSize() {
return mDogList.size();
}
@Override
public int getNewListSize() {
return dogList.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return mDogList.get(oldItemPosition).getId()
== dogList.get(newItemPosition).getId();
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
Dog newDog = dogList.get(newItemPosition);
Dog oldDog = mDogList.get(oldItemPosition);
return newDog.getId() == oldDog.getId()
&& TextUtils.equals(newDog.getName(), oldDog.getName());
}
});
mDogList = dogList;
result.dispatchUpdatesTo(this);
}
}
@Override
@NonNull
public DogViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
DogItemBinding binding =
DataBindingUtil.inflate(
LayoutInflater.from(parent.getContext()), R.layout.dog_item, parent, false);
binding.setCallback(mDogClickCallback);
return new DogViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull DogViewHolder holder, int position) {
holder.binding.setDog(mDogList.get(position));
holder.binding.executePendingBindings();
}
@Override
public int getItemCount() {
return mDogList == null ? 0 : mDogList.size();
}
@Override
public long getItemId(int position) {
return mDogList.get(position).getId();
}
static class DogViewHolder extends RecyclerView.ViewHolder {
final DogItemBinding binding;
public DogViewHolder(DogItemBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
}
----------
----------
(DogEntity also has Dog model class, if that helps)
I've tried Invalidate Caches/Restart, I've tried Clean Project, Rebuild Project. I've started a new project and copied my files into it.
Ooh, also, this is an error in addition:
import the_derek.dogstuff.databinding.DogFragmentBindingImpl;
It tells me it cannot resolve **DogFragmentBindingImpl**
I don't know how it's not getting generated but I assume the problems are intertwined. I don't know if I missed putting any code that could help, please let me know.
(modeled after)
[android architecture-components-samples][1]
[1]: https://github.com/android/architecture-components-samples/tree/master/BasicSample
</details>
# 答案1
**得分**: 1
这是[绑定适配器][1]错误。如果您在XML中编写了'app:product',则在您的Kotlin或Java类之一中必须有一个名为'product'的绑定适配器。例如,对于您的
> app:product="@{dogViewModel.dog}"
需要有类似于以下内容的代码:
@BindingAdapter("product")
fun yourFunctionName(yourViewType: YourViewType, data: List
// 在此处放置您的绑定代码
}
了解有关数据绑定和绑定适配器的更多信息。
[1]: https://developer.android.com/topic/libraries/data-binding/binding-adapters
<details>
<summary>英文:</summary>
This is [binding adapter][1] error. If you write 'app:product' in your XML, there has to be binding adapter inside one of your kotlin or java classes with the name of 'product'. For example, for your
> app:product="@{dogViewModel.dog}"
there needs to be something like this:
@BindingAdapter("product")
fun yourFunctionName(yourViewType: YourViewType, data: List<DogEntity>?) {
// your binding code here
}
Read more about data binding and binding adapters.
[1]: https://developer.android.com/topic/libraries/data-binding/binding-adapters
</details>
# 答案2
**得分**: 1
[德里克·福西特的解决方案](https://stackoverflow.com/a/63601993) 告诉你,在 include 标签内部,参数名必须与所包含布局内使用的变量名匹配。
```xml
<include
layout="@layout/dog_item"
app:dog="@{dogViewModel.dog}" />
dog_item
<data>
<variable
name="dog"
type="$path.DogClass" />
</data>
在绑定方面,没有通用的参数名称与变量匹配,您可以自己定义名称,然后相应地进行设置。
英文:
the derek Fawcett's solution is telling you that the parameter name inside the include-tag has to match the variable name used inside the included layout.
<include
layout="@layout/dog_item"
app:dog="@{dogViewModel.dog}" />
dog_item
<data>
<variable
name="dog"
type="$path.DogClass" />
</data>
There are no general parameter names to match variables when it comes to bindings, you can define the names yourself and then set them accordingly.
答案3
得分: -3
我花了几个星期或一个月的时间,认为“app:product”是一种用于XML的标准短语或约定。我以为“product”是一个类似于“gravity”或“layout”的通用术语...如果你明白我的意思的话。因为当我发表这个问题时,我对Android还不熟悉,我从来没有想过“app:”后面的术语需要根据数据中的变量进行更改。
英文:
I spent weeks or a month thinking that "app:product" was some sort of standard phrase or convention for XML. I thought "product" was a generic term used like "gravity" or "layout"..... if you get what I'm saying. Because when I posted the question I was new to Android, I never thought that the term after "app:" needed to be changed depending on the variable in data.
<include
layout="@layout/dog_item"
app:dog="@{dogViewModel.dog}" />
答案4
得分: -4
你在这里传递了一个 LiveData 对象:
app:product="@{dogViewModel.dog}"
你需要传递:
app:product="@{dogViewModel.dog.value}"
英文:
You're passing in a LiveData object here:
app:product="@{dogViewModel.dog}"
You need to pass in:
app:product="@{dogViewModel.dog.value}"
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论