当前位置: 首页 > 知识库问答 >
问题:

如何从适配器设置LiveData?

长孙谦
2023-03-14

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

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

我在ViewHolder类中设置了一个onClickListener,它位于图书馆片段的RecyclerView. Adapter中。因此,当单击一个项目时,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
    }

    [...]
}

共有3个答案

芮立果
2023-03-14

我知道现在回答太晚了。但我希望它能帮助其他开发者寻找类似问题的解决方案。

看看LiveAdapter。

您只需要在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)

就这样。不需要为适配器实现编写额外的代码,观察LiveData并通知适配器。

此外,有DiffUtil实现,所以只有更改的项目将更新RecyclerView,而不是所有。

商正诚
2023-03-14

简单地在Adapter类中使用您的活动引用,而不是viewLiefycleOwner,它就会工作

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

}
单于俊智
2023-03-14

你不应该这样做,这里有一个关于RecyclerView的课程,从显示到处理clickListener。

以下是他们对它的定义:

虽然ViewHolder是一个聆听点击的好地方,但它通常不是处理点击的正确地方。通常应该在ViewModel中处理点击,因为ViewModel可以访问数据和逻辑,以确定点击后需要发生什么。

所以你应该这样做:

适配器:

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)
    }

    [...]
}

视图模型:

private val _navigateToBook = MutableLiveData<Long>()
val navigateToBook: LiveData<Long>()
   get() = _navigateToBook

fun onLibraryClicked(libraryId: Long) {
    // your stuff
    _navigateToBook.value = libraryId
}

片段:

thumbnailAdapter = ThumbnailAdapter(model, ThumbnailListener { libraryId ->
    viewModel.onLibraryClicked(libraryId)
})

viewModel.navigateToBook.observe(viewLifecycleOwner, Observer { book ->
    book?.let {
        this.findNavController().navigate(YOUR_DESTINATION)
    }
})

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
        }
 类似资料:
  • 我已经尝试解决一个问题几个小时了,但我没有解决它。我尝试为可扩展列表视图设置适配器,但我接受了这个错误。多谢了。“尝试对空对象引用调用虚拟方法”void Android.Widget.ExpandableListView.SetAdapter(Android.Widget.ExpandableListAdapter)“”

  • 我注释了setIntTag(String),但Jaxb marchaller调用setIntTag(Integer)并将Integer传递给它,如果我删除setIntTag(Integer),marchaller调用字符串setter。 如何注释这些方法以保留两个setter,并告诉编组程序使用字符串setter?

  • 首先我在使用 keycloak-authz-client-3.3.0.final Spring boot 1.5.8.发布 spring-boot-starter-security 我一直在玩Keycloak spring adapter,探索示例,因为我们想在我们的项目中采用它。 我可以使用以下教程轻松地让它在角色中运行:https://dzone.com/articles/elyly-secu

  • 我正在尝试制作的音乐播放器中使用Volley。 下面是我如何定义音乐播放器中的歌曲。我有一个带有一些属性的“歌曲对象” 我使用albumArtURI用图像填充各种列表和网格视图。 要获取专辑ArtURI,我对其进行查询。如果URI不存在,我必须从Internet上拉取一个图像URL。 所以我设置了截取,从iTunes中提取JSON对象,解析对象,并获取它们的图像URL。 例如,这里是iTunesJ

  • 我为后台服务实现了一个AsyncTask来执行对数据库的查询,该查询速度非常快,不超过2-3秒。AsyncTask中的ProgressDialog有时很难检测到。 我的问题是,当任务完成并且我检索到游标时,当我将适配器设置到RecyclerView时,流程会冻结我的UI几秒钟,直到数据设置完毕。当我执行搜索(新查询,与获取所有行相同的过程,但行数较少),并替换光标以更新数据时,也会发生这种情况。

  • 我是kotlin android的新手。我已经创建了回收站视图的适配器。但是我不能为每个回收站视图项目执行单击事件。我需要参考代码的解释。请帮我做这件事。提前谢谢。这是我的代码供您参考。