视图模型中字段的推荐模式似乎是:
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
Run Code Online (Sandbox Code Playgroud)
(顺便说一句,该selected字段不是私有的,这是正确的吗?)
但是如果我不需要订阅 ViewModel 字段中的更改怎么办?我只需要被动地将这个值拉到另一个片段中。
我的项目详细信息:
视图模型:
private var amount = 0
fun setAmount(value: Int) { amount = value}
fun getAmount() = amount
Run Code Online (Sandbox Code Playgroud)
片段1:
bnd.button10.setOnClickListener { viewModel.setAmount(10) }
Run Code Online (Sandbox Code Playgroud)
片段2:
if(viewModel.getAmount() < 20) { bnd.textView.text = "less than 20" }
Run Code Online (Sandbox Code Playgroud)
这是一种有效的方法吗?或者有更好的吗?或者我应该只使用 LiveData 或 Flow?
也许我应该使用SavedStateHandle?它可以注入到 ViewModel 中吗?
MutableLiveData<MutableList<object>>在我拥有并且想要创建的ViewModel 中LiveData<List<object>>,但我不知道如何List从MutableList.
这是我想做的:
class AppViewModel : ViewModel() {
private val _tasks = MutableLiveData<MutableList<Task>>(mutableListOf())
val tasks: LiveData<List<Task>> = _tasks
}
Run Code Online (Sandbox Code Playgroud)
(但我收到错误类型不匹配。必需:LiveData<List> 发现:MutableLiveData<MutableList>)
当我将其更改val tasks: LiveData<List<Task>> = _tasks为val tasks: LiveData<MutableList<Task>> = _tasks它时,它可以工作,但我希望List任务中的任务不可编辑。
我们知道StateFlow和SharedFlow很热门。
\n\n\nStateFlow 是一个热流\xe2\x80\x94,只要该流被收集\n或者垃圾收集根中存在对其的任何其他引用,它就会保留在内存中。
\n
\n\nSharedFlow 是一个热流,它向所有从其收集的使用者发送值。\n
\n
水流本身是冷的。
\n\n\n流是类似于序列的冷流......
\n
我有一个问题无法找到直接答案。LiveData 是热的还是冷的?
\nandroid android-livedata kotlin-flow kotlin-stateflow kotlin-sharedflow
我希望当我按下按钮并将其写入textview. 然而,下面的代码将增加的值显示为 Log 但在屏幕上, in 的值textview没有改变。我不确定出了什么问题。如果您知道,请告诉我。
片段.kt
class SettingFragment : Fragment(), View.OnClickListener {
companion object {
fun newInstance() = SettingFragment()
private val TAG = "SettingFragment"
}
private lateinit var viewModel: SettingViewModel
private lateinit var binding: FragmentSettingBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_setting, container, false)
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProvider(this).get(SettingViewModel::class.java)
binding.lifecycleOwner = this
binding.button.setOnClickListener(this)
}
override fun onClick(v: View?) { …Run Code Online (Sandbox Code Playgroud) data-binding android kotlin android-databinding android-livedata
应该在哪些地方by lazy使用?
为什么要使用它?
如何让代码变得更好
例如:
val currentResult: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
Run Code Online (Sandbox Code Playgroud) 我用于保存用户登录数据的 ViewModel 遇到问题。
用户登录后,我使用片段 A 中的用户数据更新此 ViewModel,但是当我尝试访问片段 B 中的数据时,我刚刚设置的数据字段始终为空。
当片段 B 初始化时,userLiveData 字段最初不会被观察到,但是,当我user从片段 B 触发对对象的更改时,会在片段 B 中正确观察到更改。看来我的 ViewModel 中字段的先前值永远不会到达片段B,但是新的价值观可以。
为了进行完整性检查,我创建了一个简单的字符串变量(甚至不是 LiveData 对象),将其设置为片段 A 中的值,然后,在导航到片段 BI 后打印该值:它每次都未初始化。就好像我注入到片段 B 中的 ViewModel 与我注入到片段 A 中的 ViewModel 完全分开。
我缺少什么导致片段 B 中的 ViewModel 观察最初不使用user片段 A 中设置的最后一个已知值触发?
片段A
class FragmentA : Fragment() {
private val viewModel: LoginViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.user.observe(this, {
it?.let {
//Called successfully every time
navigateToFragmentB()
}
})
val mockUserData = User() …Run Code Online (Sandbox Code Playgroud) android mvvm android-fragments android-livedata android-viewmodel
我刚刚开始玩LiveData。我按照官方 Android文档导入不同的工件。一切都很好,直到我需要将其转换Observable为LiveData. 但LiveDataReactiveStreams没有找到。最终我减少了版本号,当我达到2.5.1时,我很惊讶它终于起作用了。
我做错什么了吗?还是谷歌方面有问题?
我找不到任何与此相关的报告问题。但我真的不知道我能做些什么不同的事情......
我尝试手动导入它。然后我用了android.arch.lifecycle.LiveDataReactiveStreams. 这确实有效,但我应该坚持下去,并将所有内容更改androidx为android.arch不是真正的解决方案。
我正在研究Android架构组件,我有点困惑.在示例中,他们使用存储库并声明ViewModel观察到存储库的数据源内的更改.我不明白数据源中的更改是如何推送到ViewModel的,因为我看不到ViewModel中的任何代码将它们订阅到存储库.类似地,片段观察ViewModel的LiveData,但它们实际上订阅了LiveData:
// Observe product data
model.getObservableProduct().observe(this, new Observer<ProductEntity>() {
@Override
public void onChanged(@Nullable ProductEntity productEntity) {
model.setProduct(productEntity);
}
});
Run Code Online (Sandbox Code Playgroud)
我在ViewModels中看不到任何类型的订阅来观察存储库.我错过了什么吗?
android mvvm viewmodel android-livedata android-architecture-components
我的本地单元测试始终使用LiveData。通常,当您尝试在MutableLiveData上设置值时,会得到
java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked.
Run Code Online (Sandbox Code Playgroud)
因为本地JVM无法访问Android框架。我使用以下方法修复了该问题:
@get:Rule
val rule = InstantTaskExecutorRule()
Run Code Online (Sandbox Code Playgroud)
一切都很好,直到我不得不使用PowerMockito模拟来自Google Play库的静态方法。自从我添加
@RunWith(PowerMockRunner::class)
@PrepareForTest(Tasks::class)
Run Code Online (Sandbox Code Playgroud)
在我的测试类声明之上,我开始再次得到这个Looper not模拟错误。我之前在MockitoJUnitRunner中使用了此规则,一切都很好。
我的一个片段具有一个AndroidViewModel,其中包含一个LiveData列表,而另一个LiveData列表的选定项具有另一个属性。以下是我正在谈论的示例:
class TeamViewModel(app: Application): AndroidViewMode(app) {
...
val selectedTeam = MutableLiveData<Team>()
val allTeams: LiveData<List<Team>>
get() = repository.getAllTeams().toLiveData()
val allPlayers: LiveData<List<Player>>
get() = repository.getAllPlayers().toLiveData()
...
}
Run Code Online (Sandbox Code Playgroud)
注意:并返回一个RxJava Flowable List,然后我通过`.toLiveData将其转换为LiveData List getAllTeamsgetAllPlayers
目前,allPlayers代表所有团队的所有球员。我想这样做,以便每当selectedTeam更改值时,它allPlayers就会被过滤掉,只显示来自的玩家selectedTeam。
我尝试过的是allPlayers像这样直接过滤:
val allPlayers: LiveData<List<Player>>
get() = repository.getAllPlayers()
.flatMap { list -> Flowable.fromIterable(list)
.filter {
player -> player.team == selectedTeam.value?.team
}
}
.toList()
.toFlowable()
.toLiveData()
Run Code Online (Sandbox Code Playgroud)
但是,您可能会猜到也可能不会猜到,allPlayers无论何时selectedTeam发生更改,它都不会更新过滤器。
反正是有动态改变过滤器allPlayers,只要selectedTeam改变?
编辑
感谢@EpicPandaForce,我得出的最终解决方案如下: …
android ×10
android-livedata ×10
kotlin ×5
mvvm ×2
viewmodel ×2
android-architecture-components ×1
data-binding ×1
kotlin-flow ×1
list ×1
mutablelist ×1
powermockito ×1
rx-java ×1