我有两个 fragment :(1) 图书馆 fragment ,(2) 书籍 fragment
图书馆 fragment 通过 RecyclerView 显示所有可用的书籍。用户可以点击每个 RecyclerView 项目,这会将 LiveData 设置为相应的书籍。同时将打开 Book Fragment,并显示该书的内容。
我在库 fragment 的 RecyclerView.Adapter 内的 ViewHolder 类中设置了一个 onClickListener。因此,当单击一个项目时,将设置实时数据,然后通过导航组件导航到 Book fragment 。 Book Fragment 在实时数据上有一个观察者并显示它。
正如您在下面的代码中看到的,我正在将 viewmodel 实例传递给适配器,这是不正确的......?或者是吗?应该怎么做?
库 fragment 代码 fragment
class LibraryFragment : Fragment() {
[...]
private val model: SharedViewModel by activityViewModels()
private lateinit var gridlayoutManager: GridLayoutManager
private lateinit var thumbnailAdapter: ThumbnailAdapter
private lateinit var thumbnailRecyclerView: RecyclerView
private lateinit var selectedFolder: Uri
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = layoutInflater.inflate(R.layout.fragment_thumbnail_viewer, container, false)
initRecyclerView(view)
view.allFolderPicker.setOnClickListener {
pickFolder()
}
view.switchFragment.setOnClickListener {
findNavController().navigate(R.id.action_allFoldersFragment_to_oneFolderFragment)
}
return view
}
private fun initRecyclerView(view: View) {
thumbnailRecyclerView = view.findViewById(R.id.thumbnail_recycler_view)
gridlayoutManager =
GridLayoutManager(requireContext(), 3, LinearLayoutManager.VERTICAL, false)
thumbnailRecyclerView.layoutManager = gridlayoutManager
thumbnailAdapter = ThumbnailAdapter(model)
thumbnailAdapter.setThumbnailList(listOf())
thumbnailRecyclerView.adapter = thumbnailAdapter
}
[...]
}
适配器类代码 fragment
class ThumbnailAdapter(model: SharedViewModel) :
RecyclerView.Adapter<ThumbnailAdapter.CustomViewHolder>() {
private var thumbnailList = listOf<Pair<String, File>>()
private val myModel = model
inner class CustomViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val thumbnail = view.thumbnail
private val title = view.title
fun bind(item: Pair<String, File>) {
val titleToSet = item.first
val bitmapToSet = Util.uriToBitmap(item.second)
val resizedBitmapToSet = Bitmap.createScaledBitmap(bitmapToSet, 150, 150, false)
thumbnail.setImageBitmap(resizedBitmapToSet)
title.text = titleToSet
itemView.setOnClickListener {
val folderWithImages = thumbnailList[adapterPosition].second.parentFile
folderWithImages?.let {
myModel.setLibraryFolderList(it)
itemView.findNavController()
.navigate(R.id.action_allFoldersFragment_to_oneFolderFragment)
}
}
}
}
[...]
}
书籍 fragment 代码 fragment
[...]
class BookViewFragment : Fragment() {
private lateinit var viewPager: ViewPager2
private lateinit var viewPagerAdapter: ViewPager2Adapter
private val model: SharedViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_image_viewer, container, false)
initRecyclerView(view)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model.selectedBookFile.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
viewPagerAdapter.setImageList(getImageList(it))
viewPagerAdapter.notifyDataSetChanged()
})
}
private fun initRecyclerView(view: View) {
viewPager = view.findViewById(R.id.main_image)
viewPagerAdapter = ViewPager2Adapter()
viewPagerAdapter.setImageList(listOf())
viewPager.adapter = viewPagerAdapter
}
[...]
}
最佳答案
你不应该那样做,这里有一个关于 RecyclerView 的类(class)从显示到处理 clickListener。
他们是这样定义的:
While the
ViewHolder
is a great place to listen for clicks, it's not usually the right place to handle them. You should usually handle clicks in theViewModel
, because theViewModel
has access to the data and logic for determining what needs to happen in response to the click.
所以你应该这样做:
适配器:
class ThumbnailAdapter(model: SharedViewModel, val clickListener: ThumbnailListener) :
RecyclerView.Adapter<ThumbnailAdapter.CustomViewHolder>() {
private var thumbnailList = listOf<Pair<String, File>>()
private val myModel = model
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
val item = getItem(position)
holder.itemView.setOnClickListener {
listener.onClick(item)
}
holder.bind(marsProperty)
}
inner class CustomViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val thumbnail = view.thumbnail
private val title = view.title
fun bind(item: Pair<String, File>) {
val titleToSet = item.first
val bitmapToSet = Util.uriToBitmap(item.second)
val resizedBitmapToSet = Bitmap.createScaledBitmap(bitmapToSet, 150, 150, false)
thumbnail.setImageBitmap(resizedBitmapToSet)
title.text = titleToSet
}
}
class ThumbnailListener(val clickListener: (libraryId: Long) -> Unit) {
fun onClick(val library: Library) = clickListener(library.id)
}
[...]
}
View 模型:
private val _navigateToBook = MutableLiveData<Long>()
val navigateToBook: LiveData<Long>()
get() = _navigateToBook
fun onLibraryClicked(libraryId: Long) {
// your stuff
_navigateToBook.value = libraryId
}
fragment :
thumbnailAdapter = ThumbnailAdapter(model, ThumbnailListener { libraryId ->
viewModel.onLibraryClicked(libraryId)
})
viewModel.navigateToBook.observe(viewLifecycleOwner, Observer { book ->
book?.let {
this.findNavController().navigate(YOUR_DESTINATION)
}
})
第二次使用数据绑定(bind)设置监听器的可能性:
xml 项目文件:
<data>
<variable
name="listener"
type="Your.Package.To.ThumbnailListener" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="170dp"
android:onClick="@{() -> listener.onClick(property)}">
...
</FrameLayout>
适配器:
fun bind(item: Pair<String, File>, listener: ThumbnailListener) {
val titleToSet = item.first
val bitmapToSet = Util.uriToBitmap(item.second)
val resizedBitmapToSet = Bitmap.createScaledBitmap(bitmapToSet, 150, 150, false)
thumbnail.setImageBitmap(resizedBitmapToSet)
title.text = titleToSet
itemView.clickListener = listener
}
关于android - 如何从 Adapter 设置 LiveData?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60822715/