![](/img/trans.png)
[英]java.lang.IllegalStateException: Cannot perform this operation because there is no current transaction
[英]Android Room JUnit testing: "AsyncTask #1" java.lang.IllegalStateException: Cannot perform this operation because there is no current transaction
我正在尝试对我的项目进行简单的测试,但是这个异常阻碍了我,我找不到原因。
我做了一个简单的测试,将一些新客户插入到我的数据库中。 我在插入客户时遇到的第一个问题是我无法在主线程中插入数据,所以我使用了AsyncTask.execute(new Runnable())
但这次我遇到了这个问题。
我提供了以下课程,希望能提供很好的洞察力。
测试类:
@RunWith(RobolectricTestRunner.class)
public class ExampleUnitTest {
ShopDatabase db;
private CustomerDao customerDao;
@Before
public void createDB() {
Context context = ApplicationProvider.getApplicationContext();
db = Room.inMemoryDatabaseBuilder(context, ShopDatabase.class).build();
customerDao = db.customerDao();
}
@Test
public void createUser(){
final Customer customer = new Customer("Test", "Test test", Date.valueOf("2020-10-10"));
AsyncTask.execute(new Runnable() {
@Override
public void run() {
customerDao.insert(customer);
}
});
Customer customerFound = customerDao.getCustomerByName("Test", "Test test");
assertEquals(customerFound.getFirstName(), customer.getFirstName(), "Could not find user..");
}
@After
public void closeDB() {
db.close();
}
存储库:
public class Repository {
private CustomerDao customerDao;
private LiveData<List<Customer>> allCustomers;
private Customer customer;
public Repository(Application application) {
// Get DB instance
ShopDatabase db = ShopDatabase.getInstance(application);
customerDao = db.customerDao();
allCustomers = customerDao.getAllCustomers();
}
public void insert(Customer customer) {
new InsertCustomerAsyncTask(customerDao).execute(customer);
}
public Customer getCustomerByName(String first, String last) {
return customerDao.getCustomerByName(first, last);
}
public LiveData<List<Customer>> getAllCustomers() {
return allCustomers;
}
// Inner Async class to insert customers
private static class InsertCustomerAsyncTask extends AsyncTask<Customer, Void, Void> {
private CustomerDao customerDao;
public InsertCustomerAsyncTask(CustomerDao customerDao) {
this.customerDao = customerDao;
}
@Override
protected Void doInBackground(Customer... customers) {
customerDao.insert(customers[0]);
return null;
}
}
数据库:
@Database(entities = {Customer.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class ShopDatabase extends RoomDatabase {
private static ShopDatabase instance;
public abstract CustomerDao customerDao();
public static synchronized ShopDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(context.getApplicationContext(),
ShopDatabase.class,"shop_database")
.fallbackToDestructiveMigration()
.addCallback(roomCallback)
.build();
}
return instance;
}
private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
new PopulateDbAsyncTask(instance).execute();
}
};
private static class PopulateDbAsyncTask extends AsyncTask<Void, Void, Void> {
private CustomerDao customerDao;
PopulateDbAsyncTask(ShopDatabase db) {
customerDao = db.customerDao();
}
@Override
protected Void doInBackground(Void... voids) {
// Customers
long c = customerDao.insert(new Customer("One", "A", Date.valueOf("2019-05-10")));
long c2 = customerDao.insert(new Customer("Two", "B", Date.valueOf("2020-07-10")));
long c3 = customerDao.insert(new Customer("Three", "C", Date.valueOf("1860-12-10")));
return null;
}
}
}
首先,我认为这是因为我的应用程序没有运行,所以这意味着我的数据库已关闭,但事实并非如此。 我在测试时打开了我的应用程序。
其次 - 当我在实例化我的数据库( db = Room.inMemoryDatabaseBuilder(context, ShopDatabase.class).build();
)后检查数据库是否打开时 - db.isOpen()
-> 它每次都返回false 。
什么会导致问题?
当我在实例化我的数据库(
db = Room.inMemoryDatabaseBuilder(context, ShopDatabase.class).build();
)后检查数据库是否打开时 - db.isOpen() -> 它每次都返回 false 。
在您尝试访问数据库之前,不会打开该数据库。 您可以在返回实例之前强制访问它(获取可写或可读的数据库/连接,也就是打开数据库文件本身,这一切都代表您在幕后完成)。 例如
......
instance.getOpenHelper().getWritableDatabase();
return instance;
使用 :-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
shopDatabase = ShopDatabase.getInstance(this);
boolean dbopen = shopDatabase.isOpen();
if (dbopen); //<<<<<<<<<< breakpoint here
}
和 :-
public static synchronized ShopDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(context.getApplicationContext(),
ShopDatabase.class,"shop_database")
.fallbackToDestructiveMigration()
.addCallback(roomCallback)
.build();
}
//instance.getOpenHelper().getWritableDatabase();
return instance;
}
结果是
更改为使用:-
public static synchronized ShopDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(context.getApplicationContext(),
ShopDatabase.class,"shop_database")
.fallbackToDestructiveMigration()
.addCallback(roomCallback)
.build();
}
instance.getOpenHelper().getWritableDatabase(); //<<<<<<<<< ADDED
return instance;
}
结果是 :-
我无法在主线程中插入数据
如果在构建时添加.allowMainThreadQueries()
,则可以
例如
public static synchronized ShopDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(context.getApplicationContext(),
ShopDatabase.class,"shop_database")
.fallbackToDestructiveMigration()
.allowMainThreadQueries()
.addCallback(roomCallback)
.build();
}
instance.getOpenHelper().getWritableDatabase();
return instance;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.