如何将房间数据库连接到自定义 ListView

How to connect Room Database to Custom ListView

我正在 android 上使用 Room Database 创建一个密码管理器。我想使用自定义 ListView,但找不到任何方法将我的房间数据库连接到自定义列表视图布局。我想我应该为我的列表视图制作一个适配器,但我不知道如何制作。寻找它,但无法做到。我该怎么做?

我通过以下方式获取数据库列表:

AppDatabase db = AppDatabase.getDbInstance(this.getApplicationContext());
    List<Password> passwordList = db.passwordDAO().getAllPasswords();

我的道:

@Dao
public interface PasswordDAO {

@Query("SELECT * FROM password")
List<Password> getAllPasswords();

@Query("SELECT hashed_password FROM password")
ArrayList<Password> getAllHashedPasswords();

@Query("SELECT app_name FROM password")
ArrayList<Password> getAllAppNames();

 @Query("SELECT uid FROM password")
 ArrayList<Password> getAllIDs();

@Insert
void insertUser(Password... passwords);

@Delete
void delete(Password password);

我的自定义 ListView 布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="@dimen/_80sdp"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="App Name"
        android:id="@+id/customListView_AppName"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="@dimen/_10sdp"
        android:textSize="@dimen/_20sdp"
        />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/customListView_HashedPassword"
        android:text="Hashed Password"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="@dimen/_50sdp"
        android:textSize="@dimen/_20sdp"
        />

</RelativeLayout>

</RelativeLayout>

我的密码Class:

@Entity
public class Password {

@PrimaryKey(autoGenerate = true)
public int uid;

@ColumnInfo(name = "app_name")
public String app_name;

@ColumnInfo(name = "hashed_password")
public String hashed_password;
}

谢谢!

I think I should make a adapter for my listview but I don't know how to make it.

您可以使用内置适配器,例如 SimpleCursorAdapter(设计用于游标)。您可以指定布局。

使用 SimpleCursorAdapter 的唯一问题是您需要一个 Cursor,而 Room 通常不提供。但是,也许考虑以下工作示例,它通过 getAllPasswords.

从提取中创建一个 MatrixCursor

该示例使用您的 密码 实体和您的 custom_listview.xml 不变。

然而,PasswordDao 已被修改(见评论)为:-

@Dao
public interface PasswordDAO {

    @Query("SELECT * FROM password")
    List<Password> getAllPasswords();

    /* can't do as insufficient data to build Password objects
    @Query("SELECT hashed_password FROM password")
    ArrayList<Password> getAllHashedPasswords();
     */

    /* Likewise
    @Query("SELECT app_name FROM password")
    ArrayList<Password> getAllAppNames();
    */


    /* Likewise
    @Query("SELECT uid FROM password")
    ArrayList<Password> getAllIDs();
    */

    @Insert
    void insertUser(Password... passwords);

    @Delete
    void delete(Password password);
}

@Database class PasswordDatabase如下:-

@Database(entities = {Password.class},version =1,exportSchema = false)
abstract class PasswordDatabase extends RoomDatabase {
    abstract PasswordDAO getDao();

    private static volatile PasswordDatabase instance = null;
    static PasswordDatabase getInstance(Context context) {
        if (instance == null) {
            instance = Room.databaseBuilder(context, PasswordDatabase.class,"password.db")
                    .allowMainThreadQueries()
                    .build();
        }
        return instance;
    }
}
  • 注意到为了方便和简洁起见,使用了 .allowMainThreadQueries。

MainActivity 的布局 activity_main.xml 是:-

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" >
    </TextView>

    <ListView
        android:id="@+id/myListView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </ListView>

</androidx.appcompat.widget.LinearLayoutCompat>
  • 即已添加 ListView

最后把它放在 MainActivity :-

public class MainActivity extends AppCompatActivity {

    ListView myListView;
    PasswordDatabase db;
    PasswordDAO dao;
    Cursor csr;
    SimpleCursorAdapter sca;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myListView = this.findViewById(R.id.myListView);
        db = PasswordDatabase.getInstance(this);
        dao = db.getDao();

        /* add some testing data */
        Password p1 = new Password();
        p1.uid = 0;
        p1.hashed_password = "hashpassword1";
        p1.app_name = "App1";
        Password p2 = new Password();
        p2.uid = 0;
        p2.hashed_password = "hashpassword2";
        p2.app_name = "App2";
        dao.insertUser(p1,p2);

        setUpOrRefreshListView();
    }

    /* As it says setup or refresh the ListView */
    private void setUpOrRefreshListView() {
        csr = getCursor();
        if (sca == null) {
            sca = new SimpleCursorAdapter(
                    this,
                    R.layout.custom_listview,csr,
                    new String[]{"app_name","hashed_password"},
                    new int[]{R.id.customListView_AppName,R.id.customListView_HashedPassword},
                    0
            );
            myListView.setAdapter(sca);
            /* BONUS handle Long Click of an Item in the ListView
                in this case just Toast info
            */
            myListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
                @SuppressLint("Range")
                @Override
                public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
                    Toast.makeText(
                            view.getContext(),
                            "You long-clicked password with AppName = "
                                    + csr.getString(csr.getColumnIndex("app_name"))
                                    + " Hash = " + csr.getString(csr.getColumnIndex("hashed_password"))
                                    + " UID = " + l,
                            Toast.LENGTH_SHORT
                    ).show();
                    return true;
                }
            });
        } else {
            sca.swapCursor(csr);
        }

    }

    /* Gets all the passwords using getAllPassswords and creates a MatrixCursor */
    private Cursor getCursor() {
        List<Password> passwords = dao.getAllPasswords();
        /* NOTE that as Cursor Adapters required a column named _ID (as per BaseColumns._ID)
            the first column has been renamed accordingly

         */
        MatrixCursor mxcsr = new MatrixCursor(new String[]{
                BaseColumns._ID,
                "app_name",
                "hashed_password"},
                0
        );
        for (Password p: dao.getAllPasswords()) {
            mxcsr.addRow(new Object[]{p.uid,p.app_name,p.hashed_password});
        }
        return mxcsr;
    }

    /* If resuming this activity then refresh the ListView */
    @Override
    protected void onResume() {
        super.onResume();
        setUpOrRefreshListView();
    }

    /* if the activity is detsroyed then close the Cursor */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        csr.close();
    }
}

如果以上是第一次 运行 那么:-

  • if 运行 将再添加两行,依此类推。尽管行有 App1 和 App2 等,但 uid 会有所不同。