Search code examples
androidkotlinandroid-cardviewandroid-gridviewcardview

Inner class constructor issue when creating adapter for GridView


I'm trying to add some items into a GridView programmatically but it's not working. I have seen answers for similar questions about this error, but I'm not sure of what should be done in this scenario. Creating an outer class or something else?

AdapterItem in adapter.addAdapterItem(MyFragment.AdapterItem(primeNumber)) returns this error:

Constructor of inner class AdapterItem can be called only with receiver of containing class

class MyFragment : androidx.fragment.app.Fragment() {
    private val primeNumbers = arrayOf("2", "3", "5", "7", "11", "13", "17", "19", "23", "29")

    private lateinit var adapter: MyAdapter

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

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        val v = view

        val mainLinearLayout = v!!.findViewById(R.id.my_linearLayout) as LinearLayout
        val cardLinearLayout = LinearLayout(context)

        cardLinearLayout.orientation = LinearLayout.VERTICAL


        val cardView = context?.let { CardView(it) }
        when {
            cardView != null -> {
                cardView.radius = twoDp.toFloat()
                cardView.setContentPadding(36,36,36,36)
                cardView.layoutParams = params
                cardView.cardElevation = twoDp.toFloat()
            }
        }


        val mTitle = TextView(context)
        mTitle.text = "Prime numbers"
        TextViewCompat.setTextAppearance(mTitle, android.R.style.TextAppearance_Large)

        val mGridView = com.companyname.appname.MyGridView(context!!)
        mGridView.columnWidth = 100f
        mGridView.run {
            numColumns = GridView.AUTO_FIT
            stretchMode = GridView.STRETCH_COLUMN_WIDTH
        }
        adapter = MyAdapter(activity!!.applicationContext, 0)
        mGridView.adapter = adapter
        for (primeNumber in primeNumbers) {
            adapter.addAdapterItem(MyFragment.AdapterItem(primeNumber))
        }

        cardLinearLayout.addView(mTitle)
        cardLinearLayout.addView(mGridView)
        cardView!!.addView(cardLinearLayout)
        mainLinearLayout.addView(cardView)

        super.onActivityCreated(savedInstanceState)
    }


    private inner class MyAdapter internal constructor(context: Context, textviewid: Int) : ArrayAdapter<AdapterItem>(context, textviewid) {
        private val items = ArrayList<AdapterItem>()

        internal fun addAdapterItem(item: MyFragment.AdapterItem) {
            items.add(item)
        }

        override fun getCount(): Int {
            return items.size
        }

        override fun getItem(position: Int): MyFragment.AdapterItem? {
            return items[position]
        }

        override fun getItemId(position: Int): Long {
            return position.toLong()
        }

        @NonNull
        override fun getView(position: Int, convertView: View?, @NonNull parent: ViewGroup): View {
            val rowView: View = when (convertView) {
                null -> activity!!.layoutInflater.inflate(R.layout.gridview_item, parent, false)
                else -> convertView
            }

            val tv = rowView.findViewById(R.id.item_gridview) as TextView
            tv.text = items[position].first

            return rowView
        }
    }

    internal inner class AdapterItem // add more items
    (var first: String)
}

GridView class

class MyGridView : GridView {
    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val heightSpec: Int = when {
            layoutParams.height == AbsListView.LayoutParams.WRAP_CONTENT -> View.MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE shr 2, View.MeasureSpec.AT_MOST)
            else -> heightMeasureSpec
        }

        super.onMeasure(widthMeasureSpec, heightSpec)
    }
}

Solution

  • change

    adapter.addAdapterItem(MyFragment.AdapterItem(primeNumber))
    

    to

    adapter.addAdapterItem(AdapterItem(primeNumber))
    

    or it's long form

    adapter.addAdapterItem(this.AdapterItem(primeNumber))
    

    because that way it's trying to use the internal access via this.AdapterItem which uses itself as outer class while your syntax forces it to use the external static way without an outer class.

    You could also just drop inner from your code entirely - as far as I see - since you don't access the outer class from the inner and that's what inner allows.