如何向AndroidViewModel传参以过滤assets目录下的JSON文件?
最优实现方案
你的场景最优解法是自定义ViewModelFactory,同时传入Application实例和分类过滤参数,既满足访问assets需要上下文的要求,又能把过滤参数传递到ViewModel内部,无需创建多个ViewModel实例,完全符合Android官方架构规范。
步骤1:修改ViewModel构造函数,增加过滤参数
调整原有ViewModel的构造,新增分类过滤参数作为构造入参,同时优化原有冗余逻辑:
class GuideViewModel( application: Application, // 新增分类过滤参数 private val filterCategory: String ) : AndroidViewModel(application) { private val _name = MutableLiveData<String>() val name: LiveData<String> get() = _name private val _difficulty = MutableLiveData(3) val difficulty: LiveData<Int> get() = _difficulty private val _date = MutableLiveData<Long>(3010) val date: LiveData<Long> get() = _date private val _graphic = MutableLiveData<String>() val graphic: LiveData<String> get() = _graphic // 初始化时直接加载并过滤数据,无需外部调用触发 init { loadJsonData() } private fun loadJsonData() { try { val jsonString = loadJsonDataFromFile() val json = JSONObject(jsonString) val jsonBrewers = json.getJSONArray("movies") for (index in 0 until jsonBrewers.length()) { val item = jsonBrewers.getJSONObject(index) // 用构造传入的过滤参数做匹配 if (item.getString(KEY_NAME) == filterCategory) { _name.value = item.getString(KEY_NAME) _difficulty.value = item.getInt(KEY_DIFFICULTY) _date.value = item.getLong(KEY_DATE) _graphic.value = item.getString(KEY_GRAPHIC) // 匹配到目标就跳出循环,减少无效遍历 break } } } catch (e: JSONException) { e.printStackTrace() } } private fun loadJsonDataFromFile(): String { var json = "" try { val input = getApplication<Application>().assets.open("movies.json") val size = input.available() val buffer = ByteArray(size) input.read(buffer) input.close() json = buffer.toString(Charsets.UTF_8) } catch (e: IOException) { e.printStackTrace() } return json } companion object { private const val KEY_NAME = "name" private const val KEY_DIFFICULTY = "difficulty" private const val KEY_DATE = "date" private const val KEY_GRAPHIC = "graphic" } }
步骤2:实现自定义ViewModelFactory
因为原生ViewModelFactory不支持带自定义参数的AndroidViewModel创建,需要自己实现Factory:
class GuideViewModelFactory( private val application: Application, private val filterCategory: String ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(GuideViewModel::class.java)) { return GuideViewModel(application, filterCategory) as T } throw IllegalArgumentException("Unknown ViewModel class") } }
步骤3:在Activity/Fragment中实例化ViewModel
传入需要的分类参数,创建ViewModel实例后直接观察LiveData即可:
Activity中使用示例
class GuideActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 替换为你实际需要的分类参数 val targetCategory = "你需要的分类值" val viewModelFactory = GuideViewModelFactory(application, targetCategory) val viewModel = ViewModelProvider(this, viewModelFactory)[GuideViewModel::class.java] // 观察数据更新UI viewModel.name.observe(this) { name -> // 更新名称UI } viewModel.difficulty.observe(this) { difficulty -> // 更新难度UI } } }
Fragment中使用示例
class GuideFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 替换为你实际需要的分类参数 val targetCategory = "你需要的分类值" val viewModelFactory = GuideViewModelFactory(requireActivity().application, targetCategory) val viewModel = ViewModelProvider(this, viewModelFactory)[GuideViewModel::class.java] // 观察数据更新UI即可 } }
额外优化建议
- 如果需要频繁切换分类过滤,不需要重建ViewModel,可在ViewModel内新增
setFilterCategory()方法,传入新参数后重新执行过滤逻辑即可 - assets的JSON文件如果是固定内容,可添加缓存逻辑,不需要每次过滤都重新读取本地文件,提升运行性能
- 生产环境建议用Gson/Moshi等JSON解析库替代原生JSONObject,减少手写解析的出错概率
内容的提问来源于stack exchange,提问作者byrnec25
相关产品推荐
相关产品推荐

