I cannot get fragment to work in a Kotlin project

neelshenning

I have a Java project with three fragments that works perfectly. I am trying to translate the project into Kotlin. Everything works so far, except the first (and only complete so far) fragment. The fragments do load as they should but the first fragment's adapter's functions

onCreateViewHolder(parent: ViewGroup, viewType: Int)

and

onBindViewHolder(viewHolder: MyViewHolder, i: Int)

never execute so the empty fragment is displayed in the user's interface. What am I missing, please?

Here is my FragmentMainEntries:

class FragmentMainEntries() : Fragment() {
    private lateinit var binding: FragmentMainEntriesBinding
    private var foodList = ArrayList<Item>()
    private var tableRowAdapter = MainFragAdapter(foodList)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?
    ): View? {

        prepareList()
        //Toast.makeText(activity, "foodList 9 = "+foodList.size, Toast.LENGTH_LONG).show()

        binding = FragmentMainEntriesBinding.inflate(layoutInflater)
        val view = binding.root
        val recyclerView = view.findViewById<RecyclerView>(R.id.recycleView)
        recyclerView.layoutManager = LinearLayoutManager(view.context)
        tableRowAdapter = MainFragAdapter(foodList)
        binding.recycleView.adapter = tableRowAdapter

        return inflater.inflate(R.layout.fragment_main_entries, container, false)
    }


    private fun prepareList()
    {

        //Toast.makeText(activity, "prepareList()", Toast.LENGTH_SHORT).show()
        try {
            foodList.clear()
            for (i in Tables.finalTable.indices) {
                val item = Item(Tables.finalTable[i]?.get(0) as Int,
                    Tables.finalTable[i]?.get(2) as String,
                    Tables.finalTable[i]?.get(3).toString(),
                    Tables.finalTable[i]?.get(4).toString().toFloat(),
                    Tables.finalTable[i]?.get(8).toString().toFloat())
                foodList.add(item)
            }
           // Toast.makeText(activity, "foodList8 = "+foodList.size, Toast.LENGTH_LONG).show()
        }
        catch(e: Exception)
        {
           Toast.makeText(activity, "MAIN ACTIVITY EXCEPTION002\n" + e.message , Toast.LENGTH_LONG).show()
           Thread.sleep(6000)
        }
    }

    companion object {

        @JvmStatic
        fun newInstance() = FragmentMainEntries().apply {

        }
    }
    }

Here is my adapter:

import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import android.widget.TextView
    import android.widget.Toast
    import androidx.recyclerview.widget.RecyclerView


    class MainFragAdapter(private var foodArrayList: MutableList<Item>) : 
    RecyclerView.Adapter<MainFragAdapter.MyViewHolder>()
    {
    lateinit var view: View

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {

        view = LayoutInflater.from(parent.context).inflate(R.layout.item_row, parent, false)
        Toast.makeText(view.context, "foodArrayList5 = "+foodArrayList.size, Toast.LENGTH_SHORT).show()
        return MyViewHolder(view)
    }

    override fun onBindViewHolder(viewHolder: MyViewHolder, i: Int) {

        if(i<1) // For debugging
        {
            Toast.makeText(view.context, "foodArrayList7 = " + foodArrayList.size, Toast.LENGTH_SHORT).show()
        }

        foodArrayList[i]
        viewHolder.tvIndex.text = foodArrayList[i].index.toString()
        viewHolder.tvDescription.text = foodArrayList[i].description
        viewHolder.tvUnits.text = foodArrayList[i].units
        viewHolder.tvPortion.text = foodArrayList[i].portion.toString()
        viewHolder.tvCalories.text = foodArrayList[i].calories.toString()
    }


    inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val tvIndex: TextView = itemView.findViewById(R.id.tvIndex)
        val tvDescription: TextView = itemView.findViewById(R.id.tvDescription)
        val tvUnits: TextView = itemView.findViewById(R.id.tvUnits)
        val tvPortion: TextView = itemView.findViewById(R.id.tvPortion)
        val tvCalories: TextView = itemView.findViewById(R.id.tvCalories)
    }

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

    companion object{   }
    }

Here is my MainActivity class:

import android.graphics.Color
    import android.os.Bundle
    import android.view.View
    import android.view.WindowInsets
    import android.widget.TextView
    import android.widget.Toast
    import androidx.appcompat.app.AppCompatActivity
    import androidx.core.content.ContextCompat
    import androidx.fragment.app.Fragment
    import androidx.fragment.app.FragmentActivity
    import androidx.viewpager2.adapter.FragmentStateAdapter
    import androidx.viewpager2.widget.ViewPager2
    import com.google.android.material.tabs.TabLayout
    import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
    import com.google.android.material.tabs.TabLayoutMediator
    import com.neels.newarcadiafragments.databinding.ActivityMainBinding
    import com.neels.newarcadiafragments.model.Tables
    import java.io.File
    import java.io.FileInputStream
    import java.io.ObjectInputStream

    class MainActivity : AppCompatActivity() {

    private var binding: ActivityMainBinding? = null
    var logTag = "Observer"
    var message: TextView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding!!.getRoot())
        val decorView = window.decorView
        decorView.windowInsetsController!!.hide(WindowInsets.Type.statusBars())
        supportActionBar!!.setDisplayShowCustomEnabled(true)
        supportActionBar!!.setCustomView(R.layout.custom_action_bar)
        supportActionBar!!.elevation = 1f
        val view = supportActionBar!!.customView
        message = view.findViewById(R.id.name)

        message!!.setOnClickListener { v: View? ->
            message!!.text = getString(R.string.message_clicked)
            Toast.makeText(this@MainActivity, "You have clicked message", Toast.LENGTH_LONG).show()
        }

        setContentView(R.layout.activity_main)
        setupTabs()
        readMainTableFromSdCard()
    }



    private fun setupTabs() {

        val tabLayout = findViewById<TabLayout>(R.id.tabLayout)
        val viewPager = findViewById<ViewPager2>(R.id.viewPager)
        viewPager.adapter = ViewPagerAdapter(this)

        TabLayoutMediator(tabLayout, viewPager
        ) { tab: TabLayout.Tab, position: Int ->
            if (position == 0) {
                tab.text = "Main Entries"
                tab.view.setBackgroundColor(Color.parseColor("#A52A2A"))
            } else if (position == 1) {
                tab.text = "Meal Entries"
                tab.view.setBackgroundColor(Color.parseColor("#A52A2A"))
            } else {
                tab.text = "Label Entry"
                tab.view.setBackgroundColor(Color.parseColor("#A52A2A"))
            }
        }.attach()

        tabLayout.addOnTabSelectedListener(object : OnTabSelectedListener {
            override fun onTabSelected(tab: TabLayout.Tab?) {
                tab!!.view.setBackgroundColor(Color.CYAN)
            }

            override fun onTabUnselected(tab: TabLayout.Tab?) {
                tab!!.view.setBackgroundColor(Color.parseColor("#A52A2A"))
            }

            override fun onTabReselected(tab: TabLayout.Tab?) {
            }
        })

    }
 

    private fun readMainTableFromSdCard() {
        val externalStorageVolumes =
            ContextCompat.getExternalFilesDirs(this.applicationContext, null)
        val sdCardStorage = externalStorageVolumes[1]
        try {
            val f2 = File("$sdCardStorage/condensed.mst")
            val readData = FileInputStream(f2)
            val readStream = ObjectInputStream(readData)
            Tables.finalTable = readStream.readObject() as Array<Array<Any?>?>
            readStream.close()
           // Toast.makeText(getApplicationContext(), "Rows = " + Tables.finalTable.size, Toast.LENGTH_SHORT).show()
        } catch (e: Exception) {
            Toast.makeText(applicationContext, "EXCEPTION: " + readMainTableFromSdCard(), Toast.LENGTH_LONG).show()
            return
        }
        //Toast.makeText(getApplicationContext(), "Rows = " + Tables.finalTable.length, Toast.LENGTH_LONG).show();
    }



    companion object {
        class ViewPagerAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {

            override fun createFragment(position: Int): Fragment {
                return if (position == 0) {
                    FragmentMainEntries.newInstance()
                } else if (position == 1) {
                    FragmentMealEntries.newInstance()
                } else {
                    FragmentLabelEntry.newInstance()
                }
            }

            override fun getItemCount(): Int {
                return 3
            }
        }
    }
    }

Here is the fragment layout file:

<?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:background="@color/very_light_background"
    android:layout_height="match_parent"
    tools:context=".FragmentMainEntries">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycleView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/viewPager" />

    </androidx.constraintlayout.widget.ConstraintLayout>

Here is my Item class:

class Item internal constructor(
    var index: Int,
    var description: String,
    var units: String,
    var portion: Float,
    var calories: Float,
    )

Here is my item row layout file:

<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/itemLayout"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="34dp"
    android:focusable="true"
    android:clickable="true"
    android:layout_margin="0dp">

    <TableLayout
        android:id="@+id/table_heading_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginStart="192dp"
        android:layout_marginTop="0dp"
        android:foreground="?selectableItemBackground">
 

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_gravity="bottom"
            android:background="@color/brown"/>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="34dp">

            <TextView
                android:id="@+id/tvIndex"
                android:layout_width="50dp"
                android:layout_height="34dp"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:layout_column="0"
                android:background="@color/brown"
                android:textAlignment="center" />

            <View
                android:layout_width="1dip"
                android:background="@color/brown"/>

            <TextView
                android:id="@+id/tvDescription"
                android:layout_width="720dp"
                android:layout_height="34dp"
                android:layout_column="1"
                android:textColor="@color/brown"
                android:background="@color/very_light_background"
                android:textAlignment="center"
                android:textAppearance="?android:attr/textAppearanceMedium"/>

            <View
                android:layout_width="1dip"
                android:background="@color/brown"/>

            <TextView
                android:id="@+id/tvPortion"
                android:layout_width="100dp"
                android:layout_height="34dp"
                android:layout_column="2"
                android:textColor="@color/brown"
                android:background="@color/very_light_background"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:textAlignment="center" />

            <View
                android:layout_width="1dip"
                android:background="@color/brown"/>

            <TextView
                android:id="@+id/tvUnits"
                android:layout_width="100dp"
                android:layout_height="34dp"
                android:layout_column="3"
                android:textColor="@color/brown"
                android:background="@color/very_light_background"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:textAlignment="center" />

            <View
                android:layout_width="1dip"
                android:background="@color/brown"/>

            <TextView
                android:id="@+id/tvCalories"
                android:layout_width="108dp"
                android:layout_height="34dp"
                android:layout_column="4"
                android:textColor="@color/brown"
                android:background="@color/very_light_background"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:textAlignment="center" />

            <View
                android:layout_width="1dip"
                android:background="@color/brown"/>
        </TableRow>

        <View
            android:layout_height="1dip"
            android:background="@color/brown"/>

    </TableLayout>
</LinearLayout>
cactustictacs

You're inflating a layout and setting stuff up on the Views in it, but then you inflate another copy of the layout (where nothing's set up) and return that for display. So your stuff might be working, just in the layout you can't see!

override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?
    ): View? {

    // inflating layout copy A, storing the Binding class it creates
    binding = FragmentMainEntriesBinding.inflate(layoutInflater)
    // you're storing the `View` you should be returning here!
    val view = binding.root
    
    // setting things up on layout A
    val recyclerView = view.findViewById<RecyclerView>(R.id.recycleView)
    recyclerView.layoutManager = LinearLayoutManager(view.context)
    tableRowAdapter = MainFragAdapter(foodList)
    binding.recycleView.adapter = tableRowAdapter

    // inflating layout copy B and returning that for display!
    return inflater.inflate(R.layout.fragment_main_entries, container, false)
}

You're doing it again in MainActivity too:

binding = ActivityMainBinding.inflate(layoutInflater)
...
// this tells the system to inflate this layout file and display it
setContentView(R.layout.activity_main)


For the Activity, you can either do

binding = ActivityMainBinding.inflate(layoutInflater)
// pass your inflated hierarchy for display
setContentView(binding.root)

or

// inflate and display a view hierarchy
setContentView(R.layout.activity_main)
// now the layout is displayed as 'view' (aka getView()) you can bind to that
// hierarchy - basically looking up all the view IDs in the binding class
binding = ActivityMainBinding.bind(view)

I prefer the first version since you just display what you inflated from the view binding, you don't need to match the correct layout XML file and view binding class, but it's up to you

Also, make your binding field lateinit like you did in your Fragment. Don't make it nullable just to have a temporary null value, using !! in your code is generally bad and a sign something shouldn't be nullable at all!


For the Fragment, do something like this:

override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?
    ): View? {

    // inflating layout copy A, storing the Binding class it creates
    binding = FragmentMainEntriesBinding.inflate(layoutInflater)
    // don't use findViewById with view binding, part of the point is you don't
    // have to do that! All your Views with IDs are already in the Binding object.
    // by using 'with(binding)' we can refer to things in binding without having to
    // prefix them all with 'binding.'
    with(binding) {
        // really binding.recyclerView - 'binding' is 'this' inside the 'with' block
        recyclerView.layoutManager = LinearLayoutManager(requireContext())
        tableRowAdapter = MainFragAdapter(foodList)
        recyclerView.adapter = tableRowAdapter
    }

    // pass back the inflated layout - 'root' is a special property of the created binding
    // object, either what it inflated through #inflate, or bound to through #bind
    return binding.root
}

edit also just FYI, you can use View Binding with your Adapter too (might as well since you're already using it!)

class MainFragAdapter(private var foodArrayList: MutableList<Item>) : 
    RecyclerView.Adapter<MainFragAdapter.MyViewHolder>()
    {
    // you're only using this as a temp thing in onCreateViewHolder
    // but it shouldn't really be here! Safer to use a local variable in the function
    lateinit var view: View

    // make this take an ItemViewBinding instead, and make the parameter
    // a val so it's a property on the object. Pass the view root to the super constructor
    inner class MyViewHolder(val binding: ItemViewBinding) : RecyclerView.ViewHolder(binding.root) {
        // no need to look anything up! It's all in the binding object
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val binding = ItemRowBinding.inflate(inflater, parent, false)
        Toast.makeText(parent.context, "foodArrayList5 = "+foodArrayList.size, Toast.LENGTH_SHORT).show()
        return MyViewHolder(binding)
    }

    override fun onBindViewHolder(viewHolder: MyViewHolder, i: Int) {
        val item = foodArrayList[i]
        // see the ViewHolder class below - working with a binding object now
        with(viewHolder.binding) {
            tvIndex.text = item.index.toString()
            tvDescription.text = item.description
            tvUnits.text = item.units
            tvPortion.text = item.portion.toString()
            tvCalories.text = item.calories.toString()
        }
    }


    // you can make this an expression if you like, it's neat
    override fun getItemCount() = foodArrayList.size
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

I Cannot Get Dropped Event to Work in WebStorm Angular Material Project

Cannot get random color generator in Kotlin to work

Why do I get a type mismatch when using "this" on fragment Kotlin

Why I get cannot be resolved with maven project

I am converting xml to csv for a client project & cannot get the conversion to work. I am using Python in the CMD

I cannot get the favicon to work on my website?

I cannot get assets to work in Rails application

I cannot get the Xilinx uartlite IP to work

I cannot get my "if" command to work properly

I cannot get my fancybox 2 to work

I cannot get my quiz code to work

Why cannot I get `where` to work in Hspec

PropertyModel cannot work with Kotlin's private field with get()

I get an error when i build my project in kotlin

How can I get Relay Modern fragment composition to work?

Cannot get fonts to work in Windows Phone 8.1 project

Cannot get to work .so shared library in android project

Kotlin Coroutines - I can not get them to work to execute on a different threads

Spring AOP (AspectJ) with Kotlin and Gradle - I can't get it to work

Cannot load Google map in Kotlin Fragment?

Navigating to fragment doesn't Work - Kotlin

SearchView.onQueryTextListener does not work in Fragment (Kotlin)

The spinner doesn't work in my Kotlin fragment

I cannot setonClickListener RelativeLayout on a fragment

How do I get ServiceStack to work in an MVC4 project?

How can I get static files to work in my Django project?

I can't get this code to work for my project?

How can work DevTools in Kotlin and Gradle project when I guess I tried a lot of solution?

In my project I wrote with Angular, I get a 'Cannot Get' error when I run it