Recycler View 在 notifyDataSetChanged() 之后不更新列表
Recycler View doesn't update list after notifyDataSetChanged()
为了简单地描述问题,我有 main activity,其中有显示 2 个片段的 viewPager2。主要 activity 还获得了一个带有搜索菜单选项的工具栏。我正在尝试搜索艺术家,因此它会自动更新第一个片段 (videoCallHomefragment) 中的回收器视图。我不知道问题出在哪里,因为这是我调试这件事的第3天,我仍然无处可去。
我的假设
- 肯定存在冲突,因为我正在使用 viewpager2 并尝试更新来自 activity
的片段中的回收器视图
- 导致“notifyDataSetChanged()”无法正常工作的依赖项版本控制冲突,另一方面,我尝试了使用 DiffUtil 的替代方法,但仍然无法正常工作
p.s。该应用程序成功检索艺术家并将其显示在回收站视图中,这表明适配器中的函数“setData”正在运行,但是在搜索艺术家时,“onBindViewHolder”和“onCreateViewHolder”在调用 notifyDataSetChanged( )
请参阅下面的代码片段
MainActivity
@AndroidEntryPoint
class MainActivity : AppCompatActivity(), ArtistsAdapter.OnArtistListener {
private lateinit var binding: ActivityMainBinding
private val mAdapter by lazy { ArtistsAdapter(this) }
private val mainViewModel: MainViewModel by viewModels()
private lateinit var viewPager2:ViewPager2
private lateinit var fragement: Fragment
private lateinit var artists: List<Artist>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
fragement = supportFragmentManager.findFragmentById(R.id.videoCallHomeFragment)!!
setSupportActionBar(findViewById(R.id.toolbar))
val tabLayout = findViewById<TabLayout>(R.id.tab_layout)
viewPager2 = findViewById(R.id.view_pager_2)
val adapter = ViewPagerAdapter(supportFragmentManager, lifecycle)
viewPager2.adapter = adapter
TabLayoutMediator(tabLayout, viewPager2){tab, postion ->
when(postion) {
0 -> {
tab.text="Artists"
}
1 -> {
tab.text = "Voice Calls"
}
}
}.attach()
viewPager2.registerOnPageChangeCallback(object: ViewPager2.OnPageChangeCallback(), SearchView.OnQueryTextListener {
@SuppressLint("ResourceType")
override fun onPageSelected(position: Int) {
if(position == 0)
{
val toolbar = findViewById<Toolbar>(R.id.mainToolbar)
toolbar.inflateMenu(R.menu.search_menu)
val search = toolbar.menu.findItem(R.id.menu_search)
val searchView = search?.actionView as? SearchView
searchView?.isSubmitButtonEnabled = true
searchView?.setOnQueryTextListener(this)
} else {
val toolbar = findViewById<Toolbar>(R.id.mainToolbar)
toolbar.menu.clear()
}
}
@SuppressLint("NotifyDataSetChanged")
override fun onQueryTextSubmit(query: String?): Boolean {
if(query != null){
// recyclerView.adapter = mAdapter
// recyclerView.layoutManager = LinearLayoutManager(applicationContext, LinearLayoutManager.VERTICAL, false)
searchArtist(query)
mAdapter.notifyDataSetChanged()
}
return true
}
@SuppressLint("NotifyDataSetChanged")
override fun onQueryTextChange(newText: String?): Boolean {
if(newText != null){
// recyclerView.adapter = mAdapter
// recyclerView.layoutManager = LinearLayoutManager(applicationContext, LinearLayoutManager.VERTICAL, false)
searchArtist(newText)
mAdapter.notifyDataSetChanged()
}
return true
}
})
requestPermissions()
val toolbar = findViewById<Toolbar>(R.id.mainToolbar)
toolbar.setBackgroundColor(Color.rgb(32, 4, 209))
toolbar.setTitleTextColor(Color.WHITE)
toolbar.setTitle(R.string.app_name)
}
private fun requestPermissions()
{
if (PermissionRequestUtil.hasCameraPermissions(this)) {
return
} else {
EasyPermissions.requestPermissions(
this,
"Please accept camera permissions to use this app.",
0,
Manifest.permission.CAMERA
)
}
}
@SuppressLint("NotifyDataSetChanged")
private fun searchArtist(query: String)
{
val searchQuery = "%$query%"
lifecycle.coroutineScope.launch {
mainViewModel.searchArtist(searchQuery).collect { it ->
mAdapter.setData(it)
mAdapter.notifyDataSetChanged()
Log.i(TAG, "new artist List set!!")
}
}
}
override fun onArtistClick(artist: Artist, position: Int) {
TODO("Not yet implemented")
}
}
VideoCallHomeFragment
package com.example.awfc.ui
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.*
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.coroutineScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.awfc.R
import com.example.awfc.adapters.ArtistsAdapter
import com.example.awfc.data.Artist
import com.example.awfc.viewmodels.MainViewModel
import com.todkars.shimmer.ShimmerRecyclerView
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@AndroidEntryPoint
class VideoCallHomeFragment : Fragment() , ArtistsAdapter.OnArtistListener {
private lateinit var mainViewModel: MainViewModel
private val mAdapter by lazy { ArtistsAdapter(this)}
private lateinit var mView: View
private lateinit var artists: List<Artist>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
mView = inflater.inflate(R.layout.fragment_video_call_home, container, false)
setHasOptionsMenu(true)
//val shimmer = mView.findViewById<ShimmerRecyclerView>(R.id.recycler_view)
//shimmer.showShimmer()
setupRecyclerView()
mainViewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)
lifecycle.coroutineScope.launch {
mainViewModel.getArtists().collect {
artists = it
mAdapter.setData(it)
//shimmer.hideShimmer()
}
}
return mView
}
@SuppressLint("CutPasteId")
fun setupRecyclerView()
{
mView.findViewById<RecyclerView>(R.id.recycler_view).adapter = mAdapter
mView.findViewById<RecyclerView>(R.id.recycler_view).layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
}
override fun onArtistClick(artist: Artist, position: Int) {
artists[position]
val intent = Intent(this.context, ArtistDetailsActivity::class.java)
intent.putExtra("artistName", artist.name)
intent.putExtra("arabicName", artist.name_arabic)
intent.putExtra("arabicDesc", artist.description_arabic)
intent.putExtra("artistDesc", artist.description)
intent.putExtra("artistImage", artist.image)
intent.putExtra("artistVideo1", artist.videoUrl1)
intent.putExtra("artistVideo2", artist.videoUrl2)
intent.putExtra("artistVideo3", artist.videoUrl3)
startActivity(intent)
}
}
艺术家适配器
package com.example.awfc.adapters
import android.annotation.SuppressLint
import android.content.ContentValues.TAG
import android.content.Intent
import android.service.autofill.OnClickAction
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.example.awfc.data.Artist
import com.example.awfc.databinding.ArtistRowLayoutBinding
import com.example.awfc.utils.ArtistsDiffUtil
class ArtistsAdapter(var artistListener: OnArtistListener) : RecyclerView.Adapter<ArtistsAdapter.MyViewHolder>() {
private var artists = emptyList<Artist>()
class MyViewHolder(private val binding: ArtistRowLayoutBinding) :
RecyclerView.ViewHolder(binding.root) {
fun init(artist: Artist, action: OnArtistListener)
{
itemView.setOnClickListener {
action.onArtistClick(artist, adapterPosition)
}
}
fun bind(modelClass: Artist) {
binding.result = modelClass
binding.executePendingBindings()
}
companion object {
fun from(parent: ViewGroup): MyViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ArtistRowLayoutBinding.inflate(layoutInflater, parent, false)
return MyViewHolder(binding)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
Log.i(TAG, "OnCreateViewHolder initiated")
return MyViewHolder(
ArtistRowLayoutBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentResult = artists[position]
holder.bind(currentResult)
holder.init(currentResult, artistListener)
Log.i(TAG, "OnBindViewHOlder initiated")
}
override fun getItemCount(): Int {
return artists.size
}
@SuppressLint("NotifyDataSetChanged")
fun setData(newData: List<Artist>) {
val artistsDiffUtil = ArtistsDiffUtil(artists, newData)
val diffUtilResult = DiffUtil.calculateDiff(artistsDiffUtil)
artists = emptyList()
artists = newData
diffUtilResult.dispatchUpdatesTo(this)
this.notifyDataSetChanged()
//this.notifyDataSetChanged()
}
interface OnArtistListener {
fun onArtistClick(artist:Artist, position: Int)
}
}
artistDiffUtil
package com.example.awfc.utils
import androidx.recyclerview.widget.DiffUtil
class ArtistsDiffUtil<T>(
private val oldList: List<T>,
private val newList: List<T>
): DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldList.size
}
override fun getNewListSize(): Int {
return newList.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] === newList[newItemPosition]
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
}
gradleFile
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
id 'kotlin-parcelize'
id 'androidx.navigation.safeargs'
}
android {
compileSdk 31
buildFeatures {
viewBinding true
dataBinding true
}
defaultConfig {
applicationId "com.example.awfc"
minSdk 21
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
javaCompileOptions {
annotationProcessorOptions {
arguments += ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
def room_version = "2.4.2"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"
implementation "com.google.dagger:hilt-android:2.28.3-alpha"
kapt "com.google.dagger:hilt-android-compiler:2.28.3-alpha"
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02"
kapt "androidx.hilt:hilt-compiler:1.0.0-alpha02"
implementation 'com.facebook.shimmer:shimmer:0.5.0'
implementation 'com.todkars:shimmer-recyclerview:0.4.1'
implementation 'de.hdodenhof:circleimageview:3.1.0'
// Image Loading library Coil
implementation "io.coil-kt:coil:0.13.0"
implementation 'com.squareup.picasso:picasso:2.71828'
// UI Tests
androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.1.1'
// When using a AppCompat theme
implementation "com.google.accompanist:accompanist-appcompat-theme:0.16.0"
implementation "com.google.android.material:compose-theme-adapter:1.1.1"
// Lifecycle
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation 'com.yqritc:android-scalablevideoview:1.0.4'
implementation 'com.github.bumptech.glide:glide:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.0'
implementation("javax.inject:javax.inject:1")
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
implementation 'androidx.navigation:navigation-fragment-ktx:2.4.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.4.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
// viewpager2
implementation 'androidx.viewpager2:viewpager2:1.0.0'
//tablayout
implementation 'com.google.android.material:material:1.3.0-alpha04'
// For developers using AndroidX in their applications
implementation 'pub.devrel:easypermissions:3.0.0'
}
您正在 MainActivity
和 VideoCallHomeFragment
中创建两个单独的 ArtistsAdapter
实例。如果 setData
在实际显示 RecyclerView
的片段内工作,听起来适配器工作正常,因为那是可以访问显示数据的实际适配器的那个。
但是在 MainActivity
中的 searchArtist
中,您在完全不同的适配器实例上调用 setData
,该实例未以任何方式连接到 RecyclerView
,所以什么都不会发生。
与其让 activity 尝试与片段中托管的小部件对话,不如让 LiveData
或类似的视图模型包含应该被显示。让 VideoCallHomeFragment
观察到,它可以在适配器上调用 setData
。您的 activity 可以调用 viewModel.getArtists()
或其他任何东西,但是 该函数 应该在内部更新 LiveData
以便观察它的任何对象都能看到要显示的新数据.
为了简单地描述问题,我有 main activity,其中有显示 2 个片段的 viewPager2。主要 activity 还获得了一个带有搜索菜单选项的工具栏。我正在尝试搜索艺术家,因此它会自动更新第一个片段 (videoCallHomefragment) 中的回收器视图。我不知道问题出在哪里,因为这是我调试这件事的第3天,我仍然无处可去。
我的假设
- 肯定存在冲突,因为我正在使用 viewpager2 并尝试更新来自 activity 的片段中的回收器视图
- 导致“notifyDataSetChanged()”无法正常工作的依赖项版本控制冲突,另一方面,我尝试了使用 DiffUtil 的替代方法,但仍然无法正常工作
p.s。该应用程序成功检索艺术家并将其显示在回收站视图中,这表明适配器中的函数“setData”正在运行,但是在搜索艺术家时,“onBindViewHolder”和“onCreateViewHolder”在调用 notifyDataSetChanged( )
请参阅下面的代码片段
MainActivity
@AndroidEntryPoint
class MainActivity : AppCompatActivity(), ArtistsAdapter.OnArtistListener {
private lateinit var binding: ActivityMainBinding
private val mAdapter by lazy { ArtistsAdapter(this) }
private val mainViewModel: MainViewModel by viewModels()
private lateinit var viewPager2:ViewPager2
private lateinit var fragement: Fragment
private lateinit var artists: List<Artist>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
fragement = supportFragmentManager.findFragmentById(R.id.videoCallHomeFragment)!!
setSupportActionBar(findViewById(R.id.toolbar))
val tabLayout = findViewById<TabLayout>(R.id.tab_layout)
viewPager2 = findViewById(R.id.view_pager_2)
val adapter = ViewPagerAdapter(supportFragmentManager, lifecycle)
viewPager2.adapter = adapter
TabLayoutMediator(tabLayout, viewPager2){tab, postion ->
when(postion) {
0 -> {
tab.text="Artists"
}
1 -> {
tab.text = "Voice Calls"
}
}
}.attach()
viewPager2.registerOnPageChangeCallback(object: ViewPager2.OnPageChangeCallback(), SearchView.OnQueryTextListener {
@SuppressLint("ResourceType")
override fun onPageSelected(position: Int) {
if(position == 0)
{
val toolbar = findViewById<Toolbar>(R.id.mainToolbar)
toolbar.inflateMenu(R.menu.search_menu)
val search = toolbar.menu.findItem(R.id.menu_search)
val searchView = search?.actionView as? SearchView
searchView?.isSubmitButtonEnabled = true
searchView?.setOnQueryTextListener(this)
} else {
val toolbar = findViewById<Toolbar>(R.id.mainToolbar)
toolbar.menu.clear()
}
}
@SuppressLint("NotifyDataSetChanged")
override fun onQueryTextSubmit(query: String?): Boolean {
if(query != null){
// recyclerView.adapter = mAdapter
// recyclerView.layoutManager = LinearLayoutManager(applicationContext, LinearLayoutManager.VERTICAL, false)
searchArtist(query)
mAdapter.notifyDataSetChanged()
}
return true
}
@SuppressLint("NotifyDataSetChanged")
override fun onQueryTextChange(newText: String?): Boolean {
if(newText != null){
// recyclerView.adapter = mAdapter
// recyclerView.layoutManager = LinearLayoutManager(applicationContext, LinearLayoutManager.VERTICAL, false)
searchArtist(newText)
mAdapter.notifyDataSetChanged()
}
return true
}
})
requestPermissions()
val toolbar = findViewById<Toolbar>(R.id.mainToolbar)
toolbar.setBackgroundColor(Color.rgb(32, 4, 209))
toolbar.setTitleTextColor(Color.WHITE)
toolbar.setTitle(R.string.app_name)
}
private fun requestPermissions()
{
if (PermissionRequestUtil.hasCameraPermissions(this)) {
return
} else {
EasyPermissions.requestPermissions(
this,
"Please accept camera permissions to use this app.",
0,
Manifest.permission.CAMERA
)
}
}
@SuppressLint("NotifyDataSetChanged")
private fun searchArtist(query: String)
{
val searchQuery = "%$query%"
lifecycle.coroutineScope.launch {
mainViewModel.searchArtist(searchQuery).collect { it ->
mAdapter.setData(it)
mAdapter.notifyDataSetChanged()
Log.i(TAG, "new artist List set!!")
}
}
}
override fun onArtistClick(artist: Artist, position: Int) {
TODO("Not yet implemented")
}
}
VideoCallHomeFragment
package com.example.awfc.ui
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.*
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.coroutineScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.awfc.R
import com.example.awfc.adapters.ArtistsAdapter
import com.example.awfc.data.Artist
import com.example.awfc.viewmodels.MainViewModel
import com.todkars.shimmer.ShimmerRecyclerView
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@AndroidEntryPoint
class VideoCallHomeFragment : Fragment() , ArtistsAdapter.OnArtistListener {
private lateinit var mainViewModel: MainViewModel
private val mAdapter by lazy { ArtistsAdapter(this)}
private lateinit var mView: View
private lateinit var artists: List<Artist>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
mView = inflater.inflate(R.layout.fragment_video_call_home, container, false)
setHasOptionsMenu(true)
//val shimmer = mView.findViewById<ShimmerRecyclerView>(R.id.recycler_view)
//shimmer.showShimmer()
setupRecyclerView()
mainViewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)
lifecycle.coroutineScope.launch {
mainViewModel.getArtists().collect {
artists = it
mAdapter.setData(it)
//shimmer.hideShimmer()
}
}
return mView
}
@SuppressLint("CutPasteId")
fun setupRecyclerView()
{
mView.findViewById<RecyclerView>(R.id.recycler_view).adapter = mAdapter
mView.findViewById<RecyclerView>(R.id.recycler_view).layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
}
override fun onArtistClick(artist: Artist, position: Int) {
artists[position]
val intent = Intent(this.context, ArtistDetailsActivity::class.java)
intent.putExtra("artistName", artist.name)
intent.putExtra("arabicName", artist.name_arabic)
intent.putExtra("arabicDesc", artist.description_arabic)
intent.putExtra("artistDesc", artist.description)
intent.putExtra("artistImage", artist.image)
intent.putExtra("artistVideo1", artist.videoUrl1)
intent.putExtra("artistVideo2", artist.videoUrl2)
intent.putExtra("artistVideo3", artist.videoUrl3)
startActivity(intent)
}
}
艺术家适配器
package com.example.awfc.adapters
import android.annotation.SuppressLint
import android.content.ContentValues.TAG
import android.content.Intent
import android.service.autofill.OnClickAction
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.example.awfc.data.Artist
import com.example.awfc.databinding.ArtistRowLayoutBinding
import com.example.awfc.utils.ArtistsDiffUtil
class ArtistsAdapter(var artistListener: OnArtistListener) : RecyclerView.Adapter<ArtistsAdapter.MyViewHolder>() {
private var artists = emptyList<Artist>()
class MyViewHolder(private val binding: ArtistRowLayoutBinding) :
RecyclerView.ViewHolder(binding.root) {
fun init(artist: Artist, action: OnArtistListener)
{
itemView.setOnClickListener {
action.onArtistClick(artist, adapterPosition)
}
}
fun bind(modelClass: Artist) {
binding.result = modelClass
binding.executePendingBindings()
}
companion object {
fun from(parent: ViewGroup): MyViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ArtistRowLayoutBinding.inflate(layoutInflater, parent, false)
return MyViewHolder(binding)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
Log.i(TAG, "OnCreateViewHolder initiated")
return MyViewHolder(
ArtistRowLayoutBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentResult = artists[position]
holder.bind(currentResult)
holder.init(currentResult, artistListener)
Log.i(TAG, "OnBindViewHOlder initiated")
}
override fun getItemCount(): Int {
return artists.size
}
@SuppressLint("NotifyDataSetChanged")
fun setData(newData: List<Artist>) {
val artistsDiffUtil = ArtistsDiffUtil(artists, newData)
val diffUtilResult = DiffUtil.calculateDiff(artistsDiffUtil)
artists = emptyList()
artists = newData
diffUtilResult.dispatchUpdatesTo(this)
this.notifyDataSetChanged()
//this.notifyDataSetChanged()
}
interface OnArtistListener {
fun onArtistClick(artist:Artist, position: Int)
}
}
artistDiffUtil
package com.example.awfc.utils
import androidx.recyclerview.widget.DiffUtil
class ArtistsDiffUtil<T>(
private val oldList: List<T>,
private val newList: List<T>
): DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldList.size
}
override fun getNewListSize(): Int {
return newList.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] === newList[newItemPosition]
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
}
gradleFile
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
id 'kotlin-parcelize'
id 'androidx.navigation.safeargs'
}
android {
compileSdk 31
buildFeatures {
viewBinding true
dataBinding true
}
defaultConfig {
applicationId "com.example.awfc"
minSdk 21
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
javaCompileOptions {
annotationProcessorOptions {
arguments += ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
def room_version = "2.4.2"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"
implementation "com.google.dagger:hilt-android:2.28.3-alpha"
kapt "com.google.dagger:hilt-android-compiler:2.28.3-alpha"
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02"
kapt "androidx.hilt:hilt-compiler:1.0.0-alpha02"
implementation 'com.facebook.shimmer:shimmer:0.5.0'
implementation 'com.todkars:shimmer-recyclerview:0.4.1'
implementation 'de.hdodenhof:circleimageview:3.1.0'
// Image Loading library Coil
implementation "io.coil-kt:coil:0.13.0"
implementation 'com.squareup.picasso:picasso:2.71828'
// UI Tests
androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.1.1'
// When using a AppCompat theme
implementation "com.google.accompanist:accompanist-appcompat-theme:0.16.0"
implementation "com.google.android.material:compose-theme-adapter:1.1.1"
// Lifecycle
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation 'com.yqritc:android-scalablevideoview:1.0.4'
implementation 'com.github.bumptech.glide:glide:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.0'
implementation("javax.inject:javax.inject:1")
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
implementation 'androidx.navigation:navigation-fragment-ktx:2.4.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.4.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
// viewpager2
implementation 'androidx.viewpager2:viewpager2:1.0.0'
//tablayout
implementation 'com.google.android.material:material:1.3.0-alpha04'
// For developers using AndroidX in their applications
implementation 'pub.devrel:easypermissions:3.0.0'
}
您正在 MainActivity
和 VideoCallHomeFragment
中创建两个单独的 ArtistsAdapter
实例。如果 setData
在实际显示 RecyclerView
的片段内工作,听起来适配器工作正常,因为那是可以访问显示数据的实际适配器的那个。
但是在 MainActivity
中的 searchArtist
中,您在完全不同的适配器实例上调用 setData
,该实例未以任何方式连接到 RecyclerView
,所以什么都不会发生。
与其让 activity 尝试与片段中托管的小部件对话,不如让 LiveData
或类似的视图模型包含应该被显示。让 VideoCallHomeFragment
观察到,它可以在适配器上调用 setData
。您的 activity 可以调用 viewModel.getArtists()
或其他任何东西,但是 该函数 应该在内部更新 LiveData
以便观察它的任何对象都能看到要显示的新数据.