我用 LiveData 构建了一个简单的 Room 示例,但是得到了一个
无法访问主线程上的数据库”- IllegalStateException
我的一般架构是带有片段的活动,它有一个带有房间的 ViewModel 和 Repository。
我的调用从这里开始(我剪切了片段,单击调用该方法的按钮)。
我使用 androidannotations,但这不应该与错误有关。
在我看来,它很简单,而且插入调用显然是在 AsyncTask 中,所以这就是为什么我真的对异常感到困惑的原因。
我的视图模型:
class FragmentAddKeywordsViewModel extends AndroidViewModel {
KeywordsRepository repository;
public FragmentAddKeywordsViewModel(@NonNull Application application) {
super(application);
if (repository == null) {
repository = new KeywordRepository(application);
}
}
public void addKeyword(Keyword keyword) {
repository.addKeyword(keyword);
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的存储库:
public class KeywordsRepository {
private KeywordDao keywordDao;
public KeywordsRepository (Application application) {
KeywordDatabase db = KeywordDatabase.getDatabase(application);
keywordDao= db.keywordDao();
}
public void addKeyword(Keyword keyword) {
new insertAsyncTask(keywordDao).doInBackground(keyword);
}
private static …Run Code Online (Sandbox Code Playgroud) 我试图使用LiveData和viewmodel从房间中获取自定义对象数据的列表。使用Livedata的getValue()方法时,返回null,但获取列表直接显示实际数据。如何在Viewmodel类中使用LiveData获得Period类的列表。
实体类
@Entity
public class Period {
@PrimaryKey
@NonNull
String header;
@TypeConverters(WritterConverter.class)
ArrayList<Writter> writters;
public Period(String header, ArrayList<Writter> writters) {
this.header = header;
this.writters = writters;
}
public String getHeader() {
return header;
}
public ArrayList<Writter> getWritters() {
return writters;
}
}
@Entity
public class Writter {
String birth;
String death;
String name;
ArrayList<String> novels;
public Writter(){}
public Writter(String birth, String death, String name, ArrayList<String> novels) {
this.birth = birth;
this.death = death;
this.name = name;
this.novels = novels;
} …Run Code Online (Sandbox Code Playgroud) 我有这样BottomSheetDialogFragment的布局:
<data>
<variable
name="viewModel"
type="com.sample.MyViewModel" />
</data>
<TextView android:id="@+id/tvValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{String.format("%.1f", viewModel.weight)}'/>
<Button android:id="@+id/cmdUpdate"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:onClick="@{() -> viewModel.updateWeight()}"
android:text="@string/update" />
Run Code Online (Sandbox Code Playgroud)
这是kotlin代码:
// MyViewModel
val weight = MutableLiveData<Double>()
fun updateWeight() {
weight.value?.let {
weight.value = (it + 0.1)
}
}
// BottomSheetDialogFragment bind view model
val myViewModel = ViewModelProviders.of(it, factory).get(MyViewModel::class)
binding.viewModel = myViewModel
// code showing BottomSheet:
val fragment = MyBottomSheetFragment()
fragment.show(fragmentManager, "bottomsheet")
Run Code Online (Sandbox Code Playgroud)
第一次打开底片片段,它可以显示重量值,但是当我单击按钮更新重量时,什么也没有发生。从调试器中,我可以看到该updateWeight方法已调用,并且权重值已更改,但未TextView更新。这也发生在其他DialogFragment上。
如果我使用常规代码,则相同的代码也可以工作Fragment
。DialogFragment和DataBinding是否有问题?
android kotlin android-databinding android-livedata android-viewmodel
因此 DataBinding 现在可以在其绑定中使用 LiveData。作为其中的一部分,我们还必须将生命周期设置为数据绑定,如下所示:
SampleLayoutBinding binding = DataBindingUtil.inflate(this, R.layout.sample_layout)
binding.setLifeCycleOwner(this)
Run Code Online (Sandbox Code Playgroud)
我的问题是在 recyclerview 中设置这个生命周期所有者的正确方法是什么?或者更恰当地说,在 recyclerview 中使用数据绑定时,我们是否需要设置 LifeCyclerOwner?
对于这个问题,我在 Github准备了一个简单而有效的例子:
我的示例应用程序使用 okhttp 下载一个包含游戏中前 30 名玩家的 JSON 数组,并将它们存储到 SQLite Room 中。在片段中,我观察相应的LiveData<List<TopEntity>>对象并更新 FastAdapter 实例:
public class TopFragment extends Fragment {
private final ItemAdapter<TopItem> mItemAdapter = new ItemAdapter<>();
private final FastAdapter<TopItem> mFastAdapter = FastAdapter.with(mItemAdapter);
private TopViewModel mViewModel;
private ProgressBar mProgressBar;
private RecyclerView mRecyclerView;
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
mViewModel = ViewModelProviders.of(this).get(TopViewModel.class);
mViewModel.getTops().observe(this, tops -> {
mItemAdapter.clear();
for (TopEntity top: tops) {
TopItem item = new TopItem(top);
mItemAdapter.add(item); …Run Code Online (Sandbox Code Playgroud) 我是 Kotlin 的初学者。我需要将一个可变参数从我的 Activity 发送到 Retrofit 调用。
这是我对创建细节活动的呼吁
override fun onCreate(savedInstanceState: Bundle?) {
//...
val id = intent.getStringExtra("id")
// Get the ViewMode
val mModel = ViewModelProviders.of(this).get(myObjectViewModel::class.java)
//Create the observer which updates the UI.
val myObjectByIdObserver = Observer<MyObject> { myObject->
//...
}
//Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
mModel.getObjectById.observe(this, myObjectByIdObserver)
}
Run Code Online (Sandbox Code Playgroud)
这里我插入值硬编码,我需要从上一个活动接收到的参数。
class MyObjectViewModel : ViewModel() {
//this is the data that we will fetch asynchronously
var myObject: MutableLiveData<MyObject>? = null
val getMyObjectById: LiveData<MyObject> …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用LiveData从Room数据库中分页数据。Google的示例代码表明使用了toLiveData函数:
class ConcertViewModel(concertDao: ConcertDao) : ViewModel() {
val concertList: LiveData<PagedList<Concert>> =
concertDao.concertsByDate().toLiveData(pageSize = 50)
}
Run Code Online (Sandbox Code Playgroud)
https://developer.android.com/topic/libraries/architecture/paging
这是我创建的遵循其示例的代码:
AppDao.kt
import androidx.lifecycle.LiveData
import androidx.paging.DataSource
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy.REPLACE
import androidx.room.Query
import com.example.model.UserConnection
@Dao
interface AppDao {
@Query("SELECT * FROM UserConnection")
fun getAll(): LiveData<List<UserConnection>>
@Insert(onConflict = REPLACE)
fun save(userConnection: UserConnection)
@Query("SELECT * FROM UserConnection ORDER BY firstName DESC")
fun connectionsByFirstName(): DataSource.Factory<Int, UserConnection>
}
Run Code Online (Sandbox Code Playgroud)
AppDatabase.kt
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.example.model.UserConnection
@Database(entities = arrayOf(UserConnection::class), version = 1, exportSchema = true) …Run Code Online (Sandbox Code Playgroud) 在我的项目中,我使用了一个稍微修改的存储库模式:
在我的存储库中,我使用公开的 LiveData<*> 字段来传达状态 - 例如,说 UserRepository 将有一个currentUser公共类型 LiveData的字段,私有的 MediatorLiveData,它将链接到一个私有字段,该字段包含要检索的当前用户 ID。
但是,addSource() {}由于某种原因,这些订阅(使用 MediatorLiveData 的方法)不会触发。
一个几乎 1:1 的例子(由于 NDA 替换了模型名称)如下:
abstract class BaseRepository: ViewModel(), KoinComponent {
val isLoading: LiveData<Boolean> = MutableLiveData<Boolean>().apply { postValue(false) }
}
class UserRepository: BaseRepository() {
private val client: IClient by inject() // Koin injection of API client
private val sharedPref: SharedPrefManager by inject() // custom wrapper …Run Code Online (Sandbox Code Playgroud) 这是我的依赖项:
//Room and Lifecycle Libraries
kapt "androidx.room:room-compiler:2.2.0-alpha02"
kapt 'androidx.room:room-compiler:2.2.0-alpha02'
kapt "androidx.lifecycle:lifecycle-compiler:2.2.0-alpha03"
implementation "androidx.room:room-runtime:2.2.0-alpha02"
implementation 'androidx.room:room-runtime:2.2.0-alpha02'
implementation "androidx.lifecycle:lifecycle-viewmodel:2.2.0-alpha03"
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0-alpha03"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-alpha03"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-alpha03"
implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
Run Code Online (Sandbox Code Playgroud)
如您所见,我实现了最终版本,但我无法访问 liveData 构建器。我怎样才能解决这个问题?
我正在使用导航底部与导航底部ViewModel内的所有片段共享,但它在第二次调用片段时抛出此异常
java.lang.IllegalArgumentException: Cannot add the same observer with different lifecycles
我试图让所有观察者都附加到活动而不是它的片段,如下所示
1-在fragemt中声明viewModel
viewModel = activity?.run {
ViewModelProviders.of(this,viewModelFactory).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
Run Code Online (Sandbox Code Playgroud)
2-观察者实时数据对象
viewModel.msg.observe(activity!!, Observer {
Log.i(TAG,it)
})
Run Code Online (Sandbox Code Playgroud)
3- 移除观察者
override fun onStop() {
super.onStop()
viewModel.msg.removeObservers(activity!!)
}
Run Code Online (Sandbox Code Playgroud)
这段代码对我来说工作正常,但我想知道我的代码是否正确并且可能工作?提前致谢
android-livedata ×10
android ×9
kotlin ×4
android-room ×3
viewmodel ×2
dao ×1
fastadapter ×1
java ×1
observable ×1
retrofit ×1