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 :-
- 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.