首页 > 解决方案 > Android Studio-Java RecyclerView 显示的视图(持有者)多于房间数据库中的行数

问题描述

1.实体(表)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. 房间数据库 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.存储库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 适配器 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的XML布局文件**

<?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>

这是问题所在:首先让我们从 HomeActivity.class 中排除这两行代码

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

并坚持在 RoomDB.class 中插入一行的第一条语句,即

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

到目前为止一切正常,它们回收器只会显示一个 View(viewHolder) 现在让我们重新包含我们在上面从 HomeActivity.class 中排除的 2 行,并通过再次添加它们 RecyclerView 将显示随机数量的视图,这个数字是大于 RoomDB 中的行数

例如,当我运行应用程序并启动它时,RecyclerView 据说必须准确显示 3 个视图(ViewHolders),因为我只插入了 3 行,而是显示了 6 个视图。

标签: javaandroidmvvmandroid-recyclerviewandroid-room

解决方案


这是由于以下原因而发生的。

第一次启动应用程序时,它会在 DB 中创建 3 个条目。来自 RoomDb 类的 1 个条目(约旦一),来自 Home Activity 类的 2 个条目。

现在,如果您通过按下设备后退按钮关闭应用程序并重新打开它,它会在 DB 中创建另外 2 个条目(Home Activities 条目(easy & letsee)。将没有 RoomDB 类(Jordan 类)的条目,因为 DB 连接仍然存在打开。所以

new LaunchAsyncTask(INSTANCE).execute();

不会执行。

现在,如果您终止应用程序并重新打开,它将在 DB 中插入另外 3 个条目。所以总计将是 DB + 中的先前条目加上这 3 个新条目。

同样的行为还在继续。

上述问题是由于主键不正确而发生的。每次它在数据库中创建一个新条目。

您可以通过将国家设为主键来尝试以下代码。

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

推荐阅读