android - 如何从 ViewModel 中的 Fragment 访问 Android 数据
问题描述
我正在学习 Android 编程,但我不知道如何在 Fragment 和 ViewModel 之间共享数据。
我正在制作应用程序,该应用程序将在设置中包含IP 地址和IP 端口字段。
在起始页片段中,我创建了fillServerData()
将数据从设置加载到serverViewModel对象的函数。
我已经在 Fragment 中创建了 ViewModel 对象,它可以正常工作。我可以在任何片段中启动它:
serverViewModel = activity?.run {
ViewModelProvider(this).get(ServerObservableData::class.java)
} ?: throw Exception("Invalid Activity")
并使用 . 访问每个字段serverViewModel.ipAddress.value.toString()
。
我在访问 ViemModel.kt 中的数据时遇到问题,我无法使用
activity?.run {
ViewModelProvider(this).get(ServerObservableData::class.java)
} ?: throw Exception("Invalid Activity")
我的问题是 - 我如何访问serverViewModel
片段外的数据?有什么方法可以在 ViewModel 中创建可以读取数据的对象?我可以使用使用数据绑定吗?
编辑:
我希望我的应用程序连接到服务器,以便它可以检索数据。
我创建了设置片段,用户将在哪里填写服务器、端口、用户名和密码数据。
我创建了 class: ServerObservableData : ViewModel()
,并且在我的起始页片段上有 function fillServerData()
,它将用于SharedPreferences
收集值并将它们传递给serverViewModel
对象。这很好用。我可以从serverViewModel
任何片段中获取数据。我只需要使用以下方法对其进行初始化:
serverViewModel = activity?.run {
ViewModelProvider(this).get(ServerObservableData::class.java)
} ?: throw Exception("Invalid Activity")
我的问题是serverViewModel
存储在对象中的数据SharedPreferences
,我需要在 ViewModel 中使用,而不是 Fragment。如何将它们从 Fragment 传递到 ViewModel?
Kamal Nayan 的建议对我来说是可以的,但由于某种原因程序崩溃并且消息是:
UninitializedPropertyAccessException:lateinit 属性 serverViewModel 尚未初始化
但是当我放置Log.i()
函数以便跟踪正在发生的事情时,会调用 onCreate(),并且serverViewModel
对象的初始化在该函数中。所以程序不应该崩溃,因为onCreate()
之前已经调用过get()
。
编辑二:
这是 DocumentsFragment.kt 中的代码:
class DocumentsFragment : Fragment() {
private lateinit var serverViewModel: ServerObservableData
private val viewModel: DocumentsViewModel by lazy {
ViewModelProvider(this).get(DocumentsViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
serverViewModel = activity?.run {
ViewModelProvider(this).get(ServerObservableData::class.java)
} ?: throw Exception("Invalid Activity")
Log.i("DocumentsFragment", "onCreate")
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding: FragmentDocumentsBinding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_documents,
container,
false
)
binding.lifecycleOwner = this
binding.documentViewModel = viewModel
return binding.root
}
fun getHttp(): String {
Log.i("getHTTP", "RETURN")
// THIS IS WHERE PROGRAM CRASHES, WHEN RETURN IS CALLED
// ...serverViewModel has not been initialized
return serverViewModel.ipAddress.value.toString()
}
fun getIP(): String {
return serverViewModel.ipPort.value.toString()
}
}
DocumentsViewModel.kt 中的代码
class DocumentsViewModel : ViewModel() {
private val _response = MutableLiveData<String>()
val response: LiveData<String>
get() = _response
init {
Log.i("ViewModel", "ViewModel INIT")
testConnection()
}
private fun testConnection() {
var baseUrl = "http://${DocumentsFragment().getHttp()}:${DocumentsFragment().getIP()}/rest/out"
val orgInfo = RequestBody(
user = "test",
request = "x",
signature = "x",
requestJson = "x"
)
viewModelScope.launch {
try {
val listResult =
ElementApi.retrofitService.sendRequest(baseUrl, orgInfo)
_response.value = "Success."
} catch (e: Exception) {
_response.value = "Failure: ${e.message.toString()}"
}
}
}
}
解决方案
** 我不是 Kotlin 人。** 但是我在 java 中使用 setter 和 getter,比如在 viewModel 中创建一个变量并创建它的 getter 和 setter。并使用 getter 从 ViewModel 外部(例如在片段中)访问该变量数据,并使用 setter 从 viewModel 外部设置 viewModel 内部变量的值。
推荐阅读
- asp.net - ASP.NET 将所有请求重定向到单个页面并重写 url,因此页面似乎位于根目录中
- android - 谷歌的新地方图书馆(实施'com.google.android.libraries.places:1.0.0')没有解决
- php - 安装 PHP MySQLi 扩展只创建 .ini 文件并且找不到 MySQLi.so 模块
- r - 一个条形图在条形图中放错了位置(ggplot2)
- angular - 使用 Angular 7 迭代 HTML 标签?(动态)
- google-chrome - 使用 Google Chrome Headless 模式强制执行屏幕截图分辨率
- walmart-api - 如何获取 Walmart API 的 API 密钥?似乎没有任何工作
- javascript - window.addEventListener 代码在移动设备上不起作用
- javascript - 一些图像逆时针旋转 90 度
- ruby-on-rails - 在 Rails 中初始化数据库行?