Search code examples
kotlinandroid-recyclerviewandroidxfragmentmanagerdialogfragment

How to get a FragmentManager for DialogFragment in Kotlin using Androidx?


I am following a tutorial where the instructor is using the Android support library v7. In my app I am using the androidx version (as suggested on the Android Developer website). When I type the lines of code as instructed, Android Studio puts a strikethrough over part of the code where I try to obtain a FragmentManager and says: "getter for fragmentManager: FragmentManager! is deprecated. Deprecated in Java." I have searched so many posts where people were having similar issues but the solutions provided don't apply to my case. Some users were having mismatched support library versions and others didn't have the proper dependencies in the gradle file. As far as I can tell those issues don't apply here.

According to the androidx documentation for FragmentManager, it states, "Your activity must derive from FragmentActivity to use this. From such an activity, you can acquire the FragmentManager by calling FragmentActivity#getSupportFragmentManager." However, I am not using an Activity, the code is inside an inner class that extends the RecylcerView.ViewHolder class which is nested inside a class extending RecyclerView.Adapter. Is my only choice to use the android support library v7?

RecyclerView Adapter Class:

import android.app.Activity
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.e_product_row.view.*

import androidx.fragment.app.DialogFragment  // greyed out as "unused import directive"
import androidx.fragment.app.FragmentManager // greyed out as "unused import directive"


class EProductAdapter(var context: Context, var arrayList : ArrayList<EProduct>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    val productView = LayoutInflater.from(context).inflate(R.layout.e_product_row, parent, false)
    return ProductViewHolder(productView)
  }

  override fun getItemCount(): Int {
    return arrayList.size
  }

  override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    // downcast holder to ProductViewHolder
    (holder as ProductViewHolder).initializeRowComponents(arrayList.get(position).id,
                                                          arrayList[position].name,
                                                          arrayList[position].price,
                                                          arrayList[position].picture)
  }

  inner class ProductViewHolder(productView: View) : RecyclerView.ViewHolder(productView) {
    fun initializeRowComponents(id: Int, name: String, price: Int, pictureName: String) {
      itemView.txt_id.text = id.toString()
      itemView.txt_name.text = name
      itemView.txt_price.text = price.toString()
      var pictureUrl = "http://192.168.0.21/OnlineStoreApp/osimages/$pictureName"
      pictureUrl = pictureUrl.replace(" ", "%20")
      Picasso.get().load(pictureUrl).into(itemView.img_product)

      // initialize add item imageView
      itemView.img_add_item.setOnClickListener {
        var amountFragment = AmountFragment()
        var fragmentManager = (itemView.context as Activity).fragmentManager // fragmentManager strikethrough text
         amountFragment.show(fragmentManager, "TAG") // show function cannot be called with arguments supplied and won't compile
      }
    }
  }
}

DialogFragment class:

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment

class AmountFragment : DialogFragment() {
  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                            savedInstanceState: Bundle? ): View? {
    return inflater.inflate(R.layout.fragment_amount, container, false)
  }
}

build.gradle(Module: app)

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"

    defaultConfig {
        applicationId "com.bryontaylor.onlinestoreapp"
        minSdkVersion 24
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.android.volley:volley:1.1.1'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'com.squareup.picasso:picasso:2.71828'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.fragment:fragment:1.2.4'
    implementation 'androidx.fragment:fragment-ktx:1.2.4'
}

Solution

  • According to the androidx documentation for FragmentManager, it states, "Your activity must derive from FragmentActivity to use this. From such an activity, you can acquire the FragmentManager by calling FragmentActivity#getSupportFragmentManager." However, I am not using an Activity

    Yes you are:

    var fragmentManager = (itemView.context as Activity).fragmentManager
    

    The only problem is that you're casting to the root Activity type and using the deprecated getFragmentManager(). You need to do exactly as the docs state: use FragmentActivity and getSupportFragmentManager():

    var fragmentManager = (itemView.context as FragmentActivity).supportFragmentManager
    

    Your show() call will then work because you're passing in the correct fragment manager type.

    Hope that helps!