androidkotlinmvvmandroid-contextandroid-pageradapter

Wrong usage of context and findViewById() in PagerAdapter?


In an existing Android App project (MVVM is used as pattern) I have found a PagerAdapter to swipe several information within this adapter:

class InformationSlideAdapter(ctx: Context) : PagerAdapter() {

    private var contextCopy = ctx

    override fun instantiateItem(container: ViewGroup, position: Int): Any {

        val layoutInflater = contextCopy.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val layoutScreen = layoutInflater.inflate(R.layout.slide_item, null)

        val imageView = layoutScreen.findViewById<ImageView>(R.id.iv_logo)
        //..
    }
}

Question 1: Why is there findViewById() used? Shouldn't databinding solve this issue also for PageAdapters?

Question 2: Whenever I find a context in any other class than my view (especially when MVVM was used), this is very anti pattern for me. Why was a context provided there? Is there a reason for not using

    val imageView = container.findViewById<ImageView>(R.id.iv_logo)

without inflating the two lines ahead?

Question 3: Altough the code is working (for now).. How are copies handled in kotlin?

    private var contextCopy = ctx

Here a complete new copy instance is created in Kotlin? E.g. when I flip the screen, the context in corresponding InformationSlideActivity handles this correctly, but my InformationSlideAdapter still has an old instance of context with the unflipped state?

Unfortunately I cant ask the coder, since he has gone.

Thnx in advance

Pav


Solution

  • Question 1: databinding or synthetics could be used use instead of findViewById. This could be legacy code or given the id of the view, it is possible that there are more views with same id and the developer wanted to avoid ambiguity by searching in a specific layout.

    Question 2: Injecting or passing context (in most cases) is an antipattern. If the context is needed it can be retrieved from the container. the difference between

    layoutScreen.findViewById<ImageView>(R.id.iv_logo)
    

    and

    container.findViewById<ImageView>(R.id.iv_logo)
    

    is that the first one is searching in the newly inflated layout, that may or may not be attached to the container at that point in time.

    Question 3:

    private var contextCopy = ctx
    

    this makes no sense, it is just making a reference copy. Given that the context is passed as a contructor parameter it is possible that the developer didn't know that they could do the following:

    class InformationSlideAdapter(val ctx: Context, list: List<RelevantItem>) : PagerAdapter() {
    

    in either case the context will not be refreshed and to have a new instance the adapter should be recreated As per the answer of question2, the context should not be passed to the adapter and instead retrieved from the container.