在主活动中,我有LiveData,其中包含成员和单击侦听器。如果单击成员,则其ID将与intent.putExtra一起传递。该ID稍后传递给在此活动中打开的方法。通过此活动,我想查看成员的详细信息。在我的MemberInfo活动中,我在问题所在的位置标记了一行。 它向我显示了此错误:无法访问主线程上的数据库,因为它可能会长时间锁定UI。
我的DAO包含以下代码:
@Query("SELECT * FROM member_table WHERE MemberID=:id")
Member getMemberInfo(long id);
这是我的主要活动:
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());
}
}
这是我的活动:
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();
}
}
}
我认为可能是因为我缺少AsyncTask方法。我试过了,但这也没用:
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;
}
我认为我使用的方法错误。有人可以帮我吗?
答案 0 :(得分:6)
一种选择是将查询更新为此:
@Query("SELECT * FROM member_table WHERE MemberID=:id")
LiveData<Member> getMemberInfo(long id);
(或类似的格式,使用Flowable
)。这样就无需手动创建自己的AsyncTask
。
在Member
类型周围返回LiveData
包装器会自动向Room发出信号,表示可以/应该异步执行查询。根据{{3}}(我的重点):
注意:Room不支持在主线程上进行数据库访问,除非您在构建器上调用了
allowMainThreadQueries()
,因为Room可能会长时间锁定UI。 异步查询(返回LiveData或Flowable实例的查询)不受此规则的限制,因为它们在需要时在后台线程上异步运行查询。。
答案 1 :(得分:3)
您可以使用Future和Callable。因此,您无需编写冗长的asynctask即可执行查询而无需添加allowMainThreadQueries()或使用LiveData。
我的岛查询:-
@Query("SELECT * from user_data_table where SNO = 1")
UserData getDefaultData();
我的存储库方法:-
public UserData getDefaultData() throws ExecutionException, InterruptedException {
Callable<UserData> callable = new Callable<UserData>() {
@Override
public UserData call() throws Exception {
return userDao.getDefaultData();
}
};
Future<UserData> future = Executors.newSingleThreadExecutor().submit(callable);
return future.get();
}
答案 2 :(得分:2)
对我来说allowMainThreadQueries()
有用。
这为在主线程上支持数据库访问提供了空间。
请参见以下代码
@Database(entities = [Word::class ],version = 1)
abstract class VocabularyDatabase:RoomDatabase() {
companion object {
private lateinit var INSTANCE:VocabularyDatabase
fun getInstance(context:Context):VocabularyDatabase= Room.databaseBuilder(
context,
VocabularyDatabase::class.java,
"vocabulary"
)
.createFromAsset("vocabulary.db")
.allowMainThreadQueries()
.build()
}
abstract fun dao():WordDao
}
答案 3 :(得分:0)
在这里,使用Future和Callables可以替代。通过使用Future和Callable,您可以摆脱AsyncTask并将查询强制到主线程。
语法如下-
@Throws(ExecutionException::class, InterruptedException::class)
private fun canContinue(id: String): UserData{
val callable = Callable { userDao.getDefaultData() }
val future = Executors.newSingleThreadExecutor().submit(callable)
return future!!.get()
}
而且,不要忘记对返回的数据进行空检查。因为它可能为空