You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Room库报错:主线程无法访问数据库,求Java解决方案

解决Android Room主线程访问数据库的Java方案

问题

使用Android Room实现SQLite本地数据库,编译阶段创建数据库,运行项目时触发主线程访问数据库的异常,目标是创建空数据库后通过GUI填充数据,需要Java环境下的解决方案。

错误日志

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.dblearning.dbroom_test/com.dblearning.dbroom_test.RecyclerActivity}: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.                              at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3698)                                                                                       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3855)                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:105)                                                                            at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:136)                                                                 at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)                                                                           at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2267)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:201)
    at android.os.Looper.loop(Looper.java:288)
    at android.app.ActivityThread.main(ActivityThread.java:7964)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:553)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
    at androidx.room.RoomDatabase.assertNotMainThread(RoomDatabase.kt:439)
    at androidx.room.RoomDatabase.query(RoomDatabase.kt:479)
    at androidx.room.util.DBUtil.query(DBUtil.kt:75)
    at com.dblearning.dbroom_test.DAO_Impl.getAll(DAO_Impl.java:165)
    at com.dblearning.dbroom_test.RecyclerActivity.onCreate(RecyclerActivity.java:29)
    at android.app.Activity.performCreate(Activity.java:8069)
    at android.app.Activity.performCreate(Activity.java:8049)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3668)

相关代码

RecyclerActivity代码

public class RecyclerActivity extends AppCompatActivity  {
    private Button add,del,update;
    private EditText dataField;
    List<DataEntity>  dataEntityList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler);
        RoomDB db = Room.databaseBuilder(this,
                RoomDB.class, "tab").build();
        DAO dao = db.Dao();
        dataEntityList =dao.getAll();
        RecyclerView recyclerView = findViewById(R.id.recyclerView);
        Adapter entityAdapter = new Adapter(dataEntityList);
        recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
        recyclerView.setAdapter(entityAdapter);
           ... 
    }
}

DAO接口代码

@Dao
public interface DAO {

    @Query("SELECT * FROM tab")
    List<DataEntity> getAll();

    @Query("SELECT * FROM tab WHERE id IN (:userIds)")
    List<DataEntity> loadAllByIds(int[] userIds);
    @Query("DELETE FROM tab")
    void deleteAll();

    @Query("SELECT * FROM tab WHERE first_item LIKE :first AND " + "second_item LIKE :last LIMIT 1")
    DataEntity findByName(String first, String last);

    @Update
    void update(DataEntity entity);

    @Insert
    void insertAll(DataEntity... Entities);
    @Delete
    void delete(DataEntity Entity);
}

DataEntity实体类代码

@Entity(tableName = "tab" )
public class DataEntity {

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id")
    public int uid;

    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    @ColumnInfo(name = "first_item")
    public String firstItem;

    public String getFirstItem() {
        return firstItem;
    }

    public void setFirstItem(String firstItem) {
        this.firstItem = firstItem;
    }

    @ColumnInfo(name = "second_item")
    public String secondItem;

    public String getSecondItem() {
        return secondItem;
    }

    public void setSecondItem(String secondItem) {
        this.secondItem = secondItem;
    }
    public DataEntity(){

    }
}

解决方案

Room默认禁止主线程访问数据库,避免UI阻塞,以下是三种Java环境下的解决方式:

1. 使用AsyncTask执行后台查询(传统Java方案)

修改RecyclerActivity,将数据库查询放在AsyncTask中执行,查询完成后更新RecyclerView的Adapter:

public class RecyclerActivity extends AppCompatActivity  {
    private Button add,del,update;
    private EditText dataField;
    List<DataEntity>  dataEntityList;
    private Adapter entityAdapter;
    private RecyclerView recyclerView;
    private DAO dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler);
        RoomDB db = Room.databaseBuilder(this, RoomDB.class, "tab").build();
        dao = db.Dao();
        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
        
        // 启动AsyncTask执行查询
        new LoadDataTask().execute();
           ... 
    }

    private class LoadDataTask extends AsyncTask<Void, Void, List<DataEntity>> {
        @Override
        protected List<DataEntity> doInBackground(Void... voids) {
            // 后台线程执行数据库查询
            return dao.getAll();
        }

        @Override
        protected void onPostExecute(List<DataEntity> result) {
            super.onPostExecute(result);
            dataEntityList = result;
            entityAdapter = new Adapter(dataEntityList);
            recyclerView.setAdapter(entityAdapter);
        }
    }
}

2. 改造DAO返回LiveData(推荐,生命周期感知)

这种方式更符合Android架构组件的设计,Room会自动在后台线程执行查询,并在数据变化时通知UI:

  • 首先修改DAO接口,将getAll()方法返回LiveData<List<DataEntity>>:
@Dao
public interface DAO {

    @Query("SELECT * FROM tab")
    LiveData<List<DataEntity>> getAll(); // 修改返回类型

    // 其他方法保持不变
    @Query("SELECT * FROM tab WHERE id IN (:userIds)")
    List<DataEntity> loadAllByIds(int[] userIds);
    @Query("DELETE FROM tab")
    void deleteAll();

    @Query("SELECT * FROM tab WHERE first_item LIKE :first AND " + "second_item LIKE :last LIMIT 1")
    DataEntity findByName(String first, String last);

    @Update
    void update(DataEntity entity);

    @Insert
    void insertAll(DataEntity... Entities);
    @Delete
    void delete(DataEntity Entity);
}
  • 然后修改RecyclerActivity,观察LiveData的变化:
public class RecyclerActivity extends AppCompatActivity  {
    private Button add,del,update;
    private EditText dataField;
    private Adapter entityAdapter;
    private RecyclerView recyclerView;
    private DAO dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler);
        RoomDB db = Room.databaseBuilder(this, RoomDB.class, "tab").build();
        dao = db.Dao();
        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
        
        // 观察LiveData,数据变化时更新Adapter
        dao.getAll().observe(this, new Observer<List<DataEntity>>() {
            @Override
            public void onChanged(List<DataEntity> dataEntities) {
                entityAdapter = new Adapter(dataEntities);
                recyclerView.setAdapter(entityAdapter);
            }
        });
           ... 
    }
}

3. 临时允许主线程访问(仅调试用,不推荐上线)

如果只是临时调试,可以在构建数据库时添加allowMainThreadQueries()方法,但这种方式会导致UI卡顿,上线版本绝对不能用:

RoomDB db = Room.databaseBuilder(this, RoomDB.class, "tab")
               .allowMainThreadQueries() // 添加此行
               .build();

内容的提问来源于stack exchange,提问作者Drained

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 17:18:11