Android 如何从适配器设置LiveData?
我有两个片段:(1)图书馆片段,(2)书籍片段 library fragments通过RecyclerView显示所有可用的书籍。用户可以在每个RecyclerView项上设置选项卡,这将把LiveData设置为相应的图书。同时,书籍片段将被打开,并显示该书的内容 我在库片段的RecyclerView.Adapter内的ViewHolder类中设置了onClickListener。因此,当单击一个项目时,将设置livedata,然后通过导航组件导航到图书片段。书中的片段有一个对实时数据的观察者,并显示了它 正如您在下面的代码中所看到的,我正在将viewmodel实例传递给适配器,这是不正确的。。。。?还是这样?如何做到这一点 库片段代码片段Android 如何从适配器设置LiveData?,android,android-fragments,kotlin,android-adapter,android-livedata,Android,Android Fragments,Kotlin,Android Adapter,Android Livedata,我有两个片段:(1)图书馆片段,(2)书籍片段 library fragments通过RecyclerView显示所有可用的书籍。用户可以在每个RecyclerView项上设置选项卡,这将把LiveData设置为相应的图书。同时,书籍片段将被打开,并显示该书的内容 我在库片段的RecyclerView.Adapter内的ViewHolder类中设置了onClickListener。因此,当单击一个项目时,将设置livedata,然后通过导航组件导航到图书片段。书中的片段有一个对实时数据的观察者,
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
}
[...]
}
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)
}
}
}
}
[...]
}
[...]
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
}
[...]
}
适配器类代码片段
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
}
[...]
}
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)
}
}
}
}
[...]
}
[...]
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
}
[...]
}
你不应该这样做,这里有一个关于从显示到处理clickListener的课程 以下是他们对它的定义: 虽然
ViewHolder
是一个聆听点击的好地方,但它通常不是处理点击的正确地方。您通常应该在ViewModel
中处理单击,因为ViewModel
可以访问数据和逻辑,以确定响应单击需要发生什么
所以你应该这样做:
适配器:
class ThumbnailAdapter(型号:SharedViewModel,val clickListener:ThumbnailListener):
RecyclerView.Adapter(){
private var thumbnailList=listOf()
private val myModel=model
覆盖BindViewHolder(holder:CustomViewHolder,位置:Int){
val item=getItem(位置)
holder.itemView.setOnClickListener{
listener.onClick(项)
}
持有人绑定(marsProperty)
}
内部类CustomViewHolder(视图:视图):RecyclerView.ViewHolder(视图){
private val thumbnail=view.thumbnail
private val title=view.title
趣味绑定(项目:成对){
val titleToSet=项目。第一个
val bitmapToSet=Util.uriToBitmap(item.second)
val resizedBitmapToSet=Bitmap.createScaledBitmap(bitmapToSet,150,150,false)
缩略图.setImageBitmap(大小为DbitMapToSet)
title.text=titleToSet
}
}
类ThumbnailListener(val clickListener:(库ID:Long)->单位){
fun onClick(val library:library)=clickListener(library.id)
}
[...]
}
视图模型:
private val\u navigateBook=MutableLiveData()
val navigateToBook:LiveData()
get()=\u NavigateTook
仅限乐趣已单击库(库ID:长){
//你的东西
_navigateToBook.value=libraryId
}
片段:
thumbnailAdapter=thumbnailAdapter(型号,ThumbnailListener{libraryId->
viewModel.OnlLibrary已单击(libraryId)
})
viewModel.NavigateBook.observe(viewLifecycleOwner,Observer{book->
书?让我看看{
this.findNavController().navigate(您的目的地)
}
})
第二种可能性是,这次使用数据绑定设置侦听器: xml项目文件:
...
适配器:
fun绑定(项:配对,侦听器:ThumbnailListener){
val titleToSet=项目。第一个
val bitmapToSet=Util.uriToBitmap(item.second)
val resizedBitmapToSet=Bitmap.createScaledBitmap(bitmapToSet,150,150,false)
缩略图.setImageBitmap(大小为DbitMapToSet)
title.text=titleToSet
itemView.clickListener=监听器
}
只需在适配器类中使用您的活动
引用,而不是viewLifecycleOwner
,它就可以工作了
class ThumbnailAdapter(
private val activity: FragmentActivity
) : RecyclerView.Adapter<ThumbnailAdapter.CustomViewHolder>() {
// ... Other functions
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model.selectedBookFile.observe(activity, androidx.lifecycle.Observer {
// Your code goes here
})
}
// ... Other functions
}
类ThumbnailAdapter(
私有val活动:碎片活动
):RecyclerView.Adapter(){
//……其他职能
覆盖已创建的视图(视图:视图,保存状态:捆绑?){
super.onViewCreated(视图,savedInstanceState)
model.selectedBookFile.Observer(活动,androidx.lifecycle.Observer{
//你的密码在这里
})
}
//……其他职能
}
我知道现在回答太晚了。
但我希望它能帮助其他开发者寻找类似问题的解决方案
看一看
您只需要在Gradle中添加最新的依赖项
dependencies {
implementation 'com.github.RaviKoradiya:LiveAdapter:1.3.4'
// kapt 'com.android.databinding:compiler:GRADLE_PLUGIN_VERSION' // this line only for Kotlin projects
}
并将适配器与您的RecyclerView绑定
// Kotlin sample
LiveAdapter(
data = liveListOfItems,
lifecycleOwner = this@MainActivity,
variable = BR.item )
.map<Header, ItemHeaderBinding>(R.layout.item_header) {
onBind{
}
onClick{
}
areContentsTheSame { old: Header, new: Header ->
return@areContentsTheSame old.text == new.text
}
areItemSame { old: Header, new: Header ->
return@areContentsTheSame old.text == new.text
}
}
.map<Point, ItemPointBinding>(R.layout.item_point) {
onBind{
}
onClick{
}
areContentsTheSame { old: Point, new: Point ->
return@areContentsTheSame old.id == new.id
}
areItemSame { old: Header, new: Header ->
return@areContentsTheSame old.text == new.text
}
}
.into(recyclerview)
//Kotlin示例
活适配器(
数据=liveListOfItems,
生命周期所有者=this@MainActivity,
变量=BR.item)
.地图(右布局.项目标题){
onBind{
}
onClick{
}
内容是否相同{old:Header,new:Header->
return@areContentsTheSameold.text==new.text
}
areItemSame{old:Header,new:Header->
return@areContentsTheSameold.text==new.text
}
}
.地图(右布局图项目\ U点){
onBind{
}
onClick{
}
内容是否相同{旧:点,新:点->
return@areContentsTheSameold.id==new.id
}
areItemSame{old:Header,new:Header->
return@areContentsTheSameold.text==new.text
}
}
.进入(回收视图)
就这样。无需为适配器实现编写额外代码,请观察LiveData并通知适配器
另外,实现DiffUtil,这样只有更改的项才会在RecyclerView上更新,而不是全部更新。知道onClickListener触发的操作不应由适配器处理是件好事,但不幸的是,它没有回答将ViewModel传递给适配器的问题。此外,无法将ThumbnailListener分配给itemView.setOnCl