Room:无法在主线程上访问数据库,因为它可能会长时间锁定 UI

新手上路,请多包涵

在主要活动中,我有包含成员和点击侦听器的 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;
}

我想我用错了方法。有谁能够帮助我?

原文由 LordGash 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 688
2 个回答

一种选择是将您的查询更新为此:

 @Query("SELECT * FROM member_table WHERE MemberID=:id")
LiveData<Member> getMemberInfo(long id);

(或类似的,使用 Flowable )。这避免了手动创建您自己的 AsyncTask 的需要。

返回 LiveData 围绕 Member 类型的包装自动向Room发出信号,表明查询可以/应该异步执行。根据 https://developer.android.com/training/data-storage/room/accessing-data (我的重点):

注意:除非您在构建器上调用了 allowMainThreadQueries() ,否则 Room 不支持主线程上的数据库访问,因为它可能会长时间锁定 UI。 异步查询——返回 LiveData 或 Flowable 实例的查询——不受此规则约束,因为它们在需要时在后台线程上异步运行查询

原文由 stkent 发布,翻译遵循 CC BY-SA 4.0 许可协议

您可以使用 Future 和 Callable。因此,您无需编写冗长的异步任务,无需添加 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();
}

原文由 beginner 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题