Как получить вставленный идентификатор строки после вставки строки в комнате в основной поток
Я хочу вернуть вставленный идентификатор строки, чтобы использовать его для обновления некоторого значения в той же строке
@Entity(tableName = "course")
public class Course {
@PrimaryKey(autoGenerate = true)
private int id;
private String firebaseId;
}
@Dao
public interface CourseDao {
@Insert(onConflict = REPLACE)
long insertCourse(Course course);
@Query("UPDATE course SET firebaseId = :firebaseId WHERE id = :id")
void updateFirebaseId(int id, String firebaseId);
}
проблема в том, что я не могу вернуть идентификатор в основной поток
public class Repository {
private static final Object LOCK= new Object();
private static Repository sInstance;
private final CourseDao mCourseDao;
private final AppExecutors mAppExecutors;
public void insertCourse(final Course course) {
mAppExecutors.diskIO().execute(new Runnable() {
@Override
public void run() {
mCourseDao.insertCourse(course);
}
});
}
public void updateCourse(final Course course) {
mAppExecutors.diskIO().execute(new Runnable() {
@Override
public void run() {
mCourseDao.updateCourse(course);
}
});
}
}
Я пытался использовать liveData, но он не поддерживается при вставке
Error:(34, 20) error: Methods annotated with @Insert can return either void, long, Long, long[], Long[] or List<Long>.
Можно ли вернуть идентификатор курса после завершения вставки без написания отдельного запроса выбора?
1 ответ
LiveData
не поддерживается для insert
,
Я чувствую, что есть 2 подхода insert
работа в фоновом потоке и отправка результата (long
) вернуться к деятельности:
С помощью
LiveData
Мне лично нравится такой подход:public class Repository { private LiveData<Long> insertedId = MutableLiveData() public void insertCourse(final Course course) { mAppExecutors.diskIO().execute(new Runnable() { @Override public void run() { Long id = mCourseDao.insertCourse(course); insertId.setValue(id); } }); } }
С помощью
Rx
:return Single.fromCallable(() -> mCourseDao.insertCourse(course));
Здесь вы получите
Single<Long>
который вы можете наблюдать в своемActivity
Замечания: Repository
вернусь Long
в ViewModel
и в вашем ViewModel
будет иметь LiveData
а также setValue
вещи.
Я так сделал на Яве
В среде, где вам нужен идентификатор:
public class MyIdClass {
ArrayList<Integer> someIds = new ArrayList<>(); //this could be a primitive it doesn't matter
конструктор с репозиторием....{}
@FunctionalInterface //desugaring... normal interfaces are ok I guess?
public interface GetIdFromDao {
void getId(long id);
}
public void insertSomething(
Something something
) {
someRepository.insertSomething(
something,
id -> someIds.add((int)id) //lambda replacement, I think method reference cannot be done because of (int) casting, but if Array is type long it could be done.
);
}
}
В абстрактном классе MyDao...: (что-то, что я не могу не подчеркнуть..., работайте с ABSTRACT CLASS DAO, его более гибким)
@Insert(onConflict = OnConflictStrategy.IGNORE)
protected abstract long protectedInsertSomething(Something something);
public void insert(
Something something,
MyIdClass.GetIdFromDao getIdFromDao
) {
//get long id with insert method type long
long newSomethingId = protectedInsertSomething(something);
getIdFromDao.getId(newSomethingId);
}
Внутри репозитория, если вы используете AsyncTask<X, Y, Z>
, вы действительно можете передавать через VarAgrs все, даже прослушиватели, но не забудьте преобразовать их в том порядке, в котором они вставлены, и использовать тип Object или общего предка.
(Something) object[0];
(MyIdClass.GetIdFromDao) object[1];
new InsertAsyncTask<>(dao).execute(
something, //0
getIdFromDao //1
)
Также используйте @SupressWarnings("unchecked")
, Ничего не произошло
Теперь, если вы хотите еще большего взаимодействия, вы можете подключить LiveData к слушателю или создать Factory ViewModel... абстрактную factory ViewModel... что было бы интересно. Но я считаю, что у DataBinding есть модель наблюдаемого представления, которую, я думаю, можно использовать (?)... Я действительно не знаю.