Ravers
Ravers

Reputation: 1040

Changing list on fragment is changing in other fragments

I have a TabLayout/ViewPager with two fragments in my activity. The tabs are created and then I request some information. When I get this information, I update the RecyclerView of each tab.

Main Activity

private fun setViews() {
    val adapter = TabsAdapter(supportFragmentManager)
    adapter.addFragment(NewsFragment(), getString(R.string.dossier_activity_news))
    adapter.addFragment(PhotosFragment(), resources.getString(R.string.dossier_activity_photos))

    view_pager.adapter = adapter
    tab_layout.setupWithViewPager(view_pager)

    // request info
}

fun setPages(pages: List<Page>) {
    // got info

    ((view_pager.adapter as TabsAdapter).getItem(0) as NewsFragment).setPages(pages)
    ((view_pager.adapter as TabsAdapter).getItem(1) as PhotosFragment).setPages(pages)
}

The problem is: In the second tab(PhotosFragment), I want for remove all pages that does not contain a photo/thumbnail.

NewsFragment

fun setPages(pages: List<Page>) {
    if (pages.isNotEmpty()) recycler_view.adapter = PagesAdapter(this, pages)
}

PhotosFragment

fun setPages(pages: List<Page>) {
    val iterator = (pages as ArrayList<Page>).iterator()
    while (iterator.hasNext()) if (iterator.next().thumbnail == null) iterator.remove()
    if (pages.isNotEmpty()) recycler_view.adapter = PagesAdapter(this, pages)
}

When I create this iterator on the second tab, all the pages on the first fragment are also updated to no photos/thumbnails pages. Each fragment has is own life cycle and by changing the content of one fragment it should not update the other right?

Could this be because of my PagesAdapter extend RecyclerView?

PagesAdapter

class PagesAdapter(private var fragment: Fragment, private var pages: List<Page>): RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, type: Int): RecyclerView.ViewHolder {
        return when (type) {
            0 -> HeaderViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.article_header_item, parent, false))
            else -> ArticleViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.article_item, parent, false))
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val type = getItemViewType(position)
        when (type) {
            0 -> setHeader(holder as PagesAdapter.HeaderViewHolder, position)
            else -> setArticle(holder as PagesAdapter.ArticleViewHolder, position)
        }
    }

    inner class HeaderViewHolder internal constructor(view: View) : RecyclerView.ViewHolder(view) {
        val layout: RelativeLayout = view.article_header_layout
        val image: ImageView = view.article_header_image
        val title: AOTextView = view.title_header_text
        val date: AOTextView = view.date_header_text
    }

    inner class ArticleViewHolder internal constructor(view: View) : RecyclerView.ViewHolder(view) {
        val layout: RelativeLayout = view.article_layout
        val image: ImageView = view.article_image
        val strapline: AOTextView = view.strapline_text
        val title: AOTextView = view.title_text
        val date: AOTextView = view.date_text
    }
}

Both fragments have the same pages list, but I want the second fragment to filter this list to show only pages with photos/thumbnails. By filtering the list in the second fragment, the first one shows the same filtered list. Should I aproach this differently? Or is some bug in my code?

Upvotes: 1

Views: 92

Answers (1)

michalbrz
michalbrz

Reputation: 3494

You are sharing one list between two fragments, which is not a good idea. Kotlin favors immutability and in it should be the default way of doing things, unless you have very good reason.

Two fragments are sharing list reference and that's why when one of it changes it, those changes are reflected in the other fragment.

What you should do is instead of

fun setPages(pages: List<Page>) {
    val iterator = (pages as ArrayList<Page>).iterator()
    while (iterator.hasNext()) if (iterator.next().thumbnail == null) iterator.remove()
    if (pages.isNotEmpty()) recycler_view.adapter = PagesAdapter(this, pages)
}

you should write:

fun setPages(pages: List<Page>) {
    val pagesWithThumbnails = pages.filter { it.thumbnail != null }
    if (pagesWithThumbnails.isNotEmpty()) recycler_view.adapter = PagesAdapter(this, pagesWithThumbnails)
}

There you don't modify original list while having more readable and error-proof code.

Upvotes: 2

Related Questions