1

1. Entity (table) CurrentyEntity.java

@Entity(tableName = "Corona")
public class CurrentyEntity {

@PrimaryKey(autoGenerate = true)
private int id;


public int getId() {
    return this.id;
}

public void setId(int id) {
    this.id = id;
}

@NonNull
@ColumnInfo (name = "country")
private  String country;

@NonNull
public String getCountry() {
    return this.country;
}




@ColumnInfo (name = "infections_count")
private  int infections_count;

public int getInfections_count() {
    return this.infections_count;
}




public CurrentyEntity (@NonNull String country, int infections_count){

    this.country = country;
    this.infections_count = infections_count;


}

@Ignore
public CurrentyEntity (int id, String country , int infections_count){

    this.id = id;
    this.country = country;
    this.infections_count = infections_count;


}
}

2. Dao PlayerDao.class

import java.util.List;

@Dao
public interface PlayerDao {

@Insert(onConflict = OnConflictStrategy.IGNORE)
void insert(CurrentyEntity player);

@Update
void update(CurrentyEntity...players);

// how to delete a column value for a row
@Delete
void delete(CurrentyEntity player);

// how to return a specific row ??
@Query("SELECT * FROM Corona ORDER BY infections_count ASC ")
LiveData<List<CurrentyEntity>> returnRowLowToHigh();

@Query("SELECT COUNT(*) FROM Corona")
Integer getRowCount();

}

3. Room Database RoomDB.class

@Database(entities = {CurrentyEntity.class}, version = 2, exportSchema = false)
public abstract class RoomDB extends RoomDatabase {

public abstract PlayerDao PlayerDao();

private static RoomDB INSTANCE;

public static RoomDB getINSTANCE(final Context context){
    if (INSTANCE == null)
    {
       synchronized (RoomDB.class)
           {

             if (INSTANCE == null)
                {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(), RoomDB.class,"pumpin_DataBase")
                            // Wipes and rebuilds instead of migrating
                            // if no Migration object.
                            // Migration is not part of this practical.
                            .fallbackToDestructiveMigration()
                            .addCallback(afterOpeningRoomDB)
                            .build();


                }


           }

       }
    return INSTANCE;
    }

    // // the only 2 callback methods
    //    //void    onCreate(SupportSQLiteDatabase db)
    //    //Called when the database is created for the first time.
    //    //
    //    //void    onOpen(SupportSQLiteDatabase db)
    //    //Called when the database has been opened.

    private static RoomDatabase.Callback afterOpeningRoomDB = new RoomDatabase.Callback(){

        @Override
        public void onOpen(@NonNull SupportSQLiteDatabase db) {
            super.onOpen(db);
            new LaunchAsyncTask(INSTANCE).execute();
        }
    };



 private static class LaunchAsyncTask extends AsyncTask<Void,Void,Void>{

     private final PlayerDao DAO;


     public LaunchAsyncTask(RoomDB db){

         DAO = db.PlayerDao();


     }

     @Override
     protected Void doInBackground(final Void... voids) {

         DAO.insert(new CurrentyEntity("jordan",3434));


         return null;
     }
 }

}

4. Repository AllRepository.class

public class AllRepository {

private PlayerDao playerDao;
private LiveData<List<CurrentyEntity>> rowList;

private   static  String rowCount;



 AllRepository(Application application){

    RoomDB roomdb = RoomDB.getINSTANCE(application);
    playerDao = roomdb.PlayerDao();
    rowList = playerDao.returnRowLowToHigh();
}

LiveData<List<CurrentyEntity>> returnRowList () {return rowList;}

public void RemoveRow(CurrentyEntity row){ new removeRow(playerDao).execute(row);}

public void AddRow(CurrentyEntity row)  { new addRow(playerDao).execute(row);}

public void UpdateRow(CurrentyEntity row){ new updateRow(playerDao).execute(row);}

public String getRowCount(){ new getRowCount(playerDao).execute();
return rowCount; }



private static class removeRow extends AsyncTask<CurrentyEntity,Void,Void> {

    private PlayerDao removePlayerDao;
    public removeRow(PlayerDao currentDao){
      removePlayerDao = currentDao;
  }
    @Override
    protected Void doInBackground(CurrentyEntity... players) {
        removePlayerDao.delete(players[0]);
        return null;
    }
}

private static class addRow extends AsyncTask<CurrentyEntity,Void,Void> {

    private PlayerDao addPlayerDao;



    public addRow(PlayerDao currentDao){

        addPlayerDao = currentDao;
    }
    @Override
    protected Void doInBackground(CurrentyEntity... players) {
        addPlayerDao.insert(players[0]);
        return null;
    }
}

private static class updateRow extends AsyncTask<CurrentyEntity,Void,Void> {

    private PlayerDao updatePlayerDao;
    public updateRow(PlayerDao currentDao){
          updatePlayerDao = currentDao;
    }
    @Override
    protected Void doInBackground(CurrentyEntity... players) {
        updatePlayerDao.update(players[0]);
        return null;
    }
}





private static class getRowCount extends AsyncTask<CurrentyEntity,Void,Void> {

    private PlayerDao addPlayerDao;


    public getRowCount(PlayerDao currentDao){

        addPlayerDao = currentDao;
    }




    @Override
    protected Void doInBackground(CurrentyEntity... players) {
        rowCount = String.valueOf(addPlayerDao.getRowCount());
        return null;
    }


    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
    }
}

**5. ViewModel AllViewModel.class **

public class AllViewModel extends AndroidViewModel {

private AllRepository allRepository;
private LiveData<List<CurrentyEntity>> rowList;

public AllViewModel( Application application) {
    super(application);
    allRepository = new AllRepository(application);
    rowList = allRepository.returnRowList();

}

LiveData<List<CurrentyEntity>> returnRowList(){ return  rowList;}

public void removeRow(CurrentyEntity row){ allRepository.RemoveRow(row);}
public void addRow(CurrentyEntity row){ allRepository.AddRow(row);}
public void updateRow(CurrentyEntity row){ allRepository.UpdateRow(row);}
public String getRowCount(){ return allRepository.getRowCount();}

}

6. RecyclerView Adapter MenWomenRecycler.class

public class MenWomenRecycler extends RecyclerView.Adapter<MenWomenRecycler.MenWomenViewHolder> {

private final LayoutInflater mInflater;
private List<CurrentyEntity> listOfCases;


MenWomenRecycler(Context context) {

    mInflater = LayoutInflater.from(context);
}

public void setList(List<CurrentyEntity> incomingList ){

        listOfCases = incomingList;
        notifyDataSetChanged();

}





@NonNull
@Override
public MenWomenViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

    View itemView = mInflater.inflate(R.layout.view_holder_men_women, parent, false);
    return new MenWomenViewHolder(itemView);

}
@Override
public void onBindViewHolder(@NonNull MenWomenViewHolder holder, int position) {

    CurrentyEntity currentCase = listOfCases.get(position);

    TextView first = holder.cardView.findViewById(R.id.men_women_count);
    first.setText(currentCase.getCountry());
    TextView secound = holder.cardView.findViewById(R.id.men_women_country);
    secound.setText(Integer.toString(currentCase.getInfections_count()));



    // Warning : maybe I shouldve used String.format instead



}


// if this is set to 0 it fucks up the whole thing. RecyclerView'ss contents won't be displayed
// getItemCount() is called many times, and when it is first called,
// mWords has not been updated (means initially, it's null, and we can't return null).
@Override
public int getItemCount() {
    if(listOfCases != null){

        Log.w("Row Count", String.valueOf(listOfCases.size()));
        return listOfCases.size();

    } else return  0;
}





class MenWomenViewHolder extends RecyclerView.ViewHolder {

  /*  private  final TextView Country;
    private  final TextView count;
     Country = itemView.findViewById(R.id.men_women_country);
        count = itemView.findViewById(R.id.men_women_count);
        */
  private CardView cardView;
    public MenWomenViewHolder(@NonNull View itemView) {
        super(itemView);
        cardView =  (CardView) itemView;



    }
}
}  

**7. HomeActivity.Class **

public class HomeActivity extends AppCompatActivity {

private Button signout;

private AllViewModel viewModel;


private RecyclerView recyclerView;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);

    recyclerView = findViewById(R.id.men_women_recycler);
    final MenWomenRecycler adapter = new MenWomenRecycler(this);
    recyclerView.setAdapter(adapter);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));


    Log.w("look for this in  the log", "touchin when kb is null");

    viewModel = ViewModelProviders.of(this).get(AllViewModel.class);

    viewModel.returnRowList().observe(this,new Observer<List<CurrentyEntity>>() {
        @Override
        public void onChanged(@Nullable final List<CurrentyEntity> listOfCases) {
                 adapter.setList(listOfCases);
        }
    });
    String rowCount = String.valueOf(viewModel.getRowCount());
    viewModel.addRow(new CurrentyEntity("EASY", 23));
    viewModel.addRow(new CurrentyEntity("letsee", 233));

** 8. HomeActivity's XML Layout File**

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".HomeActivity">
<!-- tools:listitem="@layout/view_holder_men_women"
 this makes it possible to have a preview of the RecyclerView-->
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/men_women_recycler"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    tools:listitem="@layout/view_holder_men_women"
    />

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:id="@+id/SIGNOUT"
    android:text="@string/signOut"
    />


</LinearLayout>

Here is the problem: first of all lets exclude these 2 lines of code from HomeActivity.class

viewModel.addRow(new CurrentyEntity("EASY", 23));
    viewModel.addRow(new CurrentyEntity("letsee", 233));

and stick with the first statemment that inserts a row in RoomDB.class which is this

DAO.insert(new CurrentyEntity("jordan",3434));

so far things work fine, they recycler would only display a single View(viewHolder) Now lets reinclude the 2 lines we've excluded above from the HomeActivity.class and by adding them again RecyclerView would display a random number of views and that number is bigger than the number of rows in RoomDB

For example when I ran the app and launched it RecyclerView supposedly must displaly exactly 3 Views(ViewHolders) as I've inserted only 3 rows, instead it displayed 6 views.

1 Answer 1

3

This is happening due to the following reason.

The first time when you launch the application, It makes 3 entries in DB. 1 entry from RoomDb class( Jordan one), 2 entries from the Home Activity class.

Now if you close the application by pressing the device back button and reopen it,It makes another 2 entries in DB ( Home Activities entry ( easy & letsee ). There will be no entry from RoomDB class ( Jordan one) because DB connection is still open. So

new LaunchAsyncTask(INSTANCE).execute();

will not execute.

Now if you kill the application and reopen then it will insert another 3 entries in DB. So total will be previous entries in DB + plus these 3 new entries.

same behaviors keep going on.

The above issue is happening due to an improper primary key. Every time it is making a new entry in DB.

you can try the below code by making the country the primary key.

    @NonNull
    @PrimaryKey
    @ColumnInfo(name = "country")
    private String country;
Sign up to request clarification or add additional context in comments.

1 Comment

I seriousy appreciate the crystal clear explanation, the problem drove me mad. but the things is that I was auto generating the "id" column(primary key) for Updating already existing entries purposes. well, then I guess I have to look for another way

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.