Home > OS >  How to connect Room Database to Custom ListView
How to connect Room Database to Custom ListView

Time:12-09

I am making a password manager on android with Room Database. I want to use Custom ListView but couldn't find any ways to connect my Room Database to the custom listview layout. I think I should make a adapter for my listview but I don't know how to make it. Looked for it but couldn't make it. How do I make it?

I get list of database by:

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

My Dao:

@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);

My Custom ListView layout:

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

My Password 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;
}

Thanks!

CodePudding user response:

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

There are in built adapters that you can use, as an example a SimpleCursorAdapter (which are designed to work with Cursors). You can specify the layout.

The only issue with using the SimpleCursorAdapter is that you would need a Cursor, which Room doesn't typically provide. However,perhaps consider the following working example, which creates a MatrixCursor from an extract via your getAllPasswords.

The example uses your Password entity and your custom_listview.xml unchanged.

However, the PasswordDao has been modified (see comments) to be:-

@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);
}

The @Database class PasswordDatabase is as follows :-

@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;
    }
}
  • noting that for convenience and brevity .allowMainThreadQueries has been utilised.

The layout activity_main.xml for MainActivity is :-

<?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>
  • i.e. the ListView has been added

Finally putting it altogether in 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();
    }
}

When the above is run for the first time then :-

enter image description here

  • if run again then two more rows will be added and so on. Although the rows have App1 and App2 etc the uid's will be different.
  • Related