跳转至Fragment时如何取消Main Activity中的进度条?
解决方案
核心问题分析
你当前的代码里,点击按钮后直接提交Fragment事务,但commit()是异步执行的——主线程不会等待Fragment完全创建/初始化完成就继续执行后续逻辑,导致进度条没有被自动隐藏,会持续旋转。另外日志D/eglCodecCommon: setVertexArrayObject是因为进度条显示时,GPU一直在渲染它的旋转动画;启用广告时会叠加渲染操作,让日志量更明显,本质还是进度条未隐藏的问题。
具体解决方法
要让进度条在Fragment准备好(或后台任务完成)后自动隐藏,需要实现Fragment与Activity的状态通信,以下是两种常用方案:
方案一:接口回调
- 定义回调接口,用于通知Activity Fragment已准备完成
interface OnFragmentReadyListener { fun onFragmentReady() }
- 在Activity中实现接口,处理进度条隐藏逻辑
class MainActivity : AppCompatActivity(), OnFragmentReadyListener { private lateinit var binding: ActivityMainBinding private val MAIN_ACTIVITY_TAG = "MainActivity" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.slowButton.setOnClickListener { binding.pBar.visibility = View.VISIBLE binding.mainActFields.visibility = View.GONE supportFragmentManager.beginTransaction() .replace(R.id.MainFragment, MainFragment()) .commit() Log.i(MAIN_ACTIVITY_TAG, "Clicked") } } // 实现接口方法,隐藏进度条 override fun onFragmentReady() { binding.pBar.visibility = View.GONE // 可选:恢复原界面控件显示 // binding.mainActFields.visibility = View.VISIBLE } }
- 在Fragment的合适时机调用回调
class MainFragment : Fragment() { private var listener: OnFragmentReadyListener? = null // 绑定Activity时获取回调实例 override fun onAttach(context: Context) { super.onAttach(context) if (context is OnFragmentReadyListener) { listener = context } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 如果Fragment包含网络请求等后台任务,需等待任务完成后再调用 // 示例:网络请求成功后触发 // yourApiCall.enqueue(object : Callback<YourData> { // override fun onResponse(call: Call<YourData>, response: Response<YourData>) { // listener?.onFragmentReady() // } // override fun onFailure(call: Call<YourData>, t: Throwable) { // listener?.onFragmentReady() // 失败也需隐藏进度条 // } // }) // 无后台任务时,Fragment加载完成即触发 listener?.onFragmentReady() } // 解除绑定时清空回调,避免内存泄漏 override fun onDetach() { super.onDetach() listener = null } }
方案二:共享ViewModel(适合复杂场景)
通过ViewModel在Activity和Fragment之间共享加载状态,避免接口耦合:
- 创建共享ViewModel
class MainViewModel : ViewModel() { // 标记是否处于加载状态 val isLoading = MutableLiveData<Boolean>() }
- 在Activity中观察状态变化,自动更新UI
class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding private lateinit var viewModel: MainViewModel private val MAIN_ACTIVITY_TAG = "MainActivity" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // 初始化ViewModel viewModel = ViewModelProvider(this)[MainViewModel::class.java] // 观察加载状态,自动更新进度条和界面 viewModel.isLoading.observe(this) { isLoading -> binding.pBar.visibility = if (isLoading) View.VISIBLE else View.GONE binding.mainActFields.visibility = if (isLoading) View.GONE else View.VISIBLE } binding.slowButton.setOnClickListener { viewModel.isLoading.value = true supportFragmentManager.beginTransaction() .replace(R.id.MainFragment, MainFragment()) .commit() Log.i(MAIN_ACTIVITY_TAG, "Clicked") } } }
- 在Fragment中更新加载状态
class MainFragment : Fragment() { private lateinit var viewModel: MainViewModel override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 获取与Activity共享的ViewModel实例 viewModel = ViewModelProvider(requireActivity())[MainViewModel::class.java] // 后台任务完成后更新状态 // 示例:网络请求完成 // yourApiCall.enqueue(object : Callback<YourData> { // override fun onResponse(call: Call<YourData>, response: Response<YourData>) { // viewModel.isLoading.value = false // } // override fun onFailure(call: Call<YourData>, t: Throwable) { // viewModel.isLoading.value = false // } // }) // 无后台任务时,Fragment加载完成即更新状态 viewModel.isLoading.value = false } }
关键注意点
- 如果Fragment包含网络请求、数据库操作等后台任务,必须等任务完成后再触发进度条隐藏,而非Fragment一创建就隐藏,这样才符合你“让用户感知后台任务处理”的需求。
- 进度条隐藏后,
D/eglCodecCommon: setVertexArrayObject日志会自动消失,因为GPU不再渲染进度条的旋转动画。
内容的提问来源于stack exchange,提问作者kotlining
相关产品推荐
相关产品推荐

