Data not displaying through ViewModel - java

I am newbie to android development and not able to understand why the data is being not displayed. initially the lists are empty so it should show empty text view but it is not showing that also.
Here's the code
Viewmodel factory
public class ViewModelFactoryListItFragment implements ViewModelProvider.Factory {
String category;
Application application;
public ViewModelFactoryListItFragment(Application application,String category ) {
this.category = category;
this.application = application;
}
#NonNull
#Override
public <T extends ViewModel> T create(#NonNull Class<T> aClass) {
if (aClass.isAssignableFrom(ViewModelListItFragment.class)) {
return (T) new ViewModelListItFragment(application, category);
} else throw new IllegalArgumentException("Viewmodel not found");
}
}
ViewModel
public class ViewModelListItFragment extends ViewModel {
private AppDatabase mDb;
private LiveData<List<ListItEntry>> myEntries;
private Application mApplication;
private String mCategory;
public ViewModelListItFragment(#NonNull Application application, String category) {
this.mCategory = category;
this.mApplication = application;
mDb = AppDatabase.getInstance(mApplication);
myEntries = mDb.listItDao().getListItsByCategory(mCategory);
}
public LiveData<List<ListItEntry>> getMyEntries() {
return myEntries;
}
}
Fragment
public class ListItFragment extends Fragment {
private FragmentListItBinding mBinding;
private ViewModelListItFragment mViewModel;
private String mCategory;
public ListItFragment(String category) {
super();
this.mCategory = category;
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
Timber.i("List it fragment created");
mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_list_it, container, false);
ViewModelFactoryListItFragment factoryListItFragment = new ViewModelFactoryListItFragment(this.getActivity().getApplication(), mCategory);
mViewModel = new ViewModelProvider(this, factoryListItFragment).get(ViewModelListItFragment.class);
LiveData<List<ListItEntry>> entries = mViewModel.getMyEntries();
entries.observe(this.getViewLifecycleOwner(), listItEntries -> {
if(listItEntries == null || listItEntries.size() == 0){
mBinding.textEmpty.setVisibility(View.VISIBLE);
mBinding.recyclerView.setVisibility(View.INVISIBLE);
}
mBinding.textEmpty.setVisibility(View.INVISIBLE);
mBinding.recyclerView.setVisibility(View.VISIBLE);
});
return mBinding.getRoot();
}
I have not yet implemented recylerview adapter so it will not show existing data but when the entries are not there then also it is not showing empty textView.

entries.observe(this.getViewLifecycleOwner(), listItEntries -> {
if(listItEntries == null || listItEntries.size() == 0){
mBinding.textEmpty.setVisibility(View.VISIBLE);
mBinding.recyclerView.setVisibility(View.INVISIBLE);
} else {
mBinding.textEmpty.setVisibility(View.INVISIBLE);
mBinding.recyclerView.setVisibility(View.VISIBLE);
}
});
Your code is outside if part thus even though your condition is met the part outside your if is being executed. Add an else part to make sure that it doesn't get executed as shown above

Related

UI not updated when using SavedStateHandle

Following android's architecture guide, I am experimenting with SavedStateHandle in my view model. So when I post any changes from a thread to the view model, it doesn't reflect on UI. However, without SavedStateHandle the UI changes reflect just fine.
public class UserViewModel extends ViewModel {
UserRepository userRepository;
private static final String USER_KEY = "user_key";
private SavedStateHandle mState;
public UserViewModel(SavedStateHandle savedStateHandle) {
mState = savedStateHandle;
this.userRepository = new UserRepository();
}
public LiveData<String> getUserId() {
return mState.getLiveData(USER_KEY, userRepository.getUserId());
}
public void setUserId(String value) {
mState.set(USER_KEY, value);
}
}
public class UserFragment extends Fragment {
private UserViewModel mViewModel;
public static UserFragment newInstance() {
return new UserFragment();
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.user_fragment, container, false);
}
#Override
public void onViewCreated(#NonNull #NotNull View view, #Nullable #org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mViewModel = new ViewModelProvider(requireActivity()).get(UserViewModel.class);
mViewModel.getUserId().observe(getViewLifecycleOwner(), s -> {
((TextView) view.findViewById(R.id.text_view_1)).setText(s);
});
Executors.newCachedThreadPool().submit(() -> {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
mViewModel.setUserId("111111");
});
}
public UserViewModel getmViewModel() {
return mViewModel;
}
}
Main Activity
my view only has one framelayout with id sample_fragment
public class MainActivity extends AppCompatActivity {
private final ExecutorService executorService = Executors.newCachedThreadPool();
private UserViewModel userViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
userViewModel = new ViewModelProvider(this).get(UserViewModel.class);
if (savedInstanceState == null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
UserFragment userFragment = new UserFragment();
transaction.replace(R.id.sample_fragment, userFragment);
transaction.commit();
executorService.submit(() -> {
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
userViewModel.setUserId("1");
});
}
}
}
with this code, the changes don't reflect on UI. however when I replace the SaveStateHandle with MutableLiveData then a simple postValue changes the screen just fine. From what I have read, it seems the live data is changed only when the lifecycle is in some specific states (like CREATED).
You set a default value in your getUserId, but I don't see where you use postValue on the data in SavedStateHandle.
I would add a mUserId member and move the code in getUserId to the ViewModel constructor to make sure it's initialized before any write to it. Then make set and post methods:
LiveData<String> mUserId;
public UserViewModel(SavedStateHandle savedStateHandle) {
mState = savedStateHandle;
this.userRepository = new UserRepository();
mUserId = mState.getLiveData(USER_KEY, userRepository.getUserId());
}
public LiveData<String> getUserId() {
return mUserId;
}
public void setUserId(String value) {
mState.getLiveData(USER_KEY).setValue(value);
}
public void postUserId(String value) {
mState.getLiveData(USER_KEY).postValue(value);
}

How to make RecyclerView Multiple ViewTypes With Retrofit and ViewModel

Recently I have created RecyclerView with Multiple ViewTypes followed this video. In the video the lecturer followed the traditional method of sending data using ArrayList In MainAvtivity. But when I used ViewModel and Retrofit it is not passing any data and nothing show in the screen.
And here an expiation of what I have done.
First:
I have 3 diffrents types of views so I created a 3 model classes for each view called (FirstImageModel,LiveModel,DailyImageModel).
FirstImageModel class -- All other 2 classes have same stretcher.
public class FirstImageModel {
#SerializedName("firstImageUrl")
private String firstImageUrl;
public FirstImageModel(String firstImageUrl) {
this.firstImageUrl = firstImageUrl;
}
public String getFirstImageUrl() {
return firstImageUrl;
}
public void setFirstImageUrl(String firstImageUrl) {
this.firstImageUrl = firstImageUrl;
}
and I have created a fourth class called ItemModel that have type int and Object object.
public class ItemModel {
private int type;
private Object object;
public ItemModel(int type) {
this.type = type;
this.object = object;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
}
Second:
I have created Adapter class called HomeAdapter that extends from RecyclerView and I made 3 classes for eatch view inside the same class HomeAdapter.
public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<ItemModel> items;
public HomeAdapter(List<ItemModel> items) {
this.items = items;
}
public void setHomeList(List<ItemModel> items) {
this.items = items;
notifyDataSetChanged();
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
// Here is types are: 0-FirstImage, 1-Live, 2-DailyImage
if (viewType == 0) {
return new FirstImageViewHolder(
LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_home_container_firstimage,
parent,
false
)
);
} else if (viewType == 1) {
return new LiveViewHolder(
LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_home_container_live,
parent,
false
)
);
} else {
return new DailyImageViewHolder(
LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_home_container_dailyimage,
parent,
false
)
);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == 0) {
FirstImageModel firstImageModel = (FirstImageModel) items.get(position).getObject();
((FirstImageViewHolder) holder).setFirstImageData(firstImageModel);
} else if (getItemViewType(position) == 1) {
LiveModel liveModel = (LiveModel) items.get(position).getObject();
((LiveViewHolder) holder).setLiveImageData(liveModel);
} else {
DailyImageModel dailyImageModel = (DailyImageModel) items.get(position).getObject();
((DailyImageViewHolder) holder).setDailyImageData(dailyImageModel);
}
}
#Override
public int getItemCount() {
if(this.items != null) {
return this.items.size();
}
return 0;
}
#Override
public int getItemViewType(int position) {
return items.get(position).getType();
}
/* firstImage Adapter */
static class FirstImageViewHolder extends RecyclerView.ViewHolder {
private ImageView firstImage;
FirstImageViewHolder(#NonNull View itemView) {
super(itemView);
firstImage = itemView.findViewById(R.id.image_home_firstImage);
}
void setFirstImageData(FirstImageModel firstImageModel) {
Glide.with(itemView.getContext())
.load(firstImageModel.getFirstImageUrl())
.into(firstImage);
}
}
/* Live Adapter */
static class LiveViewHolder extends RecyclerView.ViewHolder {
private ImageView liveImage;
LiveViewHolder(#NonNull View itemView) {
super(itemView);
liveImage = itemView.findViewById(R.id.image_home_liveImage);
}
void setLiveImageData(LiveModel liveModel) {
Glide.with(itemView.getContext())
.load(liveModel.getImageLiveInfoUrl())
.into(liveImage);
}
}
/* DailyImage Adapter */
static class DailyImageViewHolder extends RecyclerView.ViewHolder {
private ImageView dailyImage;
DailyImageViewHolder(#NonNull View itemView) {
super(itemView);
dailyImage = itemView.findViewById(R.id.image_home_dailyImage);
}
void setDailyImageData(DailyImageModel dailyImageModel) {
Glide.with(itemView.getContext())
.load(dailyImageModel.getDailyImageUrl())
.into(dailyImage);
}
}
My Problem:
When I use Retrofit to load the data, I don't Know how to pass the 3 views types data to the RecyclerView using ViewModel. My ViewModel class.
public class HomeViewModel extends ViewModel {
private MutableLiveData<List<ItemModel>> homeObjectsList;
private Call<List<ItemModel>> call;
public HomeViewModel(){
homeObjectsList = new MutableLiveData<>();
}
public MutableLiveData<List<ItemModel>> getHomeItemsListObserver() {
return homeObjectsList;
}
public void makeApiCallHome() {
APIServiceHome apiServiceHome = RetroInstanceHome.getRetroClientHome().create(APIServiceHome.class);
call = apiServiceHome.getHomeObjectsList();
call.enqueue(new Callback<List<ItemModel>>() {
#Override
public void onResponse(Call<List<ItemModel>> call, Response<List<ItemModel>> response) {
homeObjectsList.postValue(response.body());
}
#Override
public void onFailure(Call<List<ItemModel>> call, Throwable t) {
homeObjectsList.postValue(null);
}
});
}
Also here's my fragment that should dislay the data in RecyclerView.
public class HomeFragment extends Fragment {
View rootView;
RecyclerView recyclerView;
private List<ItemModel> itemModelList;
private HomeViewModel viewModel;
private HomeAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_home, container, false);
initializeContent();
initializeViewModel();
return rootView;
}
private void initializeContent() {
recyclerView = rootView.findViewById(R.id.recyclerView_home);
recyclerView.setAdapter(new HomeAdapter(itemModelList));
}
private void initializeViewModel() {
ProgressBar progressBar = rootView.findViewById(R.id.progress_bar_home);
viewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
viewModel.getHomeItemsListObserver().observe(getActivity(), new Observer<List<ItemModel>>() {
#Override
public void onChanged(List<ItemModel> itemModels) {
if(itemModels != null) {
progressBar.setVisibility(View.GONE);
itemModelList = itemModels;
adapter.setHomeList(itemModels);
}
}
});
viewModel.makeApiCallHome();
}
I hope this explanation was clear to show the problem. Waiting for your answer

getValue() returning null from ViewModel (Java Android)

I have been struggling with one bug for a week now. I am a beginner android developer and I am trying to build MVVM app. The idea is to be gaming news but that does not really matter. Here are my 3 classes that are key to this bug.
My NewsFragment class:
FragmentNewsBinding binding;
NewsFragmentAdapter adapter;
Context context;
public NewsFragmentViewModel newsFragmentViewModel;
public NewsFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
newsFragmentViewModel = new ViewModelProvider(this).get(NewsFragmentViewModel.class);
// Inflating the layout for this fragment
binding = FragmentNewsBinding.inflate(inflater, container, false);
newsFragmentViewModel.init();
setAdapter(container);
observeChanges();
return binding.getRoot();
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
private void setAdapter(ViewGroup container) {
context = container.getContext();
adapter = new NewsFragmentAdapter(newsFragmentViewModel.getItems().getValue(), context);
RecyclerView.LayoutManager linearLayoutManager = new LinearLayoutManager(context);
binding.recyclerViewNews.setLayoutManager(linearLayoutManager);
binding.recyclerViewNews.setAdapter(adapter);
}
public void observeChanges() {
newsFragmentViewModel.getItems().observe(getViewLifecycleOwner(), new Observer<List<Item>>() {
#Override
public void onChanged(List<Item> items) {
adapter.notifyDataSetChanged();
}
});
}
}
NewsFragmentViewModel class:
public class NewsFragmentViewModel extends ViewModel {
private MutableLiveData<List<Item>> mItems;
private NewsRepository mRepo;
// Empty constructor
public NewsFragmentViewModel() {
}
public void init() {
if (mItems != null) {
return;
}
mRepo = NewsRepository.getInstance();
mItems = mRepo.getItems();
}
public LiveData<List<Item>> getItems() {
return mItems;
}
}
And the repository class:
public class NewsRepository {
MutableLiveData<List<Item>> mItems;
private static NewsRepository instance;
public static NewsRepository getInstance() {
if (instance == null) {
instance = new NewsRepository();
}
return instance;
}
//Empty constructor
private NewsRepository() {
}
public MutableLiveData<List<Item>> getItems() {
mItems = new MutableLiveData<>();
ServiceApi.getInstance().getGamezoneMethods().getGamezoneNews().enqueue(new Callback<Rss>() {
#Override
public void onResponse(Call<Rss> call, Response<Rss> response) {
if (response.code() == 200) {
List<Item> items = response.body().getChannel().getItems();
mItems.postValue(items);
}
}
#Override
public void onFailure(Call<Rss> call, Throwable t) {
Log.d("Failed", "Error");
mItems.postValue(null);
}
});
return mItems;
}
}
Now, the main problem with this code is that in the repository when I do my request I successfully get the data and I think, I successfully push the data to the viewmodel. But when I try to get my data from the LiveData in the viewmodel class or in the fragment class I always get null, and because of the null problem I cannot set up an adapter properly and I cannot set up my onChanged() method. I am trying to get the data in the fragment with the classic getValue() method. Please somebody help me because I am losing my mind.
If you are confused with this code, here is link to my github repo.

How to pass data from activity or fragment to viewmodel?

I am creating a project in which i am using themoviedb api to fetch data. For this I am using MVVM architecture. From MovieListFragment , I want to pass category such as popular, top_rated to MovieViewModel for filtering the movies accordingly , but there i am getting null value.
Here is MovieListFragment class :-
public class MovieListFragment extends Fragment {
private MovieViewModel movieViewModel;
private static final String BASE_URL = "https://api.themoviedb.org";
private static final String API_KEY = "API_KEY";
private String category;
private GridView gridView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_movie_list, container, false);
gridView = rootView.findViewById(R.id.images_grid_view);
movieViewModel = ViewModelProviders.of(this).get(MovieViewModel.class);
movieViewModel.setCategory(category); // from here i am passing value
movieViewModel.getMoviesRepository().observe(getActivity(), new Observer<MovieResults>() { // error line no :- 76
#Override
public void onChanged(MovieResults movieResults) {
final List<MovieResults.ResultsBean> listOfMovies = movieResults.getResults(); // error line no :- 79
MovieListAdapter mAdapter = new MovieListAdapter(getContext(), listOfMovies);
gridView.setAdapter(mAdapter);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mCallback.onImageSelected(position, listOfMovies);
}
});
}
});
return rootView;
}
public void setCategory(String category) {
this.category = category;
}
}
Here is MovieViewModel class :-
public class MovieViewModel extends AndroidViewModel {
private String category;
private static final String API_KEY = "api_key";
private MovieRepository repository;
private MutableLiveData<MovieResults> listOfMovies;
public MovieViewModel(#NonNull Application application) {
super(application);
Log.d("MovieViewModel", category); // but here i am getting null value
listOfMovies = repository.getListOfMovies(category, API_KEY);
}
public MutableLiveData<MovieResults> getMoviesRepository() {
return listOfMovies;
}
public void setCategory(String category) {
this.category = category;
}
}
I am getting error like this :-
java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List com.mountblue.moviesapp.entity.MovieResults.getResults()' on a null object reference
at com.mountblue.moviesapp.fragment.MovieListFragment$2.onChanged(MovieListFragment.java:79)
at com.mountblue.moviesapp.fragment.MovieListFragment$2.onChanged(MovieListFragment.java:76)
Since the Category is read by the constructor of MovieViewModel before the setter, it is always null.
What about category as method arguments?
public class MovieViewModel extends AndroidViewModel {
private static final String API_KEY = "api_key";
private MovieRepository repository;
private MutableLiveData<MovieResults> listOfMovies = new MutableLiveData<MovieResults>();
public MovieViewModel(#NonNull Application application) {
super(application);
}
public MutableLiveData<MovieResults> getMoviesRepository(category) {
loadData(category);
return listOfMovies;
}
private void loadData(category) {
// Do an asynchronous operation to fetch MovieResults.
repository.getListOfMovies(category, API_KEY);
...
// Receive asynchronous result in callback
// Post the result after getting the asynchronous result.
listOfMovies.postValue(response)
}
}
For a more detailed implementation, need a repository class.
Documents:
https://developer.android.com/topic/libraries/architecture/viewmodel
If you are getting null value for the string category in line movieViewModel.setCategory(category);, it means the field category of MovieListFragment is null.
Try checking if you have invoked the setCategory(String category) method on the fragment.
If that's not the case, please elaborate on the error. E.g. on which line it occurs etc.
In MovieListFragment class:
First delete this line: movieViewModel.setCategory(category);
And pass "category" here: movieViewModel.getMoviesRepository(category)
like code below:
movieViewModel.getMoviesRepository(category).observe(getActivity(), new Observer<MovieResults>() { // error line no :- 76
#Override
public void onChanged(MovieResults movieResults) {
final List<MovieResults.ResultsBean> listOfMovies = movieResults.getResults(); // error line no :- 79
MovieListAdapter mAdapter = new MovieListAdapter(getContext(), listOfMovies);
gridView.setAdapter(mAdapter);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mCallback.onImageSelected(position, listOfMovies);
}
});
}
});
In MovieViewModel class:
Move this line inside getMoviesRepository(String category) listOfMovies = repository.getListOfMovies(category, API_KEY);
And just remove category variable and setCategory() method from MovieViewModel class like this:
public class MovieViewModel extends AndroidViewModel {
private static final String API_KEY = "api_key";
private MovieRepository repository;
private MutableLiveData<MovieResults> listOfMovies;
public MovieViewModel(#NonNull Application application) {
super(application);
}
public MutableLiveData<MovieResults> getMoviesRepository(String category) {
Log.d("MovieViewModel", category); // but here i am getting null value
listOfMovies = repository.getListOfMovies(category, API_KEY);
return listOfMovies;
}
}

Using LiveData to manipulate data in RecyclerView from inside a Fragment

I have a RecyclerView in a Fragment where I would like to populate data using MutableLiveData. I have a mock DAO that returns a list of objects of my Model class. The RecyclerView is blank when executed.
This is my mock DAO class:
public class DaoMockFriends implements DaoFriendsInterface {
private ArrayList<FriendsModel> friendsModelsArrayList;
public DaoMockFriends() {
friendsModelsArrayList = new ArrayList<>();
}
#SuppressLint("NewApi")
#Override
public List<FriendsModel> getFriendsList() {
for(int i = 0 ; i < 10 ; i++){
FriendsModel friendsModel = (new FriendsModel("adasdsada"+i,"sdadsadsa"+(i*2),"adsdsadssad"+(i*3),""+(i++), LocalDateTime.now()));
friendsModelsArrayList.add(friendsModel);
}
return friendsModelsArrayList;
}
}
This is my ViewModel class:
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;
import java.util.List;
public class FriendsListLiveDataProvider extends ViewModel {
private MutableLiveData<List<FriendsModel>> friendsModelLiveData = new MutableLiveData<>();
public LiveData<List<FriendsModel>> getFriendsModelLiveData() {
if(this.friendsModelLiveData == null) friendsModelLiveData.postValue(new DaoMockFriends().getFriendsList());
return this.friendsModelLiveData;
}
}
This is my RecyclerViewAdapter class:
public class AdapterFriendsListRecyclerView extends RecyclerView.Adapter<AdapterFriendsListRecyclerView.ViewHolder> {
private List<FriendsModel> listOfFriends;
public AdapterFriendsListRecyclerView(List<FriendsModel> listOfFriends) {
this.listOfFriends = listOfFriends;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.friend_entiry_block,parent,false));
}
#SuppressLint("SetTextI18n")
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
FriendsModel friendsInterface = this.listOfFriends.get(position);
String firstName = friendsInterface.getFirstName();
String lastName = friendsInterface.getLastName();
holder.getTextView().setText(firstName+" "+lastName);
}
#Override
public int getItemCount() {
return listOfFriends.size();
}
public void addItems(List<FriendsModel> friendsInterface){
this.listOfFriends = friendsInterface;
notifyDataSetChanged();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private TextView textView;
public ViewHolder(View itemView) {
super(itemView);
this.textView = itemView.findViewById(R.id.friendEntityNameTV);
}
public TextView getTextView() {
return textView;
}
}
}
This is the implementation in the Fragment :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_friends_list, container, false);
friendsListRV = v.findViewById(R.id.FriendsListRecyclerView);
adapterFriendsListRecyclerView = new AdapterFriendsListRecyclerView(new ArrayList<>());
friendsListRV.setLayoutManager(new LinearLayoutManager(getActivity()));
friendsListRV.setAdapter(adapterFriendsListRecyclerView);
friendsListLiveDataProvider = ViewModelProviders.of(this).get(FriendsListLiveDataProvider.class);
friendsListLiveDataProvider
.getFriendsModelLiveData()
.observe(this, (friendsModels) -> adapterFriendsListRecyclerView
.addItems(friendsModels));
return v;
}
I think that somehow the data from the DAO isn't getting across to the RecyclerViewAdapter. I followed this blog.
How to make the data from the DAO visible in the RecyclerView using LiveData
EDIT:
I changed my ViewModel class as per Yogesh's answer. But my app terminates abruptly without any error or warning messages. When I debug, I found that my app crashes on execution of this line: friendsModelLiveData.postValue(new DaoMockFriends().getFriendsList());
EDIT2:
I tried with the code below in my ViewModel implementation class
public LiveData<List<FriendsModel>> getFriendsModelLiveData() {
if(friendsModelLiveData == null){
friendsModelLiveData = new MutableLiveData<>();
}
loadData();
return this.friendsModelLiveData;
}
private void loadData(){
DaoMockFriends anInterface = new DaoMockFriends();
ArrayList<FriendsModel> fm = anInterface.getFriendsList();
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Runnable() {
#Override
public void run() {
friendsModelLiveData.postValue(fm);
}
});
}
The app abruptly terminates at this ArrayList<FriendsModel> fm = anInterface.getFriendsList(); line. I followed this thread to come up with this type of approach.
Method new DaoMockFriends().getFriendsList() never gets executed, because you have initialized friendsModelLiveData at declaration.
Update:
public class FriendsListLiveDataProvider extends ViewModel {
private MutableLiveData<List<FriendsModel>> friendsModelLiveData;
public LiveData<List<FriendsModel>> getFriendsModelLiveData() {
if(this.friendsModelLiveData == null) {
friendsModelLiveData = new MutableLiveData<>();
friendsModelLiveData.postValue(new DaoMockFriends().getFriendsList());
}
return this.friendsModelLiveData;
}
}

Categories

Resources