為了簡單地描述這個問題,我有一個主要的活動,它有 viewPager2 顯示 2 個片段。主要活動還獲得一個帶有搜索選單選項的工具列。我正在嘗試搜索藝術家,因此它會自動更新第一個片段(videoCallHomefragment)中的回收站視圖。我不知道問題出在哪里,因為這是我除錯此問題的第三天,但我仍然無處可去。
我的假設
- 一定有沖突,因為我正在使用 viewpager2 并嘗試從活動的片段中更新回收站視圖
- 依賴項版本沖突導致“notifyDataSetChanged()”無法正常作業,另一方面,我嘗試了使用 DiffUtil 的替代方法,但仍然無法正常作業
ps應用程式成功檢索藝術家并將它們顯示在回收器視圖中,這表明配接器中的函式“setData”正在作業,但是在搜索藝術家時,呼叫notifyDataSetChanged時不會啟動或呼叫“onBindViewHolder”和“onCreateViewHolder” ()
請參閱下面的代碼片段
主要活動
@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")
}
}
VideoCallHome片段
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)
}
}
藝術家DiffUtil
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]
}
}
分級檔案
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'
}
uj5u.com熱心網友回復:
您正在創建兩個單獨的ArtistsAdapterinMainActivity和VideoCallHomeFragment. 如果setData在RecyclerView實際顯示 .
但是在searchArtistin 中MainActivity,你呼叫setData的是一個完全不同的配接器實體,它沒有以RecyclerView任何方式連接到,所以什么都不會發生。
與其讓活動嘗試與片段中托管的小部件對話,不如LiveData在您的視圖模型中包含應該顯示的資料的或類似的。請VideoCallHomeFragment注意,它可以呼叫setData配接器。您的活動可以呼叫viewModel.getArtists()或其他任何方式,但該函式應在內部更新,LiveData以便任何觀察它的人都會看到要顯示的新資料。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/463595.html
標籤:安卓 科特林 android-recyclerview android-viewpager2
