I have problem with observing 3 different lists with live data observer for viewing them in one single recycler view.
This is the scenario: In ListsFragment, I have TabLayout with 3 tabs (WANT, PLAYING, PLAYED) and 1 recycler view. On different tab click I load different lists of games from database and I am presenting them with Live Data observer pattern in the recycler view. Until this moment everything works OK.
The problem occurs when I press one game DELETE button, the database is updated but in the recycler view is loading wrong list and not the list of the selected tab (Probably because there are 3 active observers), so the data on the screen is updated with wrong games.
Gif of the behaviour:
https://gfycat.com/showyembarrassedbarasingha
Can anyone please help me, I tried many solutions but nothing helped and I am stuck more than 1 month.
This is the code.
Fragment:
public class ListsFragment extends Fragment implements VisitedGameInterface {
public static final String TAG = ListsFragment.class.getSimpleName();
private static final int WANT = 0;
private static final int PLAYING = 1;
private static final int PLAYED = 2;
private int selectedTab = WANT;
private GameViewModel gameViewModel;
private GameVisitedAdapter gameAdapter;
private TextView noGamesTV;
public ListsFragment() {
// Required empty public constructor
}
public static ListsFragment newInstance(Bundle bundle) {
ListsFragment fragment = new ListsFragment();
fragment.setArguments(bundle);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_lists, container, false);
TabLayout listsTabLayout = view.findViewById(R.id.lists_tab_layout);
RecyclerView listsRecyclerView = view.findViewById(R.id.lists_recycler_view);
noGamesTV = view.findViewById(R.id.no_games_tv);
listsTabLayout.addTab(listsTabLayout.newTab().setText(getString(R.string.want)), true);
listsTabLayout.addTab(listsTabLayout.newTab().setText(getString(R.string.playing)));
listsTabLayout.addTab(listsTabLayout.newTab().setText(getString(R.string.played)));
listsTabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
listsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), RecyclerView.VERTICAL, false));
listsRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
gameAdapter = new GameVisitedAdapter(getActivity(), this);
listsRecyclerView.setAdapter(gameAdapter);
gameViewModel = ViewModelProviders.of(this).get(GameViewModel.class);
gameViewModel.getWantedGames().observe(this, new Observer<List<Game>>() {
#Override
public void onChanged(List<Game> wantedGames) {
if (wantedGames.size() != 0) {
noGamesTV.setVisibility(View.GONE);
}else {
noGamesTV.setText(R.string.no_wanted_games);
noGamesTV.setVisibility(View.VISIBLE);
}
gameAdapter.setGames(wantedGames);
gameAdapter.notifyDataSetChanged();
}
});
listsTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
if (getActivity() != null && tab.getText() != null) {
if (tab.getText().equals("WANT")) {
selectedTab = tab.getPosition();
gameViewModel.getWantedGames().observe(getActivity(), new Observer<List<Game>>() {
#Override
public void onChanged(List<Game> wantedGames) {
if (wantedGames.size() != 0) {
noGamesTV.setVisibility(View.GONE);
} else {
noGamesTV.setText(R.string.no_wanted_games);
noGamesTV.setVisibility(View.VISIBLE);
}
gameAdapter.setGames(wantedGames);
gameAdapter.notifyDataSetChanged();
}
});
} else if (tab.getText().equals("PLAYING")) {
selectedTab = tab.getPosition();
gameViewModel.getPlayingGames().observe(getActivity(), new Observer<List<Game>>() {
#Override
public void onChanged(List<Game> playingGames) {
if (playingGames.size() != 0) {
noGamesTV.setVisibility(View.GONE);
} else {
noGamesTV.setText(R.string.no_playing_games);
noGamesTV.setVisibility(View.VISIBLE);
}
gameAdapter.setGames(playingGames);
gameAdapter.notifyDataSetChanged();
}
});
} else if (tab.getText().equals("PLAYED")){
selectedTab = tab.getPosition();
gameViewModel.getPlayedGames().observe(getActivity(), new Observer<List<Game>>() {
#Override
public void onChanged(List<Game> playedGames) {
if (playedGames.size() != 0) {
noGamesTV.setVisibility(View.GONE);
} else {
noGamesTV.setText(R.string.no_played_games);
noGamesTV.setVisibility(View.VISIBLE);
}
gameAdapter.setGames(playedGames);
gameAdapter.notifyDataSetChanged();
}
});
}
}
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
return view;
}
#Override
public void onGameDelete(final Game game) {
if (selectedTab == WANT){
game.setWanted(false);
showSnackBar(game, WANT);
} if (selectedTab == PLAYING){
game.setPlaying(false);
showSnackBar(game, PLAYING);
} if (selectedTab == PLAYED){
game.setPlayed(false);
showSnackBar(game, PLAYED);
}
gameViewModel.update(game);
gameAdapter.notifyDataSetChanged();
}
#Override
public void onVisitedGameClick(Game game) {
Intent intent = new Intent(getActivity(), GameActivity.class);
intent.putExtra("game", game);
startActivity(intent);
}
private void showSnackBar(final Game snackGame, final int selectedTab){
Snackbar snackbar = Snackbar.make(Objects.requireNonNull(getView()), snackGame.getName() + " deleted", Snackbar.LENGTH_LONG)
.setAction(R.string.undo, new View.OnClickListener() {
#Override
public void onClick(View view) {
if (selectedTab == WANT) snackGame.setWanted(true);
if (selectedTab == PLAYING) snackGame.setPlaying(true);
if (selectedTab == PLAYED) snackGame.setPlayed(true);
gameViewModel.insert(snackGame);
}
});
snackbar.show();
}
}
XML of ListsFragment
<RelativeLayout
android:id="#+id/lists_layout" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
tools:context=".fragment.ListsFragment">
<com.google.android.material.tabs.TabLayout
android:id="#+id/lists_tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabSelectedTextColor="#color/button_blue"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/lists_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/lists_tab_layout"/>
<TextView
android:id="#+id/no_games_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
tools:text="No games at this moment"
android:textColor="#color/text_black"
android:visibility="invisible"/>
</RelativeLayout>
The adapter:
public class GameVisitedAdapter extends RecyclerView.Adapter<GameVisitedAdapter.GameVisitedViewHolder> {
private Context context;
private LayoutInflater inflater;
private List<Game> games = new ArrayList<>();
private VisitedGameInterface visitedGameInterface;
public GameVisitedAdapter(Context context, VisitedGameInterface visitedGameInterface){
this.context = context;
inflater = LayoutInflater.from(context);
this.visitedGameInterface = visitedGameInterface;
}
public void setGames(List<Game> games){
this.games = games;
}
#NonNull
#Override
public GameVisitedViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.item_game_visited, parent, false);
return new GameVisitedViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull GameVisitedViewHolder holder, int position) {
Game game = games.get(position);
if (game.getCover() != null) {
Glide
.with(context)
.load(context.getString(R.string.cover_url) + game.getCover().getImage_id() + ".jpg")
.centerCrop()
.placeholder(context.getResources().getDrawable(R.drawable.placeholder))
.into(holder.gameCover);
}
holder.gameTitle.setText(game.getName());
SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy");
String dateString = formatter.format((new Date((long) game.getFirst_release_date() * 1000)));
holder.gameYear.setText(dateString);
}
#Override
public int getItemCount() {
return games.size();
}
class GameVisitedViewHolder extends RecyclerView.ViewHolder {
private ImageView gameCover, gameDeleteButton;
private TextView gameTitle, gameYear;
GameVisitedViewHolder(#NonNull View itemView) {
super(itemView);
gameCover = itemView.findViewById(R.id.game_cover);
gameTitle = itemView.findViewById(R.id.game_name);
gameYear = itemView.findViewById(R.id.game_release_year);
gameDeleteButton = itemView.findViewById(R.id.game_delete_button);
gameDeleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
visitedGameInterface.onGameDelete(games.get(getAdapterPosition()));
}
});
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
visitedGameInterface.onVisitedGameClick(games.get(getAdapterPosition()));
}
});
}
}
}
The ViewModel
public class GameViewModel extends AndroidViewModel {
private GameRepository gameRepository;
public GameViewModel(#NonNull Application application) {
super(application);
gameRepository = new GameRepository(application);
}
public void insert(Game game){
gameRepository.insert(game);
}
public void update(Game game){
gameRepository.update(game);
}
public void deleteGame(Game game){
gameRepository.delete(game);
}
public void deleteAll(){
gameRepository.deleteAll();
}
public void DeleteVisitedGames(){ gameRepository.deleteVisitedGames();}
public LiveData<List<Game>> getWantedGames(){
return gameRepository.getWantedGames();
}
public LiveData<List<Game>> getPlayingGames(){
return gameRepository.getPlayingGames();
}
public LiveData<List<Game>> getPlayedGames(){
return gameRepository.getPlayedGames();
}
public LiveData<List<Game>> getVisitedGames(){
return gameRepository.getVisitedGames();
}
public LiveData<List<Game>> getAllGamesFromDB(){
return gameRepository.getAllGamesFromDB();
}
}
The Repository:
public class GameRepository {
private GameDao gameDao;
private LiveData<List<Game>> wantedGames;
private LiveData<List<Game>> playingGames;
private LiveData<List<Game>> playedGames;
private LiveData<List<Game>> visitedGames;
private LiveData<List<Game>> allGamesFromDB;
public GameRepository(Application application){
GameDatabase gameDatabase = GameDatabase.getInstance(application);
gameDao = gameDatabase.gameDao();
wantedGames = gameDao.getWantedGames();
playingGames = gameDao.getPlayingGames();
playedGames = gameDao.getPlayedGames();
visitedGames = gameDao.getVisitedGames();
allGamesFromDB = gameDao.getAllGamesFromDB();
}
public LiveData<List<Game>> getWantedGames(){
return wantedGames;
}
public LiveData<List<Game>> getPlayingGames(){
return playingGames;
}
public LiveData<List<Game>> getPlayedGames(){
return playedGames;
}
public LiveData<List<Game>> getVisitedGames(){
return visitedGames;
}
public LiveData<List<Game>> getAllGamesFromDB(){
return allGamesFromDB;
}
public void insert(Game game){
new InsertAsyncTask(gameDao).execute(game);
}
public void update(Game game){
new UpdateAsyncTask(gameDao).execute(game);
}
public void delete(Game game){
new DeleteItemAsyncTask(gameDao).execute(game);
}
public void deleteAll(){
new DeleteAllAsyncTask(gameDao).execute();
}
public void deleteVisitedGames() {new DeleteVisitedAsyncTask(gameDao).execute();}
//-------------INSERT GAME ASYNC TASK
private static class InsertAsyncTask extends AsyncTask<Game, Void, Void> {
private GameDao asyncDao;
public InsertAsyncTask(GameDao asyncDao){
this.asyncDao = asyncDao;
}
#Override
protected Void doInBackground(Game... games) {
asyncDao.insert(games[0]);
return null;
}
}
//-------------UPDATE GAME ASYNC TASK
private static class UpdateAsyncTask extends AsyncTask<Game, Void, Void> {
private GameDao asyncDao;
public UpdateAsyncTask(GameDao asyncDao){
this.asyncDao = asyncDao;
}
#Override
protected Void doInBackground(Game... games) {
asyncDao.updateGame(games[0]);
return null;
}
}
//----------DELETE GAME ASYNC TASK
private static class DeleteItemAsyncTask extends AsyncTask <Game, Void, Void> {
private GameDao asyncDao;
public DeleteItemAsyncTask(GameDao asyncDao){
this.asyncDao = asyncDao;
}
#Override
protected Void doInBackground(Game... games) {
asyncDao.deleteGame(games[0]);
return null;
}
}
//-------------DELETE ALL ASYNC TASK
private static class DeleteAllAsyncTask extends AsyncTask <Void, Void, Void>{
private GameDao asyncDao;
public DeleteAllAsyncTask(GameDao asyncDao){
this.asyncDao = asyncDao;
}
#Override
protected Void doInBackground(Void... voids) {
asyncDao.deleteAllGames();
return null;
}
}
//-------------DELETE VISITED GAMES ASYNC TASK
private static class DeleteVisitedAsyncTask extends AsyncTask <Void, Void, Void>{
private GameDao asyncDao;
public DeleteVisitedAsyncTask(GameDao asyncDao){
this.asyncDao = asyncDao;
}
#Override
protected Void doInBackground(Void... voids) {
asyncDao.deleteVisitedGames();
return null;
}
}
}
The DAO:
#Dao
public interface GameDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Game game);
#Delete
void deleteGame(Game game);
#Update
void updateGame(Game game);
#Query("DELETE FROM game_table")
void deleteAllGames();
#Query("SELECT * FROM game_table WHERE isWanted")
LiveData<List<Game>> getWantedGames();
#Query("SELECT * FROM game_table WHERE isPlaying")
LiveData<List<Game>> getPlayingGames();
#Query("SELECT * FROM game_table WHERE isPlayed")
LiveData<List<Game>> getPlayedGames();
#Query("SELECT * FROM game_table WHERE isVisited")
LiveData<List<Game>> getVisitedGames();
#Query("SELECT * FROM game_table")
LiveData<List<Game>> getAllGamesFromDB();
#Query("DELETE FROM game_table WHERE isVisited")
void deleteVisitedGames();
}
Database:
#Database(entities = Game.class, version = 8, exportSchema = false)
#TypeConverters({Converters.class})
public abstract class GameDatabase extends RoomDatabase {
public abstract GameDao gameDao();
private static GameDatabase INSTANCE;
public static GameDatabase getInstance(Context context){
if (INSTANCE == null){
synchronized (GameDatabase.class){
if (INSTANCE == null){
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
GameDatabase.class, "game_database")
.fallbackToDestructiveMigration()
.addCallback(sRoomDatabaseCallback)
.build();
}
}
}
return INSTANCE;
}
private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback(){
#Override
public void onOpen(#NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
}
};
}
My 2cents: even after you change tabs, your observers are still active, as you are using the same table for everything and I believe (just glance at the code) you are updating your game entry (e.g: isPlayed set to false) thus it send updates to all active observers thus sending update to the recylerview.
With that in mind, in case I am right here, you can:
Make 3 distinct tables (can be in the same database)
use viewpager to have 3 fragments with 3 diffent recyclers (actually you can use viewpager2 with a viewholder instead of making fragments)
have 3 recyclers (and you do a visibility.Gone every time user changes the tab)
In case I am not right, option 2 e 3 still solve your problem. I hope it helps!
p.s: you could also remove and insert observers everytime users changes tab, I find it to be less straightforward though.
Related
I am trying to get some data from a website and load it into my app.
The app has 1 MainActivity and 3 fragments and uses ViewBinding.
Unfortunately I can not create a instance of viewmodel in the 1st Fragment.
I already searched stackoverflow and the internet (a lot) but I somehow can not get all the solutions given working.
I get the exception on materialViewModel.getMaterials().observe in the HomeFragment.
Any help is highly appreciated.
My HomeFragment:
public class HomeFragment extends Fragment {
private MaterialViewModel materialViewModel;
private FragmentHomeBinding binding;
ArrayList<MaterialModel> posts;
public HomeFragment() {
}
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentHomeBinding.inflate(inflater, container, false);
materialViewModel = new ViewModelProvider(getActivity()).get(MaterialViewModel.class);
initializeRecyclerView();
getPosts();
return binding.getRoot();
}
private void initializeRecyclerView() {
posts = new ArrayList<>();
binding.rvMain.setLayoutManager(new LinearLayoutManager(getActivity()));
}
private void getPosts() {
materialViewModel.getMaterials().observe(getActivity(), new Observer<List<MaterialModel>>() {
#Override
public void onChanged(#Nullable List<MaterialModel> posts) {
binding.rvMain.setAdapter(new ItemAdapter((ArrayList<MaterialModel>) posts));
}
});
getIsLoaded();
}
public void getIsLoaded(){
materialViewModel.getIsLoaded().observe(getActivity(), new Observer<Boolean>() {
#Override
public void onChanged(#Nullable Boolean aBoolean) {
if (aBoolean == true){
//activityMainBinding.progressBarID.setVisibility(View.GONE);
Log.w("PAR-LOADED ", "DATA IS LOADED");
}
}
});
}
#Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}
My MaterialViewmodel:
public class MaterialViewModel extends AndroidViewModel {
private MutableLiveData<List<MaterialModel>> matts;
private MaterialRepository materialRepository;
public MaterialViewModel(Application application) {
super(application);
materialRepository = new MaterialRepository(application);
}
public void init() {
if (this.matts == null) {
matts = materialRepository.getAllMaterials();
}
}
public LiveData<List<MaterialModel>> getMaterials() {
return this.matts;
}
public MutableLiveData<Boolean> getIsLoaded() {
return materialRepository.dataIsLoaded;
}
}
My MaterialRepository:
public class MaterialRepository {
API_Service service;
private String posts;
ArrayList<String> arrayLiNames = new ArrayList<>();
ArrayList<String> arrayLiLinks = new ArrayList<>();
public ArrayList<MaterialModel> materialData = new ArrayList<>();
public MutableLiveData<List<MaterialModel>> mattis;
public MutableLiveData<Boolean> dataIsLoaded;
public MaterialRepository(Application application) {
super();
service = RetrofitClass.getClient(application).create(API_Service.class);
}
public MutableLiveData<List<MaterialModel>> getAllMaterials() {
Call<List<MaterialModel>> postResponseCall = service.getMaterials();
postResponseCall.enqueue(new Callback<List<MaterialModel>>() {
#Override
public void onResponse(Call<List<MaterialModel>> call, Response<List<MaterialModel>> response) {
if (response.code() == 200) {
Log.w("PAR-RESPONSE-CODE ", String.valueOf(response.code()));
posts = String.valueOf(response.body());
//new MyTask().execute();
}
}
#Override
public void onFailure(Call<List<MaterialModel>> call, Throwable t) {
}
});
return mattis;
}
private class MyTask extends AsyncTask<Void, Void, List<MaterialModel>> {
...
#Override
protected List<MaterialModel> doInBackground(Void... params) {
#Override
protected void onPostExecute(List<MaterialModel> result) {
mattis.setValue(result);
dataIsLoaded.setValue(true);
}
}
}
I am using retrofit2 for fetching data from the server and after fetching saving data in room database and then showing in recycler view. But it is no displayed (my data what I get using retrofit). I try display it in my fragment. In file ...data/data/databese/source.db these data are saved. I see it. So, that means that my code works. But I can't understand why it is not displayed.
my database class:
#Database(entities = {Source.class}, exportSchema = false, version = 1)
public abstract class SourceDatabase extends RoomDatabase {
private static final String DB_NAME = "source.db";
public abstract SourceDao sourceDao();
private static SourceDatabase instance;
public static SourceDatabase getInstance(Context context) {
if (instance == null) {
instance =buildDatabaseInstance(context);
}
return instance;
}
private static SourceDatabase buildDatabaseInstance(Context context) {
return Room.databaseBuilder(context,
SourceDatabase.class,
DB_NAME).build();
}
}
repository:
public class DataBaseRepository {
private static DataBaseRepository dataBaseRepository;
private SourceDao sourceDao;
private LiveData<List<Source>> allSourcestoDb;
private Context context;
public static DataBaseRepository getInstance(Context context) {
if (dataBaseRepository == null) {
dataBaseRepository = new DataBaseRepository(context);
}
return dataBaseRepository;
}
public DataBaseRepository(Context context) {
this.context = context;
SourceDatabase db = SourceDatabase.getInstance(context);
sourceDao = db.sourceDao();
allSourcestoDb = sourceDao.getSources();
}
public void getSourceListTodb(String key) {//отправка данных в LiveData
RestClient restClient = RestClient.getInstance();
restClient.startRetrofit();
restClient.getServerApi().getNews(key).enqueue(new Callback<News>() {
#Override
public void onResponse(Call<News> call, Response<News> response) {
Completable.fromAction(new Action (){
#Override
public void run() throws Exception {
if (response.body() != null) {
List<Source> list = response.body().getSources();
sourceDao.insert(list);
}
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onComplete() {
}
#Override
public void onError(Throwable e) {
}
});
}
#Override
public void onFailure(Call<News> call, Throwable t) {
Log.d("error", "Can't parse data " + t);
}
});
}
public LiveData<List<Source>> getAllSourcestoDb() {
return allSourcestoDb;
}
}
dao:
#Dao
public interface SourceDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(List<Source> sources);
#Query("SELECT * FROM source")
LiveData<List<Source>> getSources();
}
viewModel:
public class SourceViewModel extends AndroidViewModel {
private DataBaseRepository dataBaseRepository;
private LiveData<List<Source>> allSources; //for db
public SourceViewModel(#NonNull Application application) {
super(application);
dataBaseRepository =DataBaseRepository.getInstance(application); //for db
allSources = dataBaseRepository.getAllSourcestoDb();
}
public LiveData<List<Source>> getAllSources() {
return allSources;
}
}
and fragment:
public class SavedDataFragment extends Fragment {
private SourceViewModel sourceViewModel;
private DataBaseRepository dataBaseRepository;
private RecyclerView recyclerView;
private List<Source> sourceList;
private SavedDataAdapter adapter;
public SavedDataFragment() {
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.saved_data,container,false);
DataSharedPreference sharedPreference = DataSharedPreference.getSPInstance();
String api_key = sharedPreference.loadText(getActivity());
dataBaseRepository = new DataBaseRepository(getActivity());
sourceViewModel = ViewModelProviders.of(this).get(SourceViewModel.class);
recyclerView = view.findViewById(R.id.recyclerViewSavedFragment);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
sourceList = new ArrayList<>();
adapter = new SavedDataAdapter(getActivity(), sourceList);
recyclerView.setAdapter(adapter);
sourceViewModel.getAllSources().observe(this, new Observer<List<Source>>() {
#Override
public void onChanged(List<Source> sources) {
adapter.setSourceList(sourceList);
}
});
dataBaseRepository.getSourceListTodb(api_key);
return view;
}
}
adapter:
public class SavedDataAdapter extends RecyclerView.Adapter<SavedDataAdapter.SourceSavedViewHolder> {
private LayoutInflater inflater;
private List<Source> sources;
public SavedDataAdapter(Context context, List<Source> sources) {
this.sources = sources;
this.inflater = LayoutInflater.from(context);
}
#NonNull
#Override
public SavedDataAdapter.SourceSavedViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.saved_item, parent, false);
return new SourceSavedViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final SavedDataAdapter.SourceSavedViewHolder holder, int position) {
final Source source = sources.get(position);
holder.sourceId.setText(source.getId());
holder.sourceName.setText(source.getName());
holder.sourceDescription.setText(source.getDescription());
holder.sourceURL.setText(source.getUrl());
holder.sourceCategory.setText(source.getCategory());
holder.sourceLanguage.setText(source.getLanguage());
holder.sourceCountry.setText(source.getCountry());
}
#Override
public int getItemCount() {
return sources.size();
}
public void setSourceList(List<Source> sources) {
this.sources = sources;
notifyDataSetChanged();
}
public static class SourceSavedViewHolder extends RecyclerView.ViewHolder {
TextView sourceName, sourceId, sourceDescription, sourceURL, sourceCategory, sourceLanguage, sourceCountry;
public SourceSavedViewHolder(View view) {
super(view);
sourceName = view.findViewById(R.id.sourceName);
sourceId = view.findViewById(R.id.sourceIdItem);
sourceDescription = view.findViewById(R.id.sourceDescription);
sourceURL = view.findViewById(R.id.sourceURL);
sourceCategory = view.findViewById(R.id.sourceCategory);
sourceLanguage = view.findViewById(R.id.sourceLanguage);
sourceCountry = view.findViewById(R.id.sourceCountry);
}
}
}
In your Fragment inside onChanged,
you're setting adapter.setSourceList(sourceList) where sourceList is an empty arrayList.
You should instead setSourceList to sources which is the updated list passed as an argument to onChanged method
That is :-
sourceViewModel.getAllSources().observe(this, new Observer<List<Source>>() {
#Override
public void onChanged(List<Source> sources) {
adapter.setSourceList(sources); // sources and not sourceList
}
});
Also there are few more things that should be taken care of.
For ex- in your observe method, you have passed this as first argument which is wrong when using Fragments as it may causes memory leaks. Instead you should pass viewLifeOwner..
More can found on this link Use viewLifecycleOwner as the LifecycleOwner
Try ti change this:
#Query("SELECT * FROM source")
To:
#Query("SELECT * FROM Source")
I am writing a simple application that stores 2 string values in a database using Room (I am trying to learn this library). So, I have only one line on my list. Presented for the first time. The rest are not displayed. What is the reason for this behavior?
Model
#Entity
public class Note {
#PrimaryKey(autoGenerate = true)
private long id;
private String title;
private String text;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
NoteDao
#Dao
public interface NoteDao {
#Insert
void insert(Note note);
#Delete
void delete(Note note);
#Query("SELECT * FROM Note")
List<Note> getAllNotes();
}
AppDatabase
#Database(entities = Note.class, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract NoteDao getNoteDao();
}
DataManager
public class DataManager {
private AppDatabase appDatabase;
public DataManager (AppDatabase appDatabase) {
this.appDatabase = appDatabase;
}
public List <Note> getNotes () {
try {
return new GetNotes (). execute (). get ();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace ();
return null;
}
}
public void insertNote (Note note) {
new InsertNote (note) .execute ();
}
public void deleteNote (Note note) {
new DeleteNote (note) .execute ();
}
// Get all notes
public class GetNotes extends AsyncTask <Void, Void, List <Note>> {
#Override
protected List <Note> doInBackground (Void ... voids) {
return appDatabase.getNoteDao (). getAllNotes ();
}
}
// Insert note
public class InsertNote extends AsyncTask <Void, Void, Void> {
private Note note;
InsertNote (Note note) {
this.note = note;
}
#Override
protected Void doInBackground (Void ... voids) {
appDatabase.getNoteDao (). insert (note);
return null;
}
}
// Delete note
public class DeleteNote extends AsyncTask <Void, Void, Void> {
private Note note;
public DeleteNote (Note note) {
this.note = note;
}
#Override
protected Void doInBackground (Void ... voids) {
appDatabase.getNoteDao (). delete (note);
return null;
}
}
}
Mvp
public interface NoteListView extends MvpView {
void showNoteList(List<Note> note);
}
Presenter
public class NoteListPresenter extends MvpPresenter<NoteListView> {
private DataManager dataManager;
public NoteListPresenter(DataManager dataManager) {
this.dataManager = dataManager;
}
public void getNotes(){
getView().showNoteList(dataManager.getNotes());
}
public void deleteNote(Note note) {
dataManager.deleteNote(note);
getView().showNoteList(dataManager.getNotes());
}
}
Adapter
public class NoteAdapter extends RecyclerView.Adapter<NoteAdapter.ViewHolder> {
private List<Note> listNote;
private Context context;
public NoteAdapter(Context context, List<Note> listNote) {
this.listNote = listNote;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.title.setText(listNote.get(position).getTitle());
holder.text.setText(listNote.get(position).getText());
}
#Override
public int getItemCount() {
return listNote.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView title, text;
public ViewHolder(#NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
text = itemView.findViewById(R.id.text);
}
}
}
MainActivity
public class MainActivity extends AppCompatActivity implements NoteListView {
private NoteListPresenter presenter;
private RecyclerView recyclerView;
private NoteAdapter noteAdapter;
private ConstraintLayout constraintLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
constraintLayout = findViewById(R.id.coordinatorMain);
recyclerView = findViewById(R.id.recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
presenter = new NoteListPresenter(App.getDataManager());
presenter.attachView(this);
presenter.getNotes();
}
public void onNextActivity(View view){
startActivity(new Intent(MainActivity.this, AddNoteActivity.class));
}
#Override
public void showNoteList(List<Note> note) {
noteAdapter = new NoteAdapter(this, note);
recyclerView.setAdapter(noteAdapter);
}
#Override
protected void onResume() {
super.onResume();
presenter.getNotes();
}
#Override
public void showMessage(String message) {
Snackbar.make(constraintLayout, message, Snackbar.LENGTH_SHORT).show();
}
}
UPD
SaveNoteView
public interface SaveNoteView extends MvpView {
void insertNote(Note note);
}
SaveNotePresenter
public class SaveNotePresenter extends MvpPresenter<SaveNoteView> {
private DataManager dataManager;
public SaveNotePresenter(DataManager dataManager) {
this.dataManager = dataManager;
}
public void insertNote(Note note){
dataManager.insertNote(note);
getView().insertNote(note);
}
}
AddNoteActivity
public class AddNoteActivity extends AppCompatActivity implements SaveNoteView {
private TextInputEditText title, text;
private ConstraintLayout constraintLayout;
private SaveNotePresenter presenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_note);
constraintLayout = findViewById(R.id.constrainAdd);
title = findViewById(R.id.titleEditText);
text = findViewById(R.id.textEditText);
presenter = new SaveNotePresenter(App.getDataManager());
presenter.attachView(this);
}
//Save a note
public void saveNote(View view){
Note note = new Note();
note.setTitle(title.getText().toString());
note.setText(text.getText().toString());
presenter.insertNote(note);
finish();
}
#Override
public void insertNote(Note note) {
DataManager dataManager = App.getDataManager();
dataManager.insertNote(note);
}
#Override
public void showMessage(String message) {
Snackbar.make(constraintLayout, message, Snackbar.LENGTH_SHORT).show();
}
}
It's pretty likely that there is only 1 id which is beeing replaced the whole time (if this is not the case, check how often insertion is done)
I used Kotlin with Room but in this official example they have a public autogenerated primaryKey, which might be required for Room to access it and autogenerate it. So make the variable public and see if it works
There was no problem. I just specified the parent layout for item_list in full screen. Therefore, the subsequent ones were not visible. Silly mistake:D
I am trying to figure out why the LiveData observer for getAllGoals() does not trigger immediately in the fragment when I update a record. However, the observer is called only after switching to another fragment using the bottom tab navigation and then coming back to the original fragment.
The fragment in question:
MyGoalsFragment.java
public class MyGoalsFragment extends Fragment implements MyGoalsAdapter.MyGoalsCallback {
FragmentMyGoalsBinding myGoalsBinding;
private MyGoalsViewModel myGoalsViewModel;
MyGoalsAdapter myGoalsAdapter;
ConstraintSet smallConstraintSet = new ConstraintSet();
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
myGoalsViewModel = new ViewModelProvider(getActivity(), ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication())).get(MyGoalsViewModel.class);
myGoalsBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_my_goals, container, false);
myGoalsBinding.recyclerView2.setLayoutManager(new LinearLayoutManager(getActivity()));
DrawerLayout drawerLayout = (DrawerLayout) getActivity().findViewById(R.id.drawer_layout);
myGoalsBinding.menu.setOnClickListener(v -> {
drawerLayout.openDrawer(GravityCompat.START);
});
TransitionManager.beginDelayedTransition(myGoalsBinding.recyclerView2);
myGoalsAdapter = new MyGoalsAdapter();
myGoalsAdapter.setCallback(this);
myGoalsAdapter.setContext(getActivity());
myGoalsAdapter.setRecyclerView(myGoalsBinding.recyclerView2);
myGoalsBinding.recyclerView2.setAdapter(myGoalsAdapter);
myGoalsBinding.floatingActionButton.setOnClickListener(v -> {
startActivity(new Intent(getActivity(), CreateGoalActivity.class));
getActivity().finish();
});
enableSwipeToDeleteAndUndo();
myGoalsBinding.recyclerView2.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0 && myGoalsBinding.floatingActionButton.getVisibility() == View.VISIBLE) {
myGoalsBinding.floatingActionButton.hide();
} else if (dy < 0 && myGoalsBinding.floatingActionButton.getVisibility() != View.VISIBLE) {
myGoalsBinding.floatingActionButton.show();
}
}
});
myGoalsViewModel.getAllGoals().observe(getViewLifecycleOwner(), new Observer<List<Goal>>() {
#Override
public void onChanged(List<Goal> goals) {
myGoalsAdapter.submitList(goals); // This observer is not called even after updating a record
}
});
return myGoalsBinding.getRoot();
}
#Override
public void editGoalCallback(Goal goal) {
Intent intent = new Intent(getActivity(), CreateGoalActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("goal", goal);
intent.putExtras(bundle);
startActivity(intent);
}
#Override
public void goalCheckBoxCallback(Goal goal) {
myGoalsViewModel.updateGoal(goal);
}
private void enableSwipeToDeleteAndUndo() {
SwipeToDeleteCallback swipeToDeleteCallback = new SwipeToDeleteCallback(getActivity()) {
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int i) {
if(i==ItemTouchHelper.LEFT) {
Goal tempGoal = myGoalsAdapter.getGoalAt(viewHolder.getAdapterPosition());
myGoalsViewModel.deleteGoal(tempGoal);
Snackbar.make(myGoalsBinding.rootConstraintLayout, "Goal Deleted", Snackbar.LENGTH_LONG)
.setAction("Undo", v -> {
myGoalsViewModel.insertGoal(tempGoal);
})
.setActionTextColor(getActivity().getResources().getColor(R.color.arcticLimeGreen))
.show();
}else if(i==ItemTouchHelper.RIGHT){
Goal tempGoal = myGoalsAdapter.getGoalAt(viewHolder.getAdapterPosition());
if(tempGoal.isCompleted())
tempGoal.setCompleted(false);
else
tempGoal.setCompleted(true);
TransitionManager.beginDelayedTransition(myGoalsBinding.recyclerView2);
myGoalsViewModel.updateGoal(tempGoal); // This is where the update is called
}
}
};
ItemTouchHelper itemTouchhelper = new ItemTouchHelper(swipeToDeleteCallback);
itemTouchhelper.attachToRecyclerView(myGoalsBinding.recyclerView2);
}
}
The MyGoals ViewModel:
public class MyGoalsViewModel extends AndroidViewModel {
private NoteRepository repository;
private LiveData<List<Goal>> allGoals;
public MyGoalsViewModel(#NonNull Application application) {
super(application);
repository = new NoteRepository(application);
allGoals = repository.getAllGoals();
}
public LiveData<List<Goal>> getAllGoals(){
return allGoals;
}
public void deleteGoal(Goal goal){repository.deleteGoal(goal);}
public void insertGoal(Goal goal){repository.insertGoal(goal);}
public void updateGoal(Goal goal){repository.updateGoal(goal);}
}
The Repository:
public class NoteRepository {
private String DB_NAME = "db_task";
Context context;
private GoalDao goalDao;
private LiveData<List<Goal>> allGoals;
private NoteDatabase noteDatabase;
public NoteRepository(Context context) {
noteDatabase = NoteDatabase.getInstance(context);
goalDao = noteDatabase.goalDao();
allGoals = goalDao.getAllGoals();
this.context = context;
}
public void insertGoal(Goal goal){
new InsertGoalAsyncTask(goalDao).execute(goal);
}
public void deleteGoal(Goal goal){
new DeleteGoalAsyncTask(goalDao).execute(goal);
}
public void updateGoal(Goal goal){
new UpdateGoalAsyncTask(goalDao).execute(goal);
}
public void deleteAllGoals(){
new DeleteAllGoalAsyncTask(goalDao).execute();
}
public LiveData<List<Goal>> getAllGoals(){
return allGoals;
}
private static class InsertGoalAsyncTask extends AsyncTask<Goal,Void,Void>{
private GoalDao goalDao;
private InsertGoalAsyncTask(GoalDao goalDao){
this.goalDao = goalDao;
}
#Override
protected Void doInBackground(Goal... goals) {
goalDao.insert(goals[0]);
return null;
}
}
private static class DeleteGoalAsyncTask extends AsyncTask<Goal,Void,Void>{
private GoalDao goalDao;
private DeleteGoalAsyncTask(GoalDao goalDao){
this.goalDao = goalDao;
}
#Override
protected Void doInBackground(Goal... goals) {
goalDao.delete(goals[0]);
return null;
}
}
private static class UpdateGoalAsyncTask extends AsyncTask<Goal,Void,Void>{
private GoalDao goalDao;
private UpdateGoalAsyncTask(GoalDao goalDao){
this.goalDao = goalDao;
}
#Override
protected Void doInBackground(Goal... goals) {
goalDao.update(goals[0]);
return null;
}
}
private static class DeleteAllGoalAsyncTask extends AsyncTask<Void,Void,Void>{
private GoalDao goalDao;
private DeleteAllGoalAsyncTask(GoalDao goalDao){
this.goalDao = goalDao;
}
#Override
protected Void doInBackground(Void... voids) {
goalDao.deleteAllGoals();
return null;
}
}
}
The DAO class:
#Dao
public interface GoalDao {
#Insert
void insert(Goal goal);
#Update
void update(Goal goal);
#Delete
void delete(Goal goal);
#Query("DELETE from goal_table")
void deleteAllGoals();
#Query("Select * from goal_table order by end_date")
LiveData<List<Goal>> getAllGoals();
}
I have this issue in 2 fragments and there are 2 other fragments that do not have this issue with the exact same implementation. Why is the observer not being called as soon as I update a record in MyGoals fragment?
I found the solution, the problem was not in the LiveData code, but in the Recyclerview ListAdapter & DiffUtil Implementation which stopped from triggering LiveData change.
In MyGoalsAdapter I have used DiffUtil & ListAdapter to have smooth animations and increase performance. For it to work properly we need to compare the new list with the old list. The Problem is where the contents of an object were being marked as equal when they were actually different. I solved this by adding a date field in my Model class modifiedAt
and updated the field before that Object was updated. Here is the snippet of code to explain it better.
MyGoalsAdapter:
public class MyGoalsAdapter extends ListAdapter<Goal, MyGoalsAdapter.MyGoalsViewHolder> {
private Context context;
public MyGoalsAdapter() {
super(DIFF_CALLBACK);
}
private static final DiffUtil.ItemCallback<Goal> DIFF_CALLBACK = new DiffUtil.ItemCallback<Goal>() {
#Override
public boolean areItemsTheSame(#NonNull Goal oldItem, #NonNull Goal newItem) {
return oldItem.getId() == newItem.getId();
}
#Override
public boolean areContentsTheSame(#NonNull Goal oldItem, #NonNull Goal newItem) { //Here we check if the objects in the list have changed fields.
boolean id,desc,iscomp,edate,etime,sdate,stime,title, naya, purana, createdAt, modifiedAt;
id = oldItem.getId() == newItem.getId();
desc = oldItem.getDescription().equals(newItem.getDescription());
purana = oldItem.isCompleted();
naya = newItem.isCompleted();
iscomp = purana && naya;
edate = oldItem.getEnd_date().equals(newItem.getEnd_date());
etime = oldItem.getEnd_time().equals(newItem.getEnd_time());
sdate = oldItem.getStart_date().equals(newItem.getStart_date());
stime = oldItem.getStart_time().equals(newItem.getStart_time());
title = oldItem.getTitle().equals(newItem.getTitle());
createdAt = oldItem.getCreatedAt().equals(newItem.getCreatedAt());
modifiedAt = oldItem.getModifiedAt().equals(newItem.getModifiedAt()); //This will return false for the object that is changed
return id &&
desc &&
iscomp &&
edate &&
etime &&
sdate &&
stime &&
title &&
createdAt &&
modifiedAt
;
}
};
}
When I am updating I set the Object modifiedAt field with the current Date and Time.
Goal tempGoal = myGoalsAdapter.getGoalAt(viewHolder.getAdapterPosition()); //Get the object to make change to it
//make change to the object's field
tempGoal.setModifiedAt(Calendar.getInstance().getTime()); //set the modified date with Current date
myGoalsViewModel.updateGoal(tempGoal); //Update the object to the database
Changing the modifiedAt field will tell the Adapter when there is an object that is updated, triggering the animation and showing the updated object in the List, instantly.
I hope this will help someone.
I am trying to update my database using Room persistence Library and Livedata. I am very new to java, so, with the manual and various tutorial, I have setup the DAO, entity etc. But I am still struggling with how to actually add the data.
This is my database defination:
#Entity
public class PlaceSaved {
#PrimaryKey(autoGenerate = true)
private int id;
private String place;
private String lati;
private String longi;
public PlaceSaved(String place, String lati, String longi) {
this.place = place;
this.lati = lati;
this.longi = longi;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
public String getLongi() {
return longi;
}
public void setLongi(String longi) {
this.longi = longi;
}
public String getLati() {
return lati;
}
public void setLati(String lati) {
this.lati = lati;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
DAO
#Dao
public interface DatabaseInterface {
#Query("SELECT * FROM placesaved")
LiveData<List<PlaceSaved>> getAllItems();
#Insert
void insertAll(PlaceSaved... placeSaveds);
#Delete
void delete(PlaceSaved... placeSaveds);
#Update
void update(PlaceSaved... placeSaveds);
}
Adapter
public class PlacesAdapter extends RecyclerView.Adapter<PlacesAdapter.RecyclerViewHolder>{
private List<PlaceSaved> items;
private View.OnClickListener ClickListener;
public PlacesAdapter(List<PlaceSaved> items){//}, View.OnClickListener ClickListener) {
this.items = items;
//this.ClickListener = ClickListener;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new RecyclerViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.places_list_item, parent, false));
}
#Override
public void onBindViewHolder(final RecyclerViewHolder holder, int position) {
PlaceSaved placeSaved = items.get(position);
holder.itemTextView.setText(placeSaved.getPlace());
holder.nameTextView.setText(placeSaved.getLati());
holder.dateTextView.setText(placeSaved.getLongi());
/* holder.dateTextView.setText(borrowModel.getBorrowDate().toLocaleString().substring(0, 11));
holder.itemView.setTag(borrowModel);
holder.itemView.setOnLongClickListener(longClickListener);*/
}
#Override
public int getItemCount() {
return items.size();
}
public void addItems(List<PlaceSaved> items) {
this.items = items;
notifyDataSetChanged();
}
static class RecyclerViewHolder extends RecyclerView.ViewHolder {
private TextView itemTextView;
private TextView nameTextView;
private TextView dateTextView;
RecyclerViewHolder(View view) {
super(view);
itemTextView = (TextView) view.findViewById(R.id.firstLine);
nameTextView = (TextView) view.findViewById(R.id.secondLine);
dateTextView = (TextView) view.findViewById(R.id.longitude);
}
}
}
and the ViewModel
public class PlacesViewModel extends AndroidViewModel {
private final LiveData<List<PlaceSaved>> PlacedatabaseList;
private PlaceDatabase appDatabase;
public PlacesViewModel(Application application) {
super(application);
appDatabase = PlaceDatabase.getDatabase(this.getApplication());
PlacedatabaseList = appDatabase.PlacedatabaseInterface().getAllItems();
}
public LiveData<List<PlaceSaved>> getPlaceList() {
return PlacedatabaseList;
}
public void deleteItem(PlaceSaved placeSaved) {
new deleteAsyncTask(appDatabase).execute(placeSaved);
}
private static class deleteAsyncTask extends AsyncTask<PlaceSaved, Void, Void> {
private PlaceDatabase db;
deleteAsyncTask(PlaceDatabase appDatabase) {
db = appDatabase;
}
#Override
protected Void doInBackground(final PlaceSaved... params) {
db.PlacedatabaseInterface().delete(params[0]);
return null;
}
}
}
Now, I am trying to add an item to database with OnClick of a fab as:
public class PlacesActivity extends AppCompatActivity {
private PlacesViewModel viewModel;
private PlacesAdapter placesAdapter;
private RecyclerView recyclerView;
FloatingActionButton fab, fab1, fab2, fab3;
LinearLayout fabLayout1, fabLayout2, fabLayout3;
boolean isFABOpen = false;
View fabBGLayout;
PlaceDatabase db;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.places_layout);
viewModel = ViewModelProviders.of(this).get(PlacesViewModel.class);
Runnable r =new Runnable() {
#Override
public void run() {
recyclerView = findViewById(R.id.my_recycler_view);
placesAdapter = new PlacesAdapter(new ArrayList<PlaceSaved>());//, this);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplication()));
recyclerView.setAdapter(placesAdapter);
}
};
Thread newThread = new Thread(r);
newThread.start();
fab1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Dialog
/*
Add location manually
*/
AlertDialog.Builder placeLLDialog = new AlertDialog.Builder(PlacesActivity.this);
LayoutInflater inflater = getLayoutInflater();
final View view = inflater.inflate(R.layout.place_add_dialog, null);
placeLLDialog.setView(view);
final EditText todo = view.findViewById(R.id.placeN);
final EditText time = view.findViewById(R.id.placell);
final EditText longi = view.findViewById(R.id.placell2);
placeLLDialog.setTitle("Add Place with Latitude and Longitude")
.setPositiveButton("Add", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
if (!todo.getText().toString().equals("") &&
!time.getText().toString().equals("") &&
!longi.getText().toString().equals("")) {
Snackbar.make(view, "Running", Snackbar.LENGTH_LONG).show();
/* HERE I AM TRYING TO ADD THE DATA, WHICH IS NOT WORKING
final PlaceSaved placeSaved = new PlaceSaved(todo.getText().toString(),
time.getText().toString(), longi.getText().toString());
AsyncTask.execute(new Runnable() {
#Override
public void run() {
db.databaseInterface().insertAll(placeSaved);
items = db.databaseInterface().getAllItems();
runOnUiThread(new Runnable() {
#Override
public void run() {
adapter = new PlacesAdapter(items, db, null);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);
closeFABMenu();
}
});
}
});*/
}
}
})
.setNegativeButton("Cancel", null);
AlertDialog alertDialog = placeLLDialog.create();
alertDialog.show();
alertDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
}
});
since I am very new to java, I can't find out how to add the data to the database, which is inside fab1.setOnClickListner.
I will be grateful if someone kindly helps.
UPDATE
I forgot to add database itself, here it is:
#Database(entities = {PlaceSaved.class},version = 1)
public abstract class PlaceDatabase extends RoomDatabase {
private static PlaceDatabase INSTANCE;
public static PlaceDatabase getDatabase(Context context){
if (INSTANCE == null){
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), PlaceDatabase.class,
"places_db").build();
}
return INSTANCE;
}
public abstract DatabaseInterface PlacedatabaseInterface();
Create Class AddBorrowViewModel
public class AddBorrowViewModel extends AndroidViewModel
{
private PlaceDatabase appDatabase;
public AddBorrowViewModel(#NonNull Application application) {
super(application);
appDatabase = PlaceDatabase.getDatabase(this.getApplication());
}
public void addBorrow(PlaceSaved placedSaved)
{
new addAsyncTask(appDatabase).execute(placedSaved);
}
private class addAsyncTask extends AsyncTask<PlaceSaved , Void, Void>
{
private PlaceDatabase appDatabase_;
addAsyncTask(PlaceDatabase appDatabase)
{
appDatabase_ = appDatabase;
}
#Override
protected Void doInBackground(PlaceSaved... placedSaved) {
appDatabase_.itemAndPersonModel().addBorrow(placedSaved[0]);
return null;
}
}
}
add this variable in your PlacesActivity
private AddBorrowViewModel addBorrowViewModel;
in OnCreate add this
addBorrowViewModel = ViewModelProviders.of(this).get(AddBorrowViewModel.class);
in onClickListener Of alertDilaog after snackbar
addBorrowViewModel.addBorrow(new PlaceSaved(
todo.getText().toString(),
time.getText().toString(), longi.getText().toString()
));
In your PlaceDatabase add
public abstract Dao itemAndPersonModel();