限制一个应用程序一段时间 Kotlin
Restrict an application for some time Kotlin
我正在实现一个功能,当用户输入错误代码超过 5 次时,该功能会限制应用程序 10 分钟。我已经实现了在重新启动应用程序时不初始化计时器。当他们重新启动应用程序时,他们无法单击任何按钮,但可以看到一个持续 10 分钟的对话框。知道要使用哪个功能或者简单地解释一下我就可以了。
非常感谢所有帮助。
I have tried
我将开始时间存储在 sharedPreference
中并从 System.currentTimeMillis
中减去它。因此,当结果超过 600000(10 分钟)时,他们终于可以开始使用该应用程序了。
My question
- 我想知道如何在我的代码中重新启动应用程序时继续显示对话框。
My fragment
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()
}
}
这是实现此目的的一种策略。我假设您希望此错误状态持续存在,即使用户关闭并重新打开应用程序也是如此,因此计数和时间都需要持续存在。
此处的策略是处理视图模型中的大部分逻辑,以跟踪状态并将其持久化。在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() }
}
我正在实现一个功能,当用户输入错误代码超过 5 次时,该功能会限制应用程序 10 分钟。我已经实现了在重新启动应用程序时不初始化计时器。当他们重新启动应用程序时,他们无法单击任何按钮,但可以看到一个持续 10 分钟的对话框。知道要使用哪个功能或者简单地解释一下我就可以了。 非常感谢所有帮助。
I have tried
我将开始时间存储在 sharedPreference
中并从 System.currentTimeMillis
中减去它。因此,当结果超过 600000(10 分钟)时,他们终于可以开始使用该应用程序了。
My question
- 我想知道如何在我的代码中重新启动应用程序时继续显示对话框。
My fragment
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()
}
}
这是实现此目的的一种策略。我假设您希望此错误状态持续存在,即使用户关闭并重新打开应用程序也是如此,因此计数和时间都需要持续存在。
此处的策略是处理视图模型中的大部分逻辑,以跟踪状态并将其持久化。在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() }
}