Programmatically add Fragment to an Activity in Kotlin

23,897

Solution 1

The exception says you are trying to add the Fragment to be associated with a view that doesn't exist. In fact, I'm not sure where R.id.home_fragment comes from.

Solution is this:

<FrameLayout
    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:layout_height="match_parent"
    tools:context=".MainActivity"
    android:id="@+id/root_container">
</FrameLayout>

Then

if(savedInstanceState == null) { // initial transaction should be wrapped like this
    supportFragmentManager.beginTransaction()
           .replace(R.id.root_container, homeFragment)
           .commitAllowingStateLoss()
}

So the other answer was also correct that said to use container and R.id.container, but you are also missing setContentView(R.layout.activity_main).

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

Solution 2

Add fragment to Activity

private fun addFragmentToActivity(fragment: Fragment?){

    if (fragment == null) return
    val fm = supportFragmentManager
    val tr = fm.beginTransaction()
    tr.add(R.id.framlayout, fragment)
    tr.commitAllowingStateLoss()
    curFragment = fragment
}

Add Fragment in Fragment

private fun addFragmentToFragment(fragment: Fragment){

 val ft = childFragmentManager.beginTransaction()
    ft.add(R.id.framlayout, fragment, fragment.javaClass.name)
    ft.commitAllowingStateLoss()
}

Solution 3

replace this line with container id like this

fragmentTransaction.replace(R.id.container, homeFragment).commit()

and add framelayout in your mainactivity xml

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/container"
    />

Solution 4

You need to give your fragment an id and reference it in the activity layout. E.g:


<fragment   android:name=com.example.bluelightlite.models.Team"
            android:id="@+id/Team"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent" />
Share:
23,897
Marc Freeman
Author by

Marc Freeman

Updated on May 15, 2020

Comments

  • Marc Freeman
    Marc Freeman about 4 years

    I have built a fragment that I wish to place on an activity.

    So far, my code looks like this:

    MainActivity.kt

    class MainActivity: AppCompatActivity() {
    
        @Inject
        lateinit var teamInfoModule: TeamInfoModule;
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            DaggerServiceModuleComponent.create().inject(this)
    
            val bundle = Bundle()
            val teamArrayList: ArrayList<Team> = this.teamInfoModule.getAllTeamData()
            val homeFragment = HomeFragment()
    
            bundle.putParcelableArrayList("teamData", teamArrayList)
            homeFragment.arguments = bundle
    
            val fragmentManager: FragmentManager = supportFragmentManager
            val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
            fragmentTransaction.replace(R.id.home_fragment, homeFragment).commit()
        }
    }
    

    activity_main.xml

    <layout 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">
    
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity"
            android:id="@+id/activity_main">
        </androidx.constraintlayout.widget.ConstraintLayout>
    </layout>
    

    HomeFragment.kt

    class HomeFragment @Inject constructor(): Fragment() {
    
        lateinit var team: Team
    
        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
            super.onCreateView(inflater, container, savedInstanceState)
    
            DaggerServiceModuleComponent.create().inject(this)
    
            val binding: ViewDataBinding = DataBindingUtil.inflate<ViewDataBinding>(inflater, R.layout.layout_home, container, false)
            print(arguments.toString())
            val allTeams: ArrayList<Team> = arguments?.get("teamData") as ArrayList<Team>
    
            this.team = allTeams[0]
    
            binding.setVariable(BR.team, team)
    
            return binding.root
        }
    }
    

    layout_home.xml (tied to HomeFragment)

    <?xml version="1.0" encoding="utf-8"?>
    
    <layout 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">
    
        <data>
            <variable
                name="team"
                type="com.example.bluelightlite.models.Team" />
        </data>
    
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".fragments.HomeFragment">
    
            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="1dp"
                android:layout_marginTop="79dp"
                android:layout_marginEnd="1dp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.0"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent">
    
                <TextView
                    android:id="@+id/info_text"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="@{team.name}"/>
            </androidx.cardview.widget.CardView>
    
        </androidx.constraintlayout.widget.ConstraintLayout>
    </layout>
    

    When it runs, I get the error:

    E/AndroidRuntime: FATAL EXCEPTION: main
        Process: com.example.bluelightlite, PID: 10421
        java.lang.IllegalArgumentException: No view found for id 0x7f07003a (com.example.bluelightlite:id/activity_main) for fragment HomeFragment{4b02ab3 (55c458bd-2931-48c6-8087-5e82641313c1) id=0x7f07003a}
    
  • Marc Freeman
    Marc Freeman over 4 years
    Hey, I've done as you've said but now I'm getting the same error ``` No view found for id 0x7f070049 (com.example.bluelightlite:id/container) for fragment HomeFragment{4b02ab3 (6dc9e25c-d62f-4ef7-a264-2ef39a773b5a) id=0x7f070049} ```
  • EpicPandaForce
    EpicPandaForce over 4 years
    Try not to keep a curFragment unless you also initialize it in onCreate via the currently known active findFragmentByTag.
  • Marc Freeman
    Marc Freeman over 4 years
    PERFECT!!! thank you so much, I think everyone's answer was correct here but no one mentioned the setContentView... Set as accepted answer
  • AdiAtAnd
    AdiAtAnd over 3 years
    Can use androidx.fragment.app.FragmentContainerView right instead of FrameLayout?
  • EpicPandaForce
    EpicPandaForce over 3 years
    Sure, if you want