In the main activity, I have LiveData which contains members and a click listener. If I click on a member, then his ID is passed with intent.putExtra. That ID is later passed on to the method open in this activity. With this activity, I want to see the details of a member. In my MemberInfo activity, I marked a line where my problem lies. It shows me this error: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
My DAO consists this code:
@Query("SELECT * FROM member_table WHERE MemberID=:id")
Member getMemberInfo(long id);
This is my main activity:
public class MemberMainActivity extends AppCompatActivity implements MemberListAdapter.MemberClickListener{
private MemberViewModel mMemberViewModel;
private List<Member> mMember;
void setMember(List<Member> members) {
mMember = members;
}
public static final int NEW_MEMBER_ACTIVITY_REQUEST_CODE = 1;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_member);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MemberMainActivity.this, NewMemberActivity.class);
startActivityForResult(intent, NEW_MEMBER_ACTIVITY_REQUEST_CODE);
}
});
RecyclerView recyclerView = findViewById(R.id.recyclerviewcard_member);
final MemberListAdapter adapter = new MemberListAdapter(this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
mMemberViewModel = ViewModelProviders.of(this).get(MemberViewModel.class);
mMemberViewModel.getAllMember().observe(this, new Observer<List<Member>>() {
@Override
public void onChanged(@Nullable final List<Member> members) {
mMember = members;
// Update the cached copy of the words in the adapter.
adapter.setMember(members);
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == NEW_MEMBER_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
Member member = new Member(data.getStringExtra(NewMemberActivity.EXTRA_REPLY), data.getStringExtra(NewMemberActivity.EXTRA_REPLY2));
mMemberViewModel.insert(member);
} else {
Toast.makeText(
getApplicationContext(),
R.string.empty_not_saved,
Toast.LENGTH_LONG).show();
}
}
public void onMemberClick(int position) {
Member member = mMember.get(position);
Intent intent = new Intent(getApplicationContext(),MemberInfo.class);
intent.putExtra("MemberID", member.getId());
MemberInfo.open(this, member.getId());
}
}
This is my activity:
public class MemberInfo extends AppCompatActivity {
public static void open(Activity activity, long memberid) {
Intent intent = new Intent(activity, MemberInfo.class);
intent.putExtra("MemberID", memberid);
activity.startActivity(intent);
}
private List<Member> mMember;
private MemberViewModel mMemberViewModel;
void setMember(List<Member> members){
mMember = members;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_memberinfo);
Log.i("okay", "memberinfo");
Intent intent = getIntent();
if (intent != null && intent.hasExtra("MemberID")) {
long memberid = intent.getLongExtra("MemberID", -1);
// TODO: get customer details based on customer id
TextView firstname = findViewById(R.id.layout_memberfirstname);
TextView surname = findViewById(R.id.layout_membersurname);
TextView balance = findViewById(R.id.layout_memberbalance);
-------------Member member = MemberRoomDatabase.getDatabase().memberDao().getMemberInfo(memberid);-------------
firstname.setText(member.getFirstname());
surname.setText(member.getSurname());
}
else {
Toast.makeText(
getApplicationContext(),
R.string.empty_not_saved,
Toast.LENGTH_LONG).show();
}
}
}
I thought that maybe it is because I'm missing a AsyncTask method. I tried this, but this also didn't work:
private static class insertMemberInfoAsyncTask extends AsyncTask<Member, Void, Void> {
private MemberDao mAsyncTaskDao;
insertMemberInfoAsyncTask(MemberDao dao) {
mAsyncTaskDao = dao;
}
@Override
protected Void doInBackground(Member... params) {
Member member = params[0];
mAsyncTaskDao.getMemberInfo(member.getId());
return null;
}
}
public Member getMemberInfo(long id) {
mAllMember = mMemberDao.getAllMember();
Member member = mMemberDao.getMemberInfo(id);
new insertMemberInfoAsyncTask(mMemberDao).execute(member);
return member;
}
I think I use the method wrong. Can anybody help me?
You can use Future and Callable. So you would not be required to write a long asynctask and can perform your queries without adding allowMainThreadQueries() or using LiveData.
My dao query:-
My repository method:-
Using Future and Callables can be an alternative here. By using Future and Callable you can get rid of AsyncTask and forcing your queries to the main thread.
The syntax would be as follow -
And, don't forget the null check for the data returned. Because it might be null
One option is to update your query to this:
(or similar, using
Flowable
). This avoids the need to manually create your ownAsyncTask
.Returning the
LiveData
wrapper around theMember
type automatically signals to Room that the query can/should be performed asynchronously. Per https://developer.android.com/training/data-storage/room/accessing-data (my emphasis):