Je souhaite alimenter la vue de recyclage avec une liste d'éléments et de données. J'ai utilisé un adaptateur de liaison de données et lorsque je veux envoyer des données à l'adaptateur, la liste renvoie null de livingata. le code entier est ci-dessous. merci
J'ai débogué le code et j'ai vu quand les données sont venues de AppDbHelper.java vers HomeViewmodel.java et définies sur les données en direct, l'adaptateur de liaison n'a pas changé. ainsi, bien que la valeur de vie ne soit pas nulle, l'arraylist de l'adaptateur de liaison de données (heartRateResultsModels) est null et l'application a planté.
1.fragment_home.xml
@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; } }); } }
2.BaseFragment.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(); } }
3.HomeFragment .java
public interface DbHelper { Single<ArrayList<HeartRateResultsModel>> getHeartRateResults(); }
4.BaseViewModel.java
public interface DataManager extends DbHelper, PreferencesHelper, ApiHelper { }
5.HomeViewModel.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); } } }
6.BindingUtils.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; } }
7.DataManager.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; } }
8.DbHelper .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) { } }
9.AppDataManager.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); } }
10.AppDbHelper.java
<?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>
3 Réponses :
ajoutez mViewDataBinding.setLifecycleOwner (this);
sur la méthode: onViewCreated ()
à la classe BaseFragment
, comme ceci:
@Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mViewDataBinding.setVariable(getBindingVariable(), mViewModel); mViewDataBinding.setLifecycleOwner(this); mViewDataBinding.executePendingBindings(); }
1 . Assurez-vous toujours de définir vos variables de liaison XML dans votre contrôleur d'interface utilisateur (fragment ou activité)
Dans votre mise en page XML
bindingObj.setLifeCycleOwner = this
Dans votre contrôleur d'interface utilisateur (Fragment dans ce cas)
listViewModel = ViewModel(this).get(ListViewModel::class) bindingObj.viewModel = listViewModel
2 . Il est nécessaire que vous définissiez setLifecycleOwner ()
sur LifeCycleOwner
qui est intrinsèquement votre contrôleur d'interface utilisateur, sans cela, votre LiveData perdra son effet Live car il ne pourra pas être observé, essentiellement vos LiveData ne seront pas propagés à l'interface utilisateur.
<data> <variable name="viewModel" type="com.felixfavour.ViewModel" /> </data>
où this
= UI Controller (encore une fois Activity / Fragment)
Je manquais sur le réglage
mViewDataBinding.vm = viewModel
où "vm" est la variable dans la mise en page et "viewModel" est la variable locale dans l'activité ou le fragment
De plus, comme @Menma l'a suggéré, n'oubliez pas d'ajouter
mViewDataBinding.setLifecycleOwner (ceci);