android - 使用 viewModel 处理屏幕旋转而不丢失数据 - Android
问题描述
我有一个未指定方向的活动,并且该活动附加了一个片段,该片段具有纵向和横向模式的不同布局,并且在该片段上,有条件地进行了多个API调用,我的问题是当屏幕旋转时,所有数据都丢失了并且该片段上有很多数据,我不想将每个数据保存在 saveInstance 方法上。我试过android:configChanges="keyboardHidden|orientation|screenSize"
了,但这并没有解决我的问题。我想使用 viewModel 处理这个问题。请帮助,在此先感谢。这是我的代码
存储库
class GetDataRepository {
val TAG = GetDataRepository::class.java.canonicalName
var job: CompletableJob = Job()
fun getData(
token: String?,
sslContext: SSLContext,
matchId: Int
): LiveData<ResponseModel> {
job = Job()
return object : LiveData<ResponseModel>() {
override fun onActive() {
super.onActive()
job.let { thejob ->
CoroutineScope(thejob).launch {
try {
val apiResponse = ApiService(sslContext).getData(
token
)
LogUtil.debugLog(TAG, "apiResponse ${apiResponse}")
withContext(Dispatchers.Main) {
value = apiResponse
}
} catch (e: Throwable) {
LogUtil.errorLog(TAG, "error: ${e.message}")
withContext(Dispatchers.Main) {
when (e) {
is HttpException -> {
value =
Gson().fromJson<ResponseModel>(
(e as HttpException).response()?.errorBody()
?.string(),
ResponseModel::class.java
)
}
else -> value = ResponseModel(error = e)
}
}
} finally {
thejob.complete()
}
}
}
}
}
}
fun cancelJob() {
job.cancel()
}
}
视图模式:
class DataViewModel : ViewModel() {
val TAG = DataViewModel::class.java.canonicalName
var mListener: DataListener? = null
private val mGetDataRepository: GetDataRepository = GetDataRepository()
fun getData() {
LogUtil.debugLog(TAG, "getData")
if (mListener?.isInternetAvailable()!!) {
mListener?.onStartAPI()
val context = mListener?.getContext()
val token: String? = String.format(
context?.resources!!.getString(R.string.user_token),
PreferenceUtil.getUserData(context).token
)
val sslContext = mListener?.getSSlContext()
if (sslContext != null) {
val getData =
mGetDataRepository.getData(
token
)
LogUtil.debugLog(TAG, "getData ${getData}")
mListener?.onApiCall(getData)
} else {
LogUtil.debugLog(TAG, "getData Invalid certificate")
mListener?.onError("Invalid certificate")
}
} else {
LogUtil.debugLog(TAG, "getData No internet")
mListener?.onError("Please check your internet connectivity!!!")
}
LogUtil.debugLog(TAG, "Exit getData()")
}
}
活动:
class DataActivity : AppCompatActivity() {
val TAG = DataActivity::class.java.canonicalName
lateinit var fragment: DataFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
LogUtil.debugLog(TAG, "onCreate: Enter")
var binding: ActivityDataBinding =
DataBindingUtil.setContentView(this, R.layout.activity_data)
if (savedInstanceState == null) {
fragment = DataFragment.newInstance()
supportFragmentManager.beginTransaction().add(R.id.container, fragment, DataFragment.TAG)
} else {
fragment = supportFragmentManager.findFragmentByTag(DataFragment.TAG) as DataFragment
}
LogUtil.debugLog(TAG, "onCreate: Exit")
}
}
分段:
class DataFragment : Fragment(), DataListener {
private var mBinding: FragmentDataBinding? = null
private lateinit var mViewModel: DataViewModel
companion object {
val TAG = DataFragment::class.java.canonicalName
fun newInstance(): DataFragment {
return DataFragment()
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mBinding =
DataBindingUtil.inflate(inflater, R.layout.fragment_data, container, false)
mViewModel = ViewModelProvider(this).get(DataViewModel::class.java)
mViewModel.mListener = this
getData()
return mBinding?.root
}
private fun getData() {
LogUtil.debugLog(TAG, "Enter getMatchScore()")
mViewModel.getData()
LogUtil.debugLog(TAG, "Exit getMatchScore()")
}
override fun <T> onApiCall(response: LiveData<T>) {
response.observe(this, Observer {
it as DataResponseModel
//
})
}
}
解决方案
默认情况下 viewModel 的生命周期比您的活动长(在您的情况下,屏幕旋转)。
ViewModel 不会因为配置更改而销毁,您可以查看此链接。
您似乎在活动/片段的其他地方犯了错误,请将您的活动/片段代码放在这里。
在您的片段中,您在 onCreateView 中调用 mViewModel.getData(),每次旋转活动时,此方法调用和所有存储数据都会重置并再次获取!您只需检查片段中 ViewModel 的数据,如果它是空调用getData(),看起来你的 ViewModel 引用你的 view(Fragment) (你将一个监听器从你的 Fragment 传递给你的 ViewModel),它也是一种反模式(推荐这篇文章)
推荐阅读
- .htaccess - 将任何域从非 www 重定向到 www 和 HTTPS,无需双重重定向
- java - Java 8 转换地图
> 到地图 > - java - 如何通过 Java 套接字(Java 网络)发送对象并读取它
- java - 使用for循环在休眠中保存多条记录
- javascript - 未使用 Ajax 将 PHP 记录插入数据库
- php - PhpMailer 不使用 html
- uitableview - 表格视图中每一行的列内按钮
- c# - EF Core 2.1.1 此平台不支持分布式事务
- mongodb - MongoDB推送到数组
- jsf - 带有限定符 @Bundle 的类型 ResourceBundle 的依赖关系不满足