我想向recyclerview提供元素和livedata的列表。我使用了数据绑定适配器,当我想向适配器发送数据时,列表从livedata返回null。整个代码如下。 谢谢
我调试了代码,看到数据何时从AppDbHelper.java到HomeViewmodel.java并将绑定适配器设置为实时数据。因此,尽管livedata不为null,但数据绑定适配器(heartRateResultsModels)处的arraylist为null,导致应用程序崩溃。
1.fragment_home.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="ir.basamadazmanovin.heartrate.ui.main.home.HomeViewModel" />
</data>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:refreshing="@{viewModel.isLoading}">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.home.HomeFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/fragment_home_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:adapter="@{viewModel.heartRateResultsLiveData}"
tools:listitem="@layout/row_fragment_home" />
</FrameLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</layout>
2.BaseFragment.java
public abstract class BaseFragment<T extends ViewDataBinding, V extends BaseViewModel> extends Fragment {
protected FragmentNavigation mFragmentNavigation;
private BaseActivity mActivity;
private View mRootView;
private T mViewDataBinding;
private V mViewModel;
public abstract int getBindingVariable();
public abstract
@LayoutRes
int getLayoutId();
public abstract V getViewModel();
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof BaseActivity) {
BaseActivity activity = (BaseActivity) context;
this.mActivity = activity;
activity.onFragmentAttached();
}
if (context instanceof FragmentNavigation) {
mFragmentNavigation = (FragmentNavigation) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
performDependencyInjection();
super.onCreate(savedInstanceState);
mViewModel = getViewModel();
setHasOptionsMenu(false);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mViewDataBinding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false);
mRootView = mViewDataBinding.getRoot();
return mRootView;
}
public BaseActivity getBaseActivity() {
return mActivity;
}
public T getViewDataBinding() {
return mViewDataBinding;
}
public void hideKeyboard() {
if (mActivity != null) {
mActivity.hideKeyboard();
}
}
public boolean isNetworkConnected() {
return mActivity != null && mActivity.isNetworkConnected();
}
public void openActivityOnTokenExpire() {
if (mActivity != null) {
mActivity.openActivityOnTokenExpire();
}
}
private void performDependencyInjection() {
AndroidSupportInjection.inject(this);
}
public interface Callback {
void onFragmentAttached();
void onFragmentDetached(String tag);
}
}
3.HomeFragment.java
public class HomeFragment extends BaseFragment<FragmentHomeBinding,HomeViewModel> implements HomeNavigator {
FragmentHomeBinding mFragmentHomeBinding;
@Inject
LinearLayoutManager mLayoutManager;
@Inject
HeartRateResultsAdapter mAdapter;
@Inject
ViewModelProviderFactory factory;
private HomeViewModel mHomeViewModel;
public static HomeFragment newInstance() {
return new HomeFragment();
}
@Override
public int getBindingVariable() {
return BR.viewModel;
}
@Override
public int getLayoutId() {
return R.layout.fragment_home;
}
@Override
public HomeViewModel getViewModel() {
mHomeViewModel = ViewModelProviders.of(this, factory).get(HomeViewModel.class);
return null;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHomeViewModel.setNavigator(this);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mFragmentHomeBinding = getViewDataBinding();
setUp();
}
private void setUp() {
mLayoutManager.setOrientation(RecyclerView.VERTICAL);
mFragmentHomeBinding.fragmentHomeRecyclerView.setLayoutManager(mLayoutManager);
mFragmentHomeBinding.fragmentHomeRecyclerView.setItemAnimator(new DefaultItemAnimator());
mFragmentHomeBinding.fragmentHomeRecyclerView.setAdapter(mAdapter);
}
@Override
public void handleError(Throwable throwable) {
}
}
4.BaseViewModel.java
public class BaseViewModel<N> extends ViewModel {
private final DataManager mDataManager;
private final ObservableBoolean mIsLoading = new ObservableBoolean(false);
private final SchedulerProvider mSchedulerProvider;
private CompositeDisposable mCompositeDisposable;
private WeakReference<N> mNavigator;
public BaseViewModel(DataManager dataManager,
SchedulerProvider schedulerProvider) {
this.mDataManager = dataManager;
this.mSchedulerProvider = schedulerProvider;
this.mCompositeDisposable = new CompositeDisposable();
}
@Override
protected void onCleared() {
mCompositeDisposable.dispose();
super.onCleared();
}
public CompositeDisposable getCompositeDisposable() {
return mCompositeDisposable;
}
public DataManager getDataManager() {
return mDataManager;
}
public ObservableBoolean getIsLoading() {
return mIsLoading;
}
public void setIsLoading(boolean isLoading) {
mIsLoading.set(isLoading);
}
public N getNavigator() {
return mNavigator.get();
}
public void setNavigator(N navigator) {
this.mNavigator = new WeakReference<>(navigator);
}
public SchedulerProvider getSchedulerProvider() {
return mSchedulerProvider;
}
}
5.HomeViewModel.java
public class HomeViewModel extends BaseViewModel<HomeNavigator> {
private MutableLiveData<ArrayList<HeartRateResultsModel>> heartRateResultsLiveData;
public HomeViewModel(DataManager dataManager, SchedulerProvider schedulerProvider) {
super(dataManager, schedulerProvider);
heartRateResultsLiveData = new MutableLiveData<>();
fetchRepos();
}
public void fetchRepos() {
setIsLoading(true);
getCompositeDisposable().add(getDataManager()
.getHeartRateResults()
.subscribeOn(getSchedulerProvider().io())
.observeOn(getSchedulerProvider().ui())
.subscribe(heartRateResultsModels -> {
heartRateResultsLiveData.setValue(heartRateResultsModels);
setIsLoading(false);
}, throwable -> {
setIsLoading(false);
getNavigator().handleError(throwable);
}));
}
public LiveData<ArrayList<HeartRateResultsModel>> getHeartRateResultsLiveData() {
return heartRateResultsLiveData;
}
}
6.BindingUtils.java
public final class BindingUtils {
private BindingUtils() {
// This class is not publicly instantiable
}
@BindingAdapter("imageUrl")
public static void setImageUrl(ImageView imageView, String url) {
Context context = imageView.getContext();
Glide.with(context).load(url).into(imageView);
}
@BindingAdapter("onNavigationItemSelected")
public static void setOnNavigationItemSelectedListener(
BottomNavigationView view, OnNavigationItemSelectedListener listener) {
view.setOnNavigationItemSelectedListener(listener);
}
@BindingAdapter({"adapter"})
public static void addHeartRateResultsItems(RecyclerView recyclerView,
ArrayList<HeartRateResultsModel> heartRateResultsModels) {
HeartRateResultsAdapter adapter = (HeartRateResultsAdapter) recyclerView.getAdapter();
if (adapter != null) {
adapter.clearItems();
adapter.addItems(heartRateResultsModels);
}
}
}
7.DataManager.java
public interface DataManager extends DbHelper, PreferencesHelper, ApiHelper {
}
8.DbHelper.java
public interface DbHelper {
Single<ArrayList<HeartRateResultsModel>> getHeartRateResults();
}
9.AppDataManager.java
public class AppDataManager implements DataManager{
private final ApiHelper mApiHelper;
private final Context mContext;
private final DbHelper mDbHelper;
private final Gson mGson;
private final PreferencesHelper mPreferencesHelper;
@Inject
public AppDataManager(Context context,
DbHelper dbHelper,
PreferencesHelper preferencesHelper,
ApiHelper apiHelper,
Gson gson) {
mContext = context;
mDbHelper = dbHelper;
mPreferencesHelper = preferencesHelper;
mApiHelper = apiHelper;
mGson = gson;
}
@Override
public Single<ArrayList<HeartRateResultsModel>> getHeartRateResults() {
return mDbHelper.getHeartRateResults();
}
}
10.AppDbHelper.java
@Singleton
public class AppDbHelper implements DbHelper{
private final AppDatabase mAppDatabase;
@Inject
public AppDbHelper(AppDatabase appDatabase) {
this.mAppDatabase = appDatabase;
}
@Override
public Single<ArrayList<HeartRateResultsModel>> getHeartRateResults() {
return Single.fromCallable(new Callable<ArrayList<HeartRateResultsModel>>() {
@Override
public ArrayList<HeartRateResultsModel> call() throws Exception {
ArrayList<HeartRateResultsModel> models = new ArrayList<>();
models.add(new HeartRateResultsModel("","1"));
models.add(new HeartRateResultsModel("","2"));
return models;
}
});
}
}
答案 0 :(得分:2)
我错过了设置
<块引用>mViewDataBinding.vm = 视图模型
其中“vm”是布局中的变量,“viewModel”是活动或片段中的局部变量
此外,正如@Menma 所建议的,不要忘记添加
<块引用>mViewDataBinding.setLifecycleOwner(this);
答案 1 :(得分:0)
在类mViewDataBinding.setLifecycleOwner(this);
的方法onViewCreated()
上添加BaseFragment
,像这样:
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mViewDataBinding.setVariable(getBindingVariable(), mViewModel);
mViewDataBinding.setLifecycleOwner(this);
mViewDataBinding.executePendingBindings();
}
答案 2 :(得分:0)
1 。始终确保在UI控制器(片段或活动)中设置XML绑定变量
在您的XML布局中
<data>
<variable
name="viewModel"
type="com.felixfavour.ViewModel" />
</data>
在您的UI控制器中(在这种情况下为片段)
listViewModel = ViewModel(this).get(ListViewModel::class)
bindingObj.viewModel = listViewModel
2 。必须将setLifecycleOwner()
设置为LifeCycleOwner
,这是UI控制器固有的功能,否则,LiveData将失去其Live效果,因为将无法对其进行观察,从本质上讲,LiveData不会传播到用户界面。
bindingObj.setLifeCycleOwner = this
其中this
= UI控制器(还是活动/片段)