Android Studio中保存条款同意状态为偏好设置后功能失效求助
我正在为APP实现“条款与条件”页面,首次打开APP时弹出,用户同意后进入主应用,拒绝则关闭APP。页面用ScrollView包含TextView和两个按钮,滚动到底部才启用按钮。但添加SharedPreferences相关代码后,所有功能都失效了,之前按钮的启用/禁用逻辑和点击事件都正常。
原代码
package com.example.termsandconditionsview import android.content.Context import android.content.SharedPreferences import android.os.Bundle import android.view.MotionEvent import android.view.View import android.view.ViewTreeObserver import android.widget.Button import android.widget.ScrollView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity class MainActivity : AppCompatActivity(), View.OnTouchListener, ViewTreeObserver.OnScrollChangedListener { private var svMain: ScrollView? = null private lateinit var buttonAccept: Button private lateinit var buttonDecline: Button private lateinit var sharedPref: SharedPreferences override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.terms_and_conditions_view) svMain = findViewById(R.id.scrollView2) svMain?.viewTreeObserver?.addOnScrollChangedListener(this) buttonAccept = findViewById(R.id.button_accept) buttonDecline = findViewById(R.id.button_decline) sharedPref = getSharedPreferences("myAppPrefs", Context.MODE_PRIVATE) val termsAccepted = sharedPref.getBoolean("terms_accepted", false) if (termsAccepted) { setContentView(R.layout.activity_main) } else { setContentView(R.layout.terms_and_conditions_view) } } override fun onScrollChanged() { svMain?.let { scrollView -> val view = scrollView.getChildAt(scrollView.childCount - 1) as View val bottomDetector = view.bottom - (scrollView.height + scrollView.scrollY) if (bottomDetector <= 0) { buttonAccept.isEnabled = true buttonDecline.isEnabled = true } else { buttonAccept.isEnabled = false buttonDecline.isEnabled = false } buttonAccept.setOnClickListener { // Update the termsAccepted value to true in SharedPreferences val editor = sharedPref.edit() editor.putBoolean("terms_accepted", true) editor.apply() val textAcceptTac = getString(R.string.txt_accept_tac) val duration = Toast.LENGTH_LONG val toastAccept = Toast.makeText(this, textAcceptTac, duration) toastAccept.show() setContentView(R.layout.activity_main) // Proceed with the app as the user has accepted the terms&conditions } buttonDecline.setOnClickListener{ val textDeclineTac = getString(R.string.txt_decline_tac) val duration = Toast.LENGTH_LONG val toastDecline = Toast.makeText(this, textDeclineTac, duration) toastDecline.show() // Close app when user clicks the "Decline" button. finish() } } } override fun onTouch(p0: View?, p1: MotionEvent?): Boolean { TODO("Not yet implemented") } }
问题根源
你在onCreate里先调用了一次setContentView(R.layout.terms_and_conditions_view)并初始化控件,但之后又根据termsAccepted的值再次调用setContentView,这会导致之前初始化的svMain、buttonAccept等控件引用完全失效——新布局加载后,原来的控件对象和当前界面的控件已经没有关联了。另外,你在onScrollChanged里重复设置按钮点击事件,每次滚动都会绑定一次,也会导致逻辑混乱。
修复方案
1. 调整布局加载逻辑,避免重复加载
先判断偏好设置,再加载对应布局,之后再初始化控件:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) sharedPref = getSharedPreferences("myAppPrefs", Context.MODE_PRIVATE) val termsAccepted = sharedPref.getBoolean("terms_accepted", false) // 先判断状态再加载布局,避免重复加载导致控件引用失效 if (termsAccepted) { setContentView(R.layout.activity_main) } else { setContentView(R.layout.terms_and_conditions_view) // 只有加载条款页面时才初始化相关控件和监听器 svMain = findViewById(R.id.scrollView2) svMain?.viewTreeObserver?.addOnScrollChangedListener(this) buttonAccept = findViewById(R.id.button_accept) buttonDecline = findViewById(R.id.button_decline) // 单独设置按钮点击事件 setupButtonListeners() } }
2. 提取按钮点击事件到单独方法
避免在滚动回调里重复绑定事件:
private fun setupButtonListeners() { buttonAccept.setOnClickListener { val editor = sharedPref.edit() editor.putBoolean("terms_accepted", true) editor.apply() Toast.makeText(this, getString(R.string.txt_accept_tac), Toast.LENGTH_LONG).show() setContentView(R.layout.activity_main) } buttonDecline.setOnClickListener { Toast.makeText(this, getString(R.string.txt_decline_tac), Toast.LENGTH_LONG).show() finish() } }
3. 简化滚动回调逻辑
只保留按钮启用/禁用的判断,移除事件绑定:
override fun onScrollChanged() { svMain?.let { scrollView -> val view = scrollView.getChildAt(scrollView.childCount - 1) as View val bottomDetector = view.bottom - (scrollView.height + scrollView.scrollY) // 简化判断逻辑 val isAtBottom = bottomDetector <= 0 buttonAccept.isEnabled = isAtBottom buttonDecline.isEnabled = isAtBottom } }
4. 移除无用接口实现
你没有实现OnTouchListener的onTouch方法,还抛出了TODO异常,直接删掉这个接口和对应的方法:
// 修改类声明,去掉View.OnTouchListener class MainActivity : AppCompatActivity(), ViewTreeObserver.OnScrollChangedListener { // ... 其他代码不变 }
额外建议
- 尽量避免在同一个Activity中多次调用
setContentView,可以考虑拆分出TermsActivity专门承载条款页面,逻辑会更清晰易维护。 - 存储偏好设置时,
apply()是异步提交,commit()是同步提交,这里使用apply()完全没问题。
内容的提问来源于stack exchange,提问作者Belial
相关产品推荐
相关产品推荐

