使用ViewModel处理屏幕旋转而不会丢失数据-Android

时间:2020-07-02 15:55:34

标签: android kotlin mvvm android-livedata kotlin-coroutines

我有一个活动的方向不确定,并且有一个与该活动相关的片段具有不同的纵向和横向模式布局,并且在该片段上有条件地调用了多个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()
}

}

ViewMode:

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
        //
    })

}

}

1 个答案:

答案 0 :(得分:0)

默认情况下,viewModel的生命周期长于您的活动(在您的情况下为屏幕旋转)。

只要为配置更改而取消活动,ViewModel就不会被销毁,您可以看到此link

您似乎在活动/片段中的其他地方犯了一个错误,请在此处输入您的活动/片段代码。

在片段中,您可以在onCreateView中调用mViewModel.getData(),并且每次旋转活动时,此方法调用以及所有存储数据都将重置并再次获取!,您只需检查片段中ViewModel的数据,是否它是一个空调用getData(),似乎您的ViewModel对您的view(Fragment)的引用(将侦听器从您的片段传递到ViewModel),并且它也是一个反模式(建议使用此article)< / p>