我是Android开发的新手,我一直在寻找一种方法来使用某些Android库(例如Dagger2,Fragments和ViewModel)来执行此模式。
[我希望你们中的一些人可以帮助我解决这个问题,或者说明在Android上执行此操作的常用方法。
我正在寻找这样的东西:
class FragmentPager: Fragment() {
@Inject
@Named("FullListFragment")
lateinit var listFragment: ListFragment
@Inject
@Named("FilteredListFragment")
lateinit var filteredListFragment: ListFragment
//Use fragments in the viewPager.
}
我有一个片段,显示了元素列表。它还有一个ViewModel负责更新列表。 ViewModel从查询数据库的存储库中获取列表。到目前为止非常简单。
我的用例是,我的应用程序显示应用程序内许多不同区域中的元素列表,但具有不同的数据。例如完整列表,过滤列表...
[我的想法是使用单个方法将存储库创建为接口:fun getItems(): List<Item>
和每个数据源的不同实例。结果,我有:
这些元素将在这样的理想世界中协同工作:
fun buildListFragment(repository: ListRepository) {
val viewModel = ListViewModel(repository)
val fragment = ListFragment(viewModel)
return fragment
}
val fullListFragment = buildListFragment(FullListRepository())
val filteredListFragment = buildListFragment(FilterListRepository())
val joinedListFragment = buildListFragment(JoinedListRepository())
如何使用Dagger2注入依赖项,使用ViewModelFactory创建ViewModel和片段来执行类似的操作。
class ListFragment: Fragment() {
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
viewModel = ViewModelProvider(this, viewModelFactory).get(CardListViewModel::class.java)
}
}
我通常会在发布答案之前先对我的答案进行测试,但是要与先生联系。匕首太过分了。就是说,这是我的有根据的猜测:
具有知道如何提取3个不同数据集(完整,已过滤,已合并)的单个片段意味着需要对其进行参数化。我想可以通过命名注入来完成,但是我只在需要时使用MyFragment.newInstanceA()
,MyFragment.newInstanceB()
等。
在片段中,可能使用了android注入,因为我认为您已经在做,单一的自由格式工厂是通过构造函数注入的,所有实现单一接口的3个存储库。该工厂将包装您的ViewModelProvider.Factory
实现,并提供一个方法,例如create
,该方法带有实例化片段的参数。
基于参数值,工厂将创建并返回参数正确的ViewModelProvider.Factory
实现。然后,视图模型提供者将能够get
正确地参数化视图模型。我知道这不是很多匕首,但从理论上讲它应该可以工作:)
PS .:如果数据显然显然来自单个存储,则我不会创建3个不同的存储库。可能需要在视图模型下完成对不同回购方法的调用。
我将从这样重新设计存储库开始:
interface ListRepository {
fun getFullList(): LiveData<List<Product>>
fun getFilteredList(): LiveData<List<Product>>
fun getJoinedList(): LiveData<List<Product>>
}
这里假设您要使用房间,则使用LiveData。
然后将我的ViewModel设计为能够根据listType
输入获得所需的列表。
class ListViewModel @Inject constructor(
private val listRepository: ListRepository
) : ViewModel() {
private val listType = MutableLiveData<String>()
val productList = Transformations.switchMap(listType) {
getList(it)
}
// call from fragment
fun fetchList(listType: String) {
this.listType.value = listType
}
private fun getList(listType: String): LiveData<List<Product>> {
return when (listType) {
"full" -> listRepository.getFullList()
"filter" -> listRepository.getFilteredList()
"joined" -> listRepository.getJoinedList()
else -> throw IllegalArgumentException("Unknown List Type")
}
}
}
switchMap
在此处用于防止每次我们从片段中获取列表时,存储库都返回新的LiveData实例。然后是片段将内容包裹起来。
class ListFragment : Fragment() {
lateinit var listType: String
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
private val viewModel: ListViewModel by viewModels { viewModelFactory }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
listType = arguments?.getString("listType")
?: throw java.lang.IllegalArgumentException("No listType args found")
viewModel.fetchList(listType)
viewModel.productList.observe(viewLifecycleOwner) { products ->
TODO("render products on recycler view")
}
}
}
仅一个片段用于全部三种列表类型,因为我假设这些片段的Ui或多或少相同。将根据传入的listType
参数获取并显示列表。
fragmentManager.beginTransaction()
.add(R.id.content,ListFragment().apply {
arguments = Bundle().apply {
putString("listType","full")
}
})
.commitNow()