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

如何用LiveData和ViewModel替代CursorLoader从Content Provider获取数据?

使用LiveData + ViewModel 从Content Provider 获取数据

完全可以用LiveData和ViewModel替代已弃用的CursorLoader,从Content Provider获取数据,下面是具体实现方案:

1. 创建ViewModel类

ViewModel负责数据的持有与管理,利用viewModelScope处理异步查询,自动避免内存泄漏:

class ContentProviderViewModel(application: Application) : AndroidViewModel(application) {
    // 内部用MutableLiveData更新数据,对外暴露不可变的LiveData
    private val _dataLiveData = MutableLiveData<List<YourDataModel>>()
    val dataLiveData: LiveData<List<YourDataModel>> = _dataLiveData

    // 触发数据加载
    fun loadDataFromContentProvider() {
        viewModelScope.launch(Dispatchers.IO) {
            // 替换为你的Content Provider URI、查询列、筛选条件等
            val cursor = getApplication<Application>().contentResolver.query(
                YOUR_CONTENT_URI,
                arrayOf(COLUMN_ID, COLUMN_NAME), // 要查询的字段(投影)
                null, // 筛选条件,无则传null
                null, // 筛选参数,无则传null
                COLUMN_NAME + " ASC" // 排序规则
            )

            // 将Cursor转换为数据模型列表
            val dataList = mutableListOf<YourDataModel>()
            cursor?.use { // use函数自动关闭Cursor,避免资源泄漏
                while (it.moveToNext()) {
                    val id = it.getInt(it.getColumnIndexOrThrow(COLUMN_ID))
                    val name = it.getString(it.getColumnIndexOrThrow(COLUMN_NAME))
                    dataList.add(YourDataModel(id, name))
                }
            }

            // 切回主线程更新LiveData
            withContext(Dispatchers.Main) {
                _dataLiveData.value = dataList
            }
        }
    }

    // 可选:监听Content Provider数据变化,自动刷新
    private var contentObserver: ContentObserver? = null

    init {
        contentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {
            override fun onChange(selfChange: Boolean) {
                super.onChange(selfChange)
                loadDataFromContentProvider() // 数据变化时重新加载
            }
        }
        getApplication<Application>().contentResolver.registerContentObserver(
            YOUR_CONTENT_URI,
            true, // 是否监听子URI的变化
            contentObserver!!
        )
    }

    override fun onCleared() {
        super.onCleared()
        // 取消注册ContentObserver,避免内存泄漏
        contentObserver?.let {
            getApplication<Application>().contentResolver.unregisterContentObserver(it)
        }
    }
}

2. 定义数据模型

根据你要查询的Content Provider字段,创建对应的数据模型:

data class YourDataModel(
    val id: Int,
    val name: String
    // 按需添加其他字段,比如手机号、时间等
)

3. 在UI层(Activity/Fragment)使用

在Activity或Fragment中初始化ViewModel,观察LiveData并更新UI:

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: ContentProviderViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 初始化ViewModel
        viewModel = ViewModelProvider(this)[ContentProviderViewModel::class.java]

        // 观察LiveData,数据变化时更新UI
        viewModel.dataLiveData.observe(this) { dataList ->
            updateUi(dataList)
        }

        // 首次加载数据
        viewModel.loadDataFromContentProvider()
    }

    private fun updateUi(dataList: List<YourDataModel>) {
        // 示例:给RecyclerView设置Adapter
        // val adapter = YourCustomAdapter(dataList)
        // recyclerView.adapter = adapter
    }
}

关键注意事项

  • 权限处理:如果访问的Content Provider需要权限(比如联系人、短信),需在AndroidManifest.xml中声明权限,并处理运行时权限请求。
  • Cursor安全:必须用use函数包裹Cursor操作,确保Cursor自动关闭,防止资源泄漏。
  • 线程切换:Content Provider查询属于耗时操作,必须在IO线程执行;更新LiveData时切回主线程,避免ANR。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 21:10:33