Android 如何从适配器设置LiveData?

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,然后通过导航组件导航到图书片段。书中的片段有一个对实时数据的观察者,

我有两个片段:(1)图书馆片段,(2)书籍片段

library fragments通过RecyclerView显示所有可用的书籍。用户可以在每个RecyclerView项上设置选项卡,这将把LiveData设置为相应的图书。同时,书籍片段将被打开,并显示该书的内容

我在库片段的RecyclerView.Adapter内的ViewHolder类中设置了onClickListener。因此,当单击一个项目时,将设置livedata,然后通过导航组件导航到图书片段。书中的片段有一个对实时数据的观察者,并显示了它

正如您在下面的代码中所看到的,我正在将viewmodel实例传递给适配器,这是不正确的。。。。?还是这样?如何做到这一点

库片段代码片段

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