How to add search functionality for cardview recyclerview in android kotlin? - android

SearchAdapter.kt
class SearchAdapter(ctx:Context,private val imageModelArrayList: ArrayList<SearchModel>) :
RecyclerView.Adapter<SearchAdapter.MyViewHolder>() {
private val inflater: LayoutInflater
private val arraylist: java.util.ArrayList<SearchModel>
init {
inflater = LayoutInflater.from(ctx)
this.arraylist = java.util.ArrayList<SearchModel>()
this.arraylist.addAll(MainActivity.imageModelArrayList)
}
override fun onBindViewHolder(holder: SearchAdapter.MyViewHolder, position: Int) {
holder.time.setText(imageModelArrayList[position].getOrders())
}
override fun getItemCount(): Int {
return imageModelArrayList.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchAdapter.MyViewHolder {
val view = inflater.inflate(R.layout.view_orderhistory, parent, false)
return MyViewHolder(view)
}
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var time: TextView
init {
time = itemView.findViewById(R.id.ordernumber) as TextView
}
}
fun filter(charText: String) {
var charText = charText
charText = charText.toLowerCase(Locale.getDefault())
MainActivity.imageModelArrayList.clear()
if (charText.length == 0) {
MainActivity.imageModelArrayList.addAll(arraylist)
} else {
for (wp in arraylist) {
if (wp.getOrders().toLowerCase(Locale.getDefault()).contains(charText)) {
MainActivity.imageModelArrayList.add(wp)
}
}
}
notifyDataSetChanged()
}
}
SearchModel.kt
class SearchModel {
var order: String? = null
private val image_drawable: Int = 0
fun getOrders(): String {
return order.toString()
}
fun setOrders(order: OrderHistory) {
this.order = order.toString()
}
}
I have written the code for populating the list. Code is running without any errors but my search functionality is not working.
MainActivity.kt
class MainActivity : AppCompatActivity(),SearchView.OnQueryTextListener {
private var recyclerView: RecyclerView? = null
private var adapter: SearchAdapter? = null
private var editsearch: SearchView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView=findViewById(R.id.listOfBookings) as? RecyclerView
imageModelArrayList = populateList()
Log.d("hjhjh", imageModelArrayList.size.toString() + "")
adapter = SearchAdapter(this, imageModelArrayList)
recyclerView?.adapter = adapter
recyclerView?.layoutManager = LinearLayoutManager(applicationContext, LinearLayoutManager.VERTICAL, false)
recyclerView?.addOnItemTouchListener(
RecyclerTouchListener(
applicationContext,
recyclerView!!,
object : ClickListener {
override fun onClick(view: View, position: Int) {
Toast.makeText(this#MainActivity, imageModelArrayList[position].getOrders(), Toast.LENGTH_SHORT)
.show()
}
override fun onLongClick(view: View?, position: Int) {
}
})
)
editsearch = findViewById(R.id.searchView) as SearchView
editsearch?.setOnQueryTextListener(this)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
adapter!!.filter(newText)
return false
}
private fun populateList(): ArrayList<SearchModel> {
val list = ArrayList<SearchModel>()
val xyz=HomeFragment().orderHistoryList
for (i in 0 until xyz.size-1) {
//var xyz=HomeFragment().orderHistoryList
var order=""
val imageModel = SearchModel()
imageModel.setOrders(xyz[i])
list.add(imageModel)
}
return list
}
interface ClickListener {
fun onClick(view: View, position: Int)
fun onLongClick(view: View?, position: Int)
}
internal class RecyclerTouchListener(
context: Context,
recyclerView: RecyclerView,
private val clickListener: ClickListener?
) : RecyclerView.OnItemTouchListener {
private val gestureDetector: GestureDetector
init {
gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(e: MotionEvent): Boolean {
return true
}
override fun onLongPress(e: MotionEvent) {
val child = recyclerView.findChildViewUnder(e.x, e.y)
if (child != null && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildAdapterPosition(child))
}
}
})
}
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
val child = rv.findChildViewUnder(e.x, e.y)
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildAdapterPosition(child))
}
return false
}
override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
}
}
companion object {
lateinit var imageModelArrayList: ArrayList<SearchModel>
}
}
In the HomeFragment I have the list(OrderHistoryList) which stores the order,status and date values. I am storing those list values in another list "ImageModelArrayList" for which i have written the functionality.
HomeFragment.kt
class HomeFragment : Fragment() {
private lateinit var orderHistoryViewModel: OrderHistoryViewModel
private lateinit var activityBinding: FragmentHomeBinding
var orderHistoryList:ArrayList<OrderHistory> = ArrayList()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return setupBindings(inflater, container, savedInstanceState)
}
private fun setupBindings(
inflater: LayoutInflater,
container: ViewGroup?, savedInstanceState: Bundle?
): View? {
//val activityBinding: FragmentHomeBinding = DataBindingUtil.setContentView(this.context as MainActivity, R.layout.fragment_home) as FragmentHomeBinding
activityBinding = FragmentHomeBinding.inflate(inflater, container, false)
orderHistoryViewModel = ViewModelProviders.of(this).get(OrderHistoryViewModel::class.java)
if (savedInstanceState == null) {
orderHistoryViewModel.init()
}
activityBinding.model = orderHistoryViewModel
setupListUpdate()
return (activityBinding as ViewDataBinding).root
}
fun setupListUpdate(){
orderHistoryViewModel.init()
orderHistoryViewModel.loading?.set(View.VISIBLE)
var orderHistoryDetails : OrderHistoryDetails = OrderHistoryDetails()
orderHistoryList.add(OrderHistory(order ="#102-AB-3045",status="Intransit",Date="11 Dec"))
orderHistoryList.add(OrderHistory(order ="#102-AB-3047",status="Delivered",Date="13 Dec"))
orderHistoryList.add(OrderHistory(order ="#102-AB-3048",status="Delivered",Date="12 Dec"))
orderHistoryList.add(OrderHistory(order ="#102-AB-3049",status="Delivered",Date="14 Dec"))
orderHistoryList.add(OrderHistory(order ="#102-AB-3056",status="Delivered",Date="16 Dec"))
orderHistoryList.add(OrderHistory(order ="#102-AB-3089",status="Delivered",Date="15 Dec"))
orderHistoryList.add(OrderHistory(order ="#102-AB-3090",status="Delivered",Date="17 Dec"))
orderHistoryDetails.orderHistoryList =orderHistoryList
orderHistoryDetails.orderList =MutableLiveData()
orderHistoryDetails.orderList?.value=orderHistoryDetails.orderHistoryList
orderHistoryDetails.orderList?.observe(this,
Observer<List<OrderHistory>> { bookings ->
orderHistoryViewModel.loading.set(View.GONE)
if (bookings.isEmpty()) {
orderHistoryViewModel.showEmpty.set(View.VISIBLE)
} else {
orderHistoryViewModel.showEmpty.set(View.GONE)
orderHistoryViewModel.setBookingsInAdapter(bookings)
}
})
orderHistoryViewModel.orderHistoryDetails=orderHistoryDetails
}
}

You can view these link its java guide but helpful for you
https://velmm.com/android-recyclerview-search-filter-example/
https://demonuts.com/recyclerview-search-filter/

Related

Recycler view item on click not working properly after searchview kotlin

I have implemented recyclerview with searchview in my app. But on clicking the item after search, my app crashes.
My app works fine when item on list is clicked before search.
It only stops working when clicking search result.
App Screen Record
My code for listview
class BookFragment : Fragment() , SearchView.OnQueryTextListener {
private var columnCount = 1
private lateinit var bookViewModel: BookViewModel
private val myAdapter: BookAdapter by lazy { BookAdapter(requireContext()) }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.main_book_list, container, false)
val recyclerView: RecyclerView = view.findViewById(R.id.mainList)
val fab_add_button: FloatingActionButton = view.findViewById(R.id.FAB_add_new)
setHasOptionsMenu(true)
bookViewModel = ViewModelProvider(this)[BookViewModel::class.java]
bookViewModel.allBooks.observe(viewLifecycleOwner) { books ->
myAdapter.setBooks(books)
}
with(recyclerView) {
adapter = myAdapter
layoutManager = when {
columnCount <= 1 -> LinearLayoutManager(context)
else -> GridLayoutManager(context, columnCount)
}
}
fab_add_button.setOnClickListener {
findNavController().navigate(R.id.action_bookFragment_to_addFragment)
}
postponeEnterTransition()
recyclerView.doOnPreDraw {
startPostponedEnterTransition()
}
return view
}
#Deprecated("Deprecated in Java")
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.list_menu, menu)
val search = menu.findItem(R.id.list_menu_search)
val searchView = search.actionView as SearchView
searchView.isSubmitButtonEnabled = true
searchView.setOnQueryTextListener(this)
}
#Deprecated("Deprecated in Java")
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.list_menu_setting -> findNavController().navigate(R.id.action_bookFragment_to_settingsFragment)
}
return super.onOptionsItemSelected(item)
}
override fun onQueryTextSubmit(query: String?): Boolean {
if (query != null ) searchDB(query)
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
if (newText != null ) searchDB(newText)
return true
}
private fun searchDB(string: String) {
val query = "%$string%"
bookViewModel.fetchSearchedBook(query).observe(viewLifecycleOwner) { resp ->
myAdapter.setBooks(resp)
}
}
}
My Adapter Code
class BookAdapter(context: Context) : RecyclerView.Adapter<BookAdapter.ViewHolder>() {
private var books = emptyList<LightNovel>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
SingleBookBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = books[position]
holder.idView.text = item.id.toString()
holder.contentView.text = item.title
Glide.with(holder.itemView.context)
.load(item.coverRemote)
.error(R.drawable.ic_image_error)
.into(holder.imageView)
holder.itemView.setOnClickListener {
holder.itemView.findNavController().navigate(R.id.action_bookFragment_to_detailFragment)
val action = BookFragmentDirections.actionBookFragmentToDetailFragment(item.id)
holder.itemView.findNavController().navigate(action)
}
}
override fun getItemCount(): Int = books.size
inner class ViewHolder(binding: SingleBookBinding) : RecyclerView.ViewHolder(binding.root) {
val idView: TextView = binding.itemNumber
val contentView: TextView = binding.content
val imageView: ImageView = binding.listCover
override fun toString(): String {
return super.toString() + " '" + contentView.text + "'"
}
}
#SuppressLint("NotifyDataSetChanged")
fun setBooks(lightNovels: List<LightNovel>) {
this.books = lightNovels
notifyDataSetChanged()
}
}
And Detail Fragment
class DetailFragment : Fragment() {
private val args: DetailFragmentArgs by navArgs()
private var _binding: FragmentDetailBinding? = null
private val binding get() = _binding!!
private lateinit var bookViewModel: BookViewModel
private lateinit var bookLN: LightNovel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentDetailBinding.inflate(inflater, container, false)
val view = binding.root
val bookid = args.bookID
setHasOptionsMenu(true)
bookViewModel = ViewModelProvider(this)[BookViewModel::class.java]
bookViewModel
.fetchLiveBook(bookid)
.observe(viewLifecycleOwner) {
book ->
bookLN = book
binding.detailTitle.text = book.title
val image = binding.detailCover
val imageUrl = bookLN.coverRemote
val valid = URLUtil.isValidUrl(imageUrl)
if (valid) {
Glide.with(requireContext())
.load(bookLN.coverRemote)
.error(R.drawable.ic_image_error)
.into(image)
}
if (book.synopsis != null && book.synopsis.length >= 2) {
binding.detailSynopsis.text = book.synopsis
}
if (URLUtil.isValidUrl(book.download)) {
binding.detailButton.setBackgroundColor(Color.RED) }
binding.detailButton.setOnClickListener {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(book.download))
try {
startActivity(intent)
} catch (_: ActivityNotFoundException) {
}
}
}
return view
}
#Deprecated("Deprecated in Java")
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.detail_menu, menu)
}
#Deprecated("Deprecated in Java")
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.detail_menu_update_book -> {
val action = DetailFragmentDirections.actionDetailFragmentToUpdateFragment(args.bookID)
findNavController().navigate(action)
}
R.id.detail_menu_delete_book -> {
deleteBook(bookLN)
}
}
return super.onOptionsItemSelected(item)
}
private fun deleteBook(Ln: LightNovel) {
val builder = AlertDialog.Builder(requireContext())
builder.setPositiveButton("Delete") {_,_ ->
bookViewModel.deleteBook(Ln)
findNavController().navigate(R.id.action_detailFragment_to_bookFragment)
}
builder.setNegativeButton("Cancel") {_,_ ->}
builder.setTitle("Delete Entry?")
builder.setMessage("Are you sure you want to delete ${Ln.title}")
builder.create().show()
}
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
}
I think it might be due to bookViewModel.fetchLiveBook(bookid) not working. But I do not know where it is not working.
Logcat shows following
FATAL EXCEPTION: main
Process: com.knight.moonreaderdatabase, PID: 21562
java.lang.IllegalStateException: Can't access the Fragment View's LifecycleOwner when getView() is null i.e., before onCreateView() or after onDestroyView()
at androidx.fragment.app.Fragment.getViewLifecycleOwner(Fragment.java:377)
at com.knight.moonreaderdatabase.fragments.list.BookFragment.searchDB(BookFragment.kt:98)
at com.knight.moonreaderdatabase.fragments.list.BookFragment.onQueryTextChange(BookFragment.kt:92)
at androidx.appcompat.widget.SearchView.onTextChanged(SearchView.java:1198)
at androidx.appcompat.widget.SearchView$10.onTextChanged(SearchView.java:1736)
at android.widget.TextView.sendOnTextChanged(TextView.java:10586)
at android.widget.TextView.setText(TextView.java:6322)
at android.widget.TextView.setText(TextView.java:6147)
at android.widget.EditText.setText(EditText.java:121)
at android.widget.TextView.setText(TextView.java:6099)
at androidx.appcompat.widget.SearchView.setQuery(SearchView.java:579)
at androidx.appcompat.widget.SearchView.onActionViewCollapsed(SearchView.java:1295)
at androidx.appcompat.widget.Toolbar$ExpandedActionViewMenuPresenter.collapseItemActionView(Toolbar.java:2656)
at androidx.appcompat.view.menu.MenuBuilder.collapseItemActionView(MenuBuilder.java:1384)
at androidx.appcompat.view.menu.MenuBuilder.clear(MenuBuilder.java:607)
at androidx.appcompat.app.AppCompatDelegateImpl.doInvalidatePanelMenu(AppCompatDelegateImpl.java:2183)
at androidx.appcompat.app.AppCompatDelegateImpl$2.run(AppCompatDelegateImpl.java:273)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:975)
at android.view.Choreographer.doCallbacks(Choreographer.java:799)
at android.view.Choreographer.doFrame(Choreographer.java:730)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:960)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:236)
at android.app.ActivityThread.main(ActivityThread.java:7864)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:620)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1011)

Kotlin RecyclerView MVVM data not showing

I have a RecyclerView in MVVM project. I have to get text from editText (searchWordEt) and then pass it to the function that invokes API method in viewmodel.API works fine and returns data. But when I invoke searchDefAdapter.submitList(response) in SearchFragment nothing happens and RecyclerView data not showing.
class SearchDefAdapter(
private var infoListener: OnItemClickListener,
private var addListener: OnItemClickListener
):
ListAdapter<Def, SearchDefViewHolder>(differCallback) {
interface OnItemClickListener {
fun onItemClick(position: Int)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchDefViewHolder {
return SearchDefViewHolder(
SearchWordCardBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
),
addListener,
infoListener
)
}
override fun onBindViewHolder(holder: SearchDefViewHolder, position: Int) {
holder.bind(getItem(position))
}
}
class SearchDefViewHolder(
private val binding: SearchWordCardBinding,
addListener: SearchDefAdapter.OnItemClickListener,
infoListener: SearchDefAdapter.OnItemClickListener
): RecyclerView.ViewHolder(binding.root) {
fun bind(data: Def) {
with (binding) {
searchCardTv.text = "${data.text} - ${data.tr[0].text}"
}
}
init {
binding.addSearchCard.setOnClickListener {
addListener.onItemClick(adapterPosition)
}
binding.infoSearchCard.setOnClickListener {
infoListener.onItemClick(adapterPosition)
}
}
}
val differCallback = object : DiffUtil.ItemCallback<Def>() {
override fun areItemsTheSame(oldItem: Def, newItem: Def): Boolean {
return oldItem.text == newItem.text
}
override fun areContentsTheSame(oldItem: Def, newItem: Def): Boolean {
return oldItem == newItem
}
}
#AndroidEntryPoint
class SearchFragment : Fragment() {
private var _binding: FragmentSearchBinding? = null
private val binding get() = _binding!!
lateinit var searchDefAdapter: SearchDefAdapter
private val viewModel: DictionaryViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentSearchBinding.inflate(inflater, container, false)
val view = binding.root
searchDefAdapter = SearchDefAdapter(
object : SearchDefAdapter.OnItemClickListener {
override fun onItemClick(position: Int) {
Log.d("tag", "Item Added!")
//viewModel.saveWord(position)
}
},
object : SearchDefAdapter.OnItemClickListener {
override fun onItemClick(position: Int) {
val wordFragment = WordFragment()
fragmentManager?.beginTransaction()?.replace(
R.id.nav_host_fragment_container,
wordFragment
)?.commit()
}
}
)
setUpRecyclerView(searchDefAdapter)
var job: Job? = null
binding.searchWordEt.addTextChangedListener { editable ->
job?.cancel()
job = MainScope().launch {
delay(SEARCH_WORD_TIME_DELAY)
editable?.let {
if (editable.toString().isNotEmpty())
viewModel.getTranslation(editable.toString())
}
}
}
viewModel.def.observe(viewLifecycleOwner, Observer { response ->
binding.apply {
searchDefAdapter.submitList(response)
}
})
return view
}
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
private fun setUpRecyclerView(adapter: SearchDefAdapter){
binding.searchRv.apply {
adapter
layoutManager = LinearLayoutManager(activity)
}
}
}
You haven't actually set the adapter in setUpRecyclerView()
private fun setUpRecyclerView(myAdapter: SearchDefAdapter){
binding.searchRv.apply {
layoutManager = LinearLayoutManager(activity)
adapter = myAdapter // here
}
}

RecyclerView SelectionTracker unable to keep track after navigating back to fragment

In my scenario, I have two fragments. In my first Fragment I have a RecyclerView with SelectionTracker. After selecting an item in my first fragment I can navigate to the second fragment. But from my second fragment if I navigate back to the first fragment using back button all my previous selection is lost. How can I prevent this?
I am using Jetpack Navigation Component to handle Fragment navigation.
Here is my fragment
class SelectVideoForCourseFragment : Fragment(R.layout.fragment_select_video_for_course) {
.....
..
private val adapter by lazy { MediaListAdapter() }
private lateinit var selectionTracker: SelectionTracker<String>
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initializeListeners()
initializeRecyclerView(savedInstanceState)
fetchMedias()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
selectionTracker.onSaveInstanceState(outState)
}
private fun fetchMedias() {
val mediaRepo = MediaRepo()
mediaRepo.getVideos(contentResolver).observe(viewLifecycleOwner) {
adapter.submitItems(it)
}
}
private fun initializeRecyclerView(savedInstanceState: Bundle?) {
binding.mediaList.layoutManager = GridLayoutManager(requireContext(), 3)
binding.mediaList.addItemDecoration(GridSpacingItemDecoration(3, 5.dp, false))
binding.mediaList.adapter = adapter
selectionTracker = SelectionTracker.Builder(
"tracker-select-video-for-course",
binding.mediaList,
MediaItemKeyProvider(adapter),
MediaItemDetailsLookup(binding.mediaList),
StorageStrategy.createStringStorage()
).withSelectionPredicate(
SelectionPredicates.createSelectSingleAnything()
).build()
if (savedInstanceState != null) {
selectionTracker.onRestoreInstanceState(savedInstanceState)
}
adapter.tracker = selectionTracker
}
......
...
}
My RecyclerView Adapter:
class MediaListAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
val differ = AsyncListDiffer(this, DIFF_CALLBACK_MEDIA)
var tracker: SelectionTracker<String>? = null
fun submitItems(updatedItems: List<Any>) {
differ.submitList(updatedItems)
}
fun getSelections(): List<MediaEntity> {
....
..
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == 1) {
val binding = ListItemImageBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
ViewHolderImage(binding)
} else {
val binding = ListItemVideoBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
ViewHolderVideo(binding)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is ViewHolderImage) {
tracker?.let {
val item = differ.currentList[position] as ImageEntity
holder.bind(item , it.isSelected(item.uri.toString()))
}
} else {
holder as ViewHolderVideo
val item = differ.currentList[position] as VideoEntity
tracker?.let {
holder.bind(item, it.isSelected(item.uri.toString()))
}
}
}
override fun getItemCount(): Int = differ.currentList.size
override fun getItemViewType(position: Int): Int {
return if (differ.currentList[position] is ImageEntity) {
1
} else {
2
}
}
inner class ViewHolderImage(
private val binding: ListItemImageBinding): RecyclerView.ViewHolder(binding.root
) {
fun bind(item: ImageEntity, isSelected: Boolean) {
.....
...
}
fun getItemDetails(): ItemDetailsLookup.ItemDetails<String> =
object : ItemDetailsLookup.ItemDetails<String>() {
override fun getPosition(): Int = absoluteAdapterPosition
override fun getSelectionKey(): String {
val item = differ.currentList[absoluteAdapterPosition] as ImageEntity
return item.uri.toString()
}
override fun inSelectionHotspot(e: MotionEvent): Boolean = true
}
}
inner class ViewHolderVideo(
private val binding: ListItemVideoBinding,
): RecyclerView.ViewHolder(binding.root) {
fun bind(item: VideoEntity, isSelected: Boolean) {
.....
...
}
fun getItemDetails(): ItemDetailsLookup.ItemDetails<String> =
object : ItemDetailsLookup.ItemDetails<String>() {
override fun getPosition(): Int = absoluteAdapterPosition
override fun getSelectionKey(): String {
val item = differ.currentList[absoluteAdapterPosition] as VideoEntity
return item.uri.toString()
}
override fun inSelectionHotspot(e: MotionEvent): Boolean = true
}
}
companion object {
val DIFF_CALLBACK_MEDIA = object: DiffUtil.ItemCallback<Any>() {
.....
...
}
}
}

I put the search function in the recyclerView. Items are not only seen as new data, but new data seems to be filled up a little on old data. in kotlin

Pressing the search button in Main Activity changes the values of the items in RecyclerView.
The problem is that the existing data remains except for the newly retrieved data.
How can I show you only the new values on the list?
--- MainActivity.kt ----
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var toolbar: Toolbar
private var logTag : String? = "로그 MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
Log.d(logTag,"onCreate is called")
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
toolbar = binding.searchToolbar
setContentView(view)
setSupportActionBar(toolbar)
val navView: BottomNavigationView = binding.navView
val navController : NavController = findNavController(R.id.nav_host_fragment)
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.A, R.id.B, R.id.C
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
binding.btnSearch.setOnClickListener {
val recordFragment = RecordFragment()
val bundle = Bundle()
if ( binding.etSearch.text.toString() ==""|| binding.etSearch.text.isEmpty()) {
bundle.putString("parameter", "A")
}else {
bundle.putString("parameter", binding.etSearch.text.toString())
}
recordFragment.arguments = bundle
this.supportFragmentManager.beginTransaction().replace(R.id.nav_host_fragment, recordFragment).commit()
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.record_app_bar, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.item_search -> {
when (binding.loSearch.visibility) {
GONE -> binding.loSearch.visibility = VISIBLE
VISIBLE -> binding.loSearch.visibility = GONE
else -> {
Log.d(logTag, "onOptionsItemSelected is called // error")
}
}
}
}
return super.onOptionsItemSelected(item)
}
}
class RecordFragment : Fragment() {
private var rRecyclerView: RecyclerView? = null
private val rApi: ApiInterface? = HttpClient.getRetrofit()?.create(ApiInterface::class.java)
private var EventName : String? = null
var logTag : String? = "로그 RecordFragment"
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_record, container, false)
EventName = arguments?.getString("parameter")
if (EventName == null||EventName =="") {
EventName = ""
}
rRecyclerView = root.findViewById(R.id.recordRecyclerView)
rRecyclerView?.layoutManager = LinearLayoutManager(context)
val rAdapter = Radapter()
rRecyclerView?.adapter = rAdapter
//쿼리 값을 Map 으로 생성하여 api 호출
val queries = mapOf("parameter" to EventName)
val call: Call<Record?>? = rApi!!.getRecordData(queries)
call?.enqueue(object : Callback<Record?> {
#SuppressLint("NotifyDataSetChanged")
override fun onResponse(
call: Call<Record?>,
response: retrofit2.Response<Record?>
) {
//응답 성공시 어댑터에 결과 전달
val result: Record = response.body() as Record
Log.d(logTag, "onResponse: refresh 직전")
rAdapter.setList(result.data)
rAdapter.notifyDataSetChanged()
//rAdapter.notifyItemRangeChanged(0, result.data?.size!!);
}
override fun onFailure(call: Call<Record?>, t: Throwable) {
Log.e("D/OkHttp", "onFailure - message=" + t.message)
}
})
return root
}
override fun onDestroyView() {
super.onDestroyView()
rRecyclerView?.adapter = null
rRecyclerView = null
}
inner class Radapter : RecyclerView.Adapter<RecordFragment.Radapter.RvhItem>() {
private var showMatchCount: Int? = 0
private var matchCount: Int? = 0
private var mRecord: ArrayList<Event>? = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RvhItem {
val vhView = LayoutInflater.from(parent.context).inflate(R.layout.vh_record, parent, false)
return RvhItem(vhView)
}
#SuppressLint("NotifyDataSetChanged")
fun setList(Data: List<Event>?) {
mRecord!!.clear()
mRecord!!.addAll(Data!!)
notifyDataSetChanged()
}
#SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: RvhItem, position: Int) {
val record: Event = mRecord!![position]
holder.EventName.text = record._event_name
holder.EventDate.text = record._event_date
showMatchCount = record._event_count?.toInt()
matchCount = record._event_result!!.size
}
override fun getItemCount(): Int {
return mRecord!!.size
}
inner class RvhItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
var EventName: TextView = itemView.findViewById(R.id.tv_event_name)
var EventDate: TextView = itemView.findViewById(R.id.tv_fighter_ranking)
}
}
}

Why is my listener not being called within the recycler view adapter?

I have a RecyclerView with a list of players. I want to call my listener when a player is clicked. I have logs for when a player is clicked and another where the listener is implemented. The log where the listener is implemented is not printing out. Does anyone see anything wrong?
TeamSelectionAdapter:
class TeamSelectionAdapter internal constructor(
context: Context,
val listener: TeamSelectionAdapterListener
) : ListAdapter<Player, RecyclerView.ViewHolder>(DIFF_CALLBACK) {
private val inflater: LayoutInflater = LayoutInflater.from(context)
interface TeamSelectionAdapterListener {
fun onPlayerTouched(currentPlayer: Player)
}
inner class TeamViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
private val playerCard = itemView.findViewById<MaterialCardView>(R.id.player_card)
fun bind(player: Player){
playerCard.setOnClickListener {
logDebug("Clicked! Now to call listener")
listener.onPlayerTouched(player)
}
}
}
override fun getItemCount() = currentList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val playerItemView: View = inflater.inflate(R.layout.playercard_draggable, parent, false)
return TeamViewHolder(playerItemView)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as TeamViewHolder).bind(getItem(position))
}
internal fun setTeams(playerList: List<Player>){
submitList(playerList)
}
companion object {
val TAG = PlayerListAdapter::class.java.toString()
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Player>() {
override fun areItemsTheSame(oldItem: Player, newItem: Player): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: Player, newItem: Player): Boolean {
return oldItem.id == newItem.id
}
}
}
}
TeamFragment:
class TeamCardFragment: BaseFragment() {
private lateinit var teamBackgroundImage: ImageView
private lateinit var teamRecyclerView: RecyclerView
private lateinit var teamSelectionAdapter: TeamSelectionAdapter
private var teamNumber: Int = -1
private var isDropped: Boolean = false
override fun onInflate(context: Context, attrs: AttributeSet, savedInstanceState: Bundle?) {
super.onInflate(context, attrs, savedInstanceState)
context.obtainStyledAttributes(attrs, R.styleable.TeamSelection).apply {
teamNumber = getInt(R.styleable.TeamSelection_teamNumber, -1)
logDebug("teamNumber: $teamNumber")
recycle()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
teamSelectionAdapter = TeamSelectionAdapter(requireContext(), object : TeamSelectionAdapter.TeamSelectionAdapterListener {
override fun onPlayerTouched(currentPlayer: Player) {
Log.d("******", "****player selected: $currentPlayer")
playerViewModel.setSelectedPlayerId(currentPlayer.playerId)
}
})
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.team_card, container, false)
teamBackgroundImage = view.findViewById(R.id.teamBackground)
teamBackgroundImage.setBackgroundColor(resources.getColor(R.color.color_on_secondary,null))
teamBackgroundImage.background.alpha = 50
teamRecyclerView = view.findViewById(R.id.player_card_recyclerView)
teamRecyclerView.adapter = teamSelectionAdapter
teamRecyclerView.setOnDragListener { v, event ->
val viewSource = event.localState as View
val viewId = v.id
when(event.action){
DragEvent.ACTION_DRAG_ENTERED -> {
when(viewId){
teamRecyclerView.id -> {
logDebug("team $teamNumber drag entered")
}
}
}
DragEvent.ACTION_DROP -> {
isDropped = true
when(viewId){
teamRecyclerView.id -> {
playerViewModel.selectedPlayer.value?.let{
playerViewModel.updatePlayerTeam(teamNumber,it.playerId)
}
}
}
}
}
true
}
playerViewModel.allPlayers.reobserve(this){
logDebug("players changed: $it")
it?.let{ playerList ->
val teamPlayers = playerList.filter { player -> player.team == teamNumber }
teamSelectionAdapter.setTeams(teamPlayers)
}
}
return view
}
}

Categories

Resources