Lifecycle+liveData+DataBinding三部曲
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lifecycle+liveData+DataBinding三部曲相关的知识,希望对你有一定的参考价值。
参考技术A 对Lifecycle liveData的理解:System已经做了:Fragment/Actvity已经实现了LifecycleOwner 的接口:
Userdo:1-->viewMode(或者IPresenter )implements LifecycleObserver
2-->只需在Fragment/Activity中调用:getLifecycle().addObserver(viewModel);
3-->viewModel.dataList.observe(owner, Observer);
1--2---原理:
Fragment/Activity的构造方法中已经调用了下列方法:
getLifecycle()返回的对象mLifecycleRegistry,在LifecycleOwner( Activity/Fragment)的生命周期方法中都做了监听,这就方便了我们Observer(viewMode或者Presenter)对LifecycleOwner生命周期的感知
--3--LiveData原理:
viewModel.dataList.observe(owner, Observer)------> LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);它实现了GenericLifecycleObserver,而GenericLifecycleObserver继承了LifecycleObserver接口。当组件(Fragment/Activity)生命周期变化时会通过onStateChanged()方法回调过来。Observer接口就是观察者,其中定义了LiveData数据变化的回调方法onChanged()。
因此我们就可以使用三部曲搞定 data对ui的生命周期的监控
Databinding就更简单了,直接跟着撸码就ok了,Fragment、Activity通过DataBindingUtil.inflate()就可以联系起来,而且可以双向绑定哦。
Lifecycle+liveData+DataBinding才是最爽的编码方式。
具体原理:[ https://blog.csdn.net/zhuzp_blog/article/details/78871527]
找不到接受参数类型 'androidx.lifecycle.LiveData< 的 ~ItemBinding~ 的设置器
【中文标题】找不到接受参数类型 \'androidx.lifecycle.LiveData< 的 ~ItemBinding~ 的设置器【英文标题】:Cannot find a setter for ~ItemBinding~ that accepts parameter type 'androidx.lifecycle.LiveData<找不到接受参数类型 'androidx.lifecycle.LiveData< 的 ~ItemBinding~ 的设置器 【发布时间】:2020-12-11 04:04:37 【问题描述】:找不到二传手
那 接受参数类型 'androidx.lifecycle.LiveData ' 如果绑定适配器提供了设置器,请检查适配器是否 注释正确且参数类型匹配。
两天多来,我一直在逐行浏览我的应用程序。我使用 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_
android:layout_
android:background="@color/cardview_light_background"
android:orientation="vertical">
<include
layout="@layout/dog_item"
app:product="@dogViewModel.dog" />
<FrameLayout
android:layout_
android:layout_>
<TextView
android:id="@+id/tv_loading_chew_toys"
android:layout_
android:layout_
android:text="@string/loading_chew_toys"
app:visibleGone="@isLoading" />
<FrameLayout
android:id="@+id/chew_toys_list_wrapper"
android:layout_
android:layout_>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/chew_toy_list"
android:layout_
android:layout_
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);
道查询
@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 也有 Dog 模型类,如果有帮助的话) 我试过无效缓存/重启,我试过清理项目,重建项目。我已经开始了一个新项目并将我的文件复制到其中。 哦,还有,这是一个错误补充:
import the_derek.dogstuff.databinding.DogFragmentBindingImpl;
它告诉我它无法解析 DogFragmentBindingImpl 我不知道它是如何产生的,但我认为这些问题是相互交织的。我不知道我是否错过了任何可以提供帮助的代码,请告诉我。
(仿照) android architecture-components-samples
【问题讨论】:
【参考方案1】:这是binding adapter 错误。如果您在 XML 中编写“app:product”,则在您的 kotlin 或 java 类之一中必须有一个名为“product”的绑定适配器。例如,对于您的
app:product="@dogViewModel.dog"
应该是这样的:
@BindingAdapter("product")
fun yourFunctionName(yourViewType: YourViewType, data: List<DogEntity>?)
// your binding code here
阅读有关数据绑定和绑定适配器的更多信息。
【讨论】:
当我试图将变量发送到另一个布局(在“包含”中)时,“app:”之后的值需要是变量在“”部分中的名称xml.【参考方案2】:我花了数周或一个月的时间认为“app:product”是 XML 的某种标准短语或约定。我认为“产品”是一个通用术语,如“重力”或“布局”......如果你明白我在说什么。因为当我发布我是 Android 新手的问题时,我从未想过“app:”后面的术语需要根据数据中的变量进行更改。
<include
layout="@layout/dog_item"
app:dog="@dogViewModel.dog" />
【讨论】:
这个解决方案的意义何在?我在使用<include ...>
布局时遇到了类似的问题,我不知道您的解决方案有什么帮助。【参考方案3】:
您在这里传递了一个 LiveData 对象:
app:product="@dogViewModel.dog"
你需要传入:
app:product="@dogViewModel.dog.value"
【讨论】:
假设加载了狗实体,下面有所有的细节/咀嚼玩具。此外,如果我将其更改为“@dogViewModel.dog.value”(例如 - 字符串),它会告诉我:“找不到接受参数类型 'java.lang 的 ... DogItemBinding app:product> 的设置器.String'" 试试“@dogViewModel.getDog().value” 只是 .getDog() 或 .getDog() 值产生相同的错误:-( 刚刚在 Google 的 Basic Sample App 上发现,如果我更改了他们的字段。 <include layout="@layout/product_item" app:product="@productViewModel.product" /> 到<include layout="@layout/product_item" app:product="@productViewModel.product.id" />
它会产生与我得到的完全相同的错误消息以上是关于Lifecycle+liveData+DataBinding三部曲的主要内容,如果未能解决你的问题,请参考以下文章
Lifecycle+liveData+DataBinding三部曲