我正尝试将@Dao对象的所有方法都转换为可挂起,以供Kotlin协程使用。
当我将suspended修饰符添加到工作函数定义中并尝试在Android Studio中构建时,它无法生成XXXXDao_Impl.java类
一个精简的例子:
import androidx.lifecycle.LiveData
import androidx.room.*
@Database(entities = [SomeData::class], version = 1)
abstract class SomeDatabase : RoomDatabase() {
abstract fun getDao(): SomeDataDao
}
@Entity
data class SomeData(@PrimaryKey val id: Int, val name: String)
@Dao
interface SomeDataDao {
@Query("SELECT * FROM SomeData") // Works
fun getAllSync(): List<SomeData>
@Query("SELECT * FROM SomeData") // Works
suspend fun getAllSuspend(): List<SomeData>
@Query("SELECT * FROM SomeData") // Works
fun getAllSyncLiveData(): LiveData<List<SomeData>>
@Query("SELECT * FROM SomeData") // Fails to generate code
suspend fun getAllSuspendLiveData(): LiveData<List<SomeData>>
}
失败的生成代码:
package com.example.android.rawquerysuspendtest;
import android.database.Cursor;
import androidx.lifecycle.LiveData;
import androidx.room.CoroutinesRoom;
import androidx.room.RoomDatabase;
import androidx.room.RoomSQLiteQuery;
import androidx.room.util.CursorUtil;
import androidx.room.util.DBUtil;
import java.lang.Exception;
import java.lang.Object;
import java.lang.Override;
import java.lang.String;
import java.lang.SuppressWarnings;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import kotlin.coroutines.Continuation;
@SuppressWarnings({"unchecked", "deprecation"})
public final class SomeDataDao_Impl implements SomeDataDao {
private final RoomDatabase __db;
public SomeDataDao_Impl(RoomDatabase __db) {
this.__db = __db;
}
@Override
public List<SomeData> getAllSync() {
final String _sql = "SELECT * FROM SomeData";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
__db.assertNotSuspendingTransaction();
final Cursor _cursor = DBUtil.query(__db, _statement, false);
try {
final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "id");
final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
final List<SomeData> _result = new ArrayList<SomeData>(_cursor.getCount());
while(_cursor.moveToNext()) {
final SomeData _item;
final int _tmpId;
_tmpId = _cursor.getInt(_cursorIndexOfId);
final String _tmpName;
_tmpName = _cursor.getString(_cursorIndexOfName);
_item = new SomeData(_tmpId,_tmpName);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
_statement.release();
}
}
@Override
public Object getAllSuspend(final Continuation<? super List<SomeData>> p0) {
final String _sql = "SELECT * FROM SomeData";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
return CoroutinesRoom.execute(__db, false, new Callable<List<SomeData>>() {
@Override
public List<SomeData> call() throws Exception {
final Cursor _cursor = DBUtil.query(__db, _statement, false);
try {
final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "id");
final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
final List<SomeData> _result = new ArrayList<SomeData>(_cursor.getCount());
while(_cursor.moveToNext()) {
final SomeData _item;
final int _tmpId;
_tmpId = _cursor.getInt(_cursorIndexOfId);
final String _tmpName;
_tmpName = _cursor.getString(_cursorIndexOfName);
_item = new SomeData(_tmpId,_tmpName);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
_statement.release();
}
}
}, p0);
}
@Override
public LiveData<List<SomeData>> getAllSyncLiveData() {
final String _sql = "SELECT * FROM SomeData";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
return __db.getInvalidationTracker().createLiveData(new String[]{"SomeData"}, false, new Callable<List<SomeData>>() {
@Override
public List<SomeData> call() throws Exception {
final Cursor _cursor = DBUtil.query(__db, _statement, false);
try {
final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "id");
final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
final List<SomeData> _result = new ArrayList<SomeData>(_cursor.getCount());
while(_cursor.moveToNext()) {
final SomeData _item;
final int _tmpId;
_tmpId = _cursor.getInt(_cursorIndexOfId);
final String _tmpName;
_tmpName = _cursor.getString(_cursorIndexOfName);
_item = new SomeData(_tmpId,_tmpName);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
}
}
@Override
protected void finalize() {
_statement.release();
}
});
}
@Override
public Object getAllSuspendLiveData(final Continuation<? super LiveData<List<SomeData>>> p0) {
final String _sql = "SELECT * FROM SomeData";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
return CoroutinesRoom.execute(__db, false, new Callable<LiveData<List<SomeData>>>() {
@Override
public LiveData<List<SomeData>> call() throws Exception {
final Cursor _cursor = DBUtil.query(__db, _statement, false);
try {
return _result;
} finally {
_cursor.close();
_statement.release();
}
}
}, p0);
}
}
生成错误消息:
/Projects/Android/RawQuerySuspendTest/app/build/tmp/kapt3/stubs/debug/com/example/android/rawquerysuspendtest/SomeDataDao.java:24: error: Not sure how to convert a Cursor to this method's return type (androidx.lifecycle.LiveData<java.util.List<com.example.android.rawquerysuspendtest.SomeData>>).
public abstract java.lang.Object getAllSuspendLiveData(@org.jetbrains.annotations.NotNull()
应用程序的build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.android.rawquerysuspendtest"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.core:core-ktx:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
kapt "androidx.room:room-compiler:2.1.0-rc01"
implementation "androidx.room:room-runtime:2.1.0-rc01"
implementation "androidx.room:room-ktx:2.1.0-rc01"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha01'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-alpha01'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-alpha01'
}
我是否缺少依赖项或注释处理步骤?
答案 0 :(得分:1)
房间的当前实现不支持与LiveData
一起使用的协程。作为一种解决方法,您可以像下面这样实现它:
@Dao
interface AccountDao{
@Query("SELECT * FROM account_master")
suspend fun getAllAccounts(): List<Account>
}
在实现ViewModel
类的过程中,您可以创建LiveData
并为其分配一个值,该值是从数据库中检索的:
class MainViewModel : ViewModel() {
private val dao: AccountDao = ...// initialize it somehow
private var job: Job = Job()
private val scope = CoroutineScope(job + Dispatchers.Main)
lateinit var accounts: MutableLiveData<List<Account>>
override fun onCleared() {
super.onCleared()
job.cancel()
}
fun getAccounts(): LiveData<List<Account>> {
if (!::accounts.isInitialized) {
accounts = MutableLiveData()
scope.launch {
accounts.postValue(dao.getAllAccounts())
}
}
return accounts
}
}
要使用Dispatchers.Main
导入:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'