You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何注册回调函数通知所有Fragment操作完成?Web服务登录场景适配

嘿,这个场景我太熟了!之前做项目的时候也遇到过类似的问题——Fragment加载数据时登录还没完成,得等登录结束再触发请求。给你两个实用的方案,都是Android开发里常用的解决思路:

方案一:自定义回调接口 + 单例类管理回调列表

这是最直接的原生实现方式,完全贴合你当前的单例认证类场景:

1. 定义登录状态回调接口

先写一个接口,用来规范登录完成后的回调行为:

// 如果用Java,换成Java接口语法即可
interface LoginStatusCallback {
    fun onLoginCompleted(isSuccess: Boolean, message: String?)
}

2. 在认证单例类里维护回调列表

把回调集合放在单例中,同时提供注册、注销和触发回调的方法(注意用线程安全的集合避免并发问题):

object AuthSingleton {
    // 用CopyOnWriteArrayList防止并发修改异常
    private val callbacks = CopyOnWriteArrayList<LoginStatusCallback>()

    // 注册回调
    fun registerCallback(callback: LoginStatusCallback) {
        if (!callbacks.contains(callback)) {
            callbacks.add(callback)
        }
    }

    // 注销回调!务必在Fragment销毁时调用,避免内存泄漏
    fun unregisterCallback(callback: LoginStatusCallback) {
        callbacks.remove(callback)
    }

    // 登录完成时通知所有注册的回调
    private fun notifyLoginCompleted(isSuccess: Boolean, message: String?) {
        callbacks.forEach { it.onLoginCompleted(isSuccess, message) }
    }

    // 你的原有登录方法,登录结束后触发通知
    fun login(username: String, password: String) {
        // 模拟网络登录请求
        ApiClient.login(username, password) { success, msg ->
            // 处理登录结果后,通知所有Fragment
            notifyLoginCompleted(success, msg)
        }
    }

    // 新增:检查当前是否已登录的方法
    fun isLoggedIn(): Boolean {
        // 这里写你判断登录状态的逻辑,比如读取本地token
        return false
    }
}

3. 在Fragment中注册/注销并实现回调

Fragment要在合适的生命周期节点注册和注销回调,比如视图创建时注册,视图销毁时注销:

class MyFragment : Fragment(), LoginStatusCallback {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 注册回调
        AuthSingleton.registerCallback(this)
        
        // 先检查当前是否已经登录,如果已登录直接加载数据
        if (AuthSingleton.isLoggedIn()) {
            loadDataFromWeb()
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        // 必须注销回调!否则Fragment会被单例持有,无法被GC回收
        AuthSingleton.unregisterCallback(this)
    }

    // 实现回调方法,登录完成后触发数据加载
    override fun onLoginCompleted(isSuccess: Boolean, message: String?) {
        if (isSuccess) {
            loadDataFromWeb()
        } else {
            // 处理登录失败的情况,比如显示错误提示
            Toast.makeText(requireContext(), message ?: "登录失败", Toast.LENGTH_SHORT).show()
        }
    }

    private fun loadDataFromWeb() {
        // 这里写你的网络请求加载数据逻辑
    }
}
方案二:用LiveData实现(更Android化的方案)

如果你项目里用Jetpack组件,推荐用LiveData——它自带生命周期感知能力,不用手动注销回调,能自动避免内存泄漏:

1. 在单例类里定义LiveData

object AuthSingleton {
    // 内部用MutableLiveData修改状态,对外暴露不可变的LiveData
    private val _loginStatus = MutableLiveData<LoginResult?>()
    val loginStatus: LiveData<LoginResult?> = _loginStatus

    // 封装登录结果的数据类
    data class LoginResult(val isSuccess: Boolean, val message: String?)

    fun login(username: String, password: String) {
        ApiClient.login(username, password) { success, msg ->
            // 用postValue在子线程更新LiveData
            _loginStatus.postValue(LoginResult(success, msg))
        }
    }

    fun isLoggedIn(): Boolean {
        return _loginStatus.value?.isSuccess ?: false
    }
}

2. 在Fragment中观察LiveData

class MyFragment : Fragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        // 观察登录状态变化,用viewLifecycleOwner绑定Fragment视图生命周期
        AuthSingleton.loginStatus.observe(viewLifecycleOwner) { result ->
            result?.let {
                if (it.isSuccess) {
                    loadDataFromWeb()
                } else {
                    Toast.makeText(requireContext(), it.message ?: "登录失败", Toast.LENGTH_SHORT).show()
                }
            }
        }

        // 检查当前登录状态,已登录则直接加载
        if (AuthSingleton.isLoggedIn()) {
            loadDataFromWeb()
        }
    }

    private fun loadDataFromWeb() {
        // 加载数据逻辑
    }
}
关键注意事项
  • 方案一必须手动注销回调,否则Fragment会被单例持有,引发内存泄漏。
  • 方案二一定要用viewLifecycleOwner观察LiveData,这样Fragment视图销毁时会自动移除观察者,无需手动处理。
  • 不管用哪种方案,只要MainActivity触发登录,所有注册了回调/观察了LiveData的Fragment都会收到登录完成的通知,进而执行数据加载逻辑。

内容的提问来源于stack exchange,提问作者Augusto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:13:35