我正在實作一個功能,當用戶輸入錯誤代碼超過 5 次時,該功能將應用程式限制 10 分鐘。我已經實作了在他們重新啟動應用程式時不初始化計時器。當他們重新啟動應用程式時,他們無法單擊任何按鈕,但可以看到 10 分鐘的對話框。知道要使用哪個功能或者簡單解釋一下也沒關系。所有幫助將不勝感激。
我努力了
我將開始時間存盤在 中sharedPreference并從中減去System.currentTimeMillis。因此,當結果超過 600000(10 分鐘)時,他們終于可以開始使用該應用程式了。
我的問題
- 我想知道在我的代碼中重新啟動應用程式時如何繼續顯示對話框。
我的片段
private lateinit var binding : FragmentHelpBinding
private lateinit var viewModel : HelpViewModel
private lateinit var mContext: MainActivity
override fun onAttach(context: Context) {
super.onAttach(context)
mContext = context as MainActivity
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_help, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProvider(this).get(HelpViewModel::class.java)
binding.viewModel = viewModel
otpTimeLimit()
}
private fun otpTimeLimit() = runBlocking {
val currentTime = System.currentTimeMillis()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
var startTime = currentTime
var pref: SharedPreferences? = requireContext().getSharedPreferences("otpTrialLimit", MODE_PRIVATE)
pref?.edit()?.putLong("startTime", startTime)
pref?.edit()?.commit()
if (System.currentTimeMillis() - startTime <600000) {
// dialog will show up here and should last for 10 min
clickDialog()
}else if (System.currentTimeMillis() - startTime >=600000) {
// and when 10 minutes passed, it should dismiss
}
}
private fun clickDialog() {
val layoutInflater = LayoutInflater.from(context)
val view = layoutInflater.inflate(R.layout.help_dialog, null)
var alertDialog = AlertDialog.Builder(requireContext(), R.style.CustomAlertDialog)
.setView(view)
.create()
val titleText : TextView = view.findViewById(R.id.title_text_dialog)
val contentText : TextView = view.findViewById(R.id.content_text_dialog)
binding.btnGoSearch.setOnClickListener {
titleText.text = getString(R.string.help_notification)
contentText.text = getString(R.string.notification_content)
alertDialog.show()
}
}
uj5u.com熱心網友回復:
這是這樣做的一種策略。我假設即使用戶關閉并重新打開應用程式,您也希望此錯誤狀態持續存在,因此計數和時間都需要持續存在。
這里的策略是處理視圖模型中的大部分邏輯以跟蹤狀態并保持它。在 Fragment 中,您只需要觀察實時資料:如果需要,在鎖定狀態時顯示對話框,如果對話框打開,則在狀態轉換為未鎖定時隱藏對話框。
視圖模型:
class HelpViewModel(application: Application): AndroidViewModel(application) {
companion object {
private const val SHARED_PREFS_NAME = "HelpViewModelPrefs"
private const val KEY_LOCKOUT_START_TIME = "lockoutStartTime"
private const val KEY_ERROR_COUNT = "errorCount"
private const val LOCKOUT_DURATION_MILLIS = 60_000L
}
private val sharedPrefs = application.applicationContext.getSharedPreferences(
SHARED_PREFS_NAME, Context.MODE_PRIVATE
)
private val _isErrorState = MutableLiveData<Boolean>()
val isErrorState: LiveData<Boolean> get() = _isErrorState
// Set up this property so it automatically persists and is initialized
// with any previously persisted value.
private var errorCount: Int = sharedPreferences.getInt(KEY_ERROR_COUNT, 0)
set(value) {
field = value
sharedPreferences.edit {
putInt(KEY_ERROR_COUNT, value)
}
}
init {
// Figure out if we are already locked out and set state appropriately.
// If we are locked out, schedule when to end locked out state.
val lockoutStartTime = sharedPrefs.getLong(KEY_LOCKOUT_START_TIME, 0)
val lockoutEndTime = lockoutStartTime LOCKOUT_DURATION_MILLIS
val now = System.currentTimeMillis()
if (now < lockoutEndTime) {
isErrorState.value = true
viewModelScope.launch {
delay(lockoutEndTime - now)
isErrorState.value = false
}
} else {
isErrorState.value = false
}
}
// call when the user performs an error
fun incrementErrorCount() {
errorCount
if (errorCount >= 5) {
// Reset count, initiate lockout state, and schedule end of state
errorCount = 0
sharedPrefs.edit {
putLong(KEY_LOCKOUT_START_TIME, System.currentTimeMillis())
}
isErrorState.value = true
viewModelScope.launch {
delay(LOCKOUT_DURATION_MILLIS)
isErrorState.value = false
}
}
}
}
在片段中,我們通過觀察實時資料來處理狀態。我們保留對任何當前打開的對話框的參考,因此如果在打開時狀態轉換,我們可以自動關閉它。當 Fragment 被銷毀時,我們會將參考清空,因此我們不會泄漏它們。
private var lockoutDialog: AlertDialog? = null
private val viewModel: HelpViewModel by viewModels()
private var shouldShowLockoutDialog = false
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// ...
viewModel.isErrorState.observe(viewLifecycleOwner) { isErrorState ->
shouldShowLockoutDialog = isErrorState
if (!isErrorState) {
lockoutDialog?.dismiss()
}
}
binding.btnGoSearch.setOnClickListener {
if (shouldShowLockoutDialog) {
showLockoutDialog()
} else {
// TODO some behavior when not locked out
}
}
}
private fun showLockoutDialog() {
val layoutInflater = LayoutInflater.from(requireContext())
val view = layoutInflater.inflate(R.layout.help_dialog, null).apply {
findViewById<TextView>(R.id.title_text_dialog).text =
requireContext.getString(R.string.help_notification)
findViewById<TextView>(R.id.content_text_dialog).text =
requireContext.getString(R.string.notification_content)
}
lockoutDialog = AlertDialog.Builder(
requireContext(),
R.style.CustomAlertDialog
)
.setView(view)
.setOnDismissListener { lockoutDialog = null }
.create()
.also { it.show() }
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/454451.html
