androidkotlinandroid-fragmentsfragmentandroid-fragmentactivity

call a fragment from another class\function kotlin


  1. GameActivity
  2. ____FragmentQuest
  3. ____FragmentFight
  4. class MapLvl.kt

this is a text RPG Fragment Quest displays a journey through different maps (changing the content in one fragment according to a template) text, pictures, navigation buttons. if there is a mob on the map, then the "Fight" button appears and a fragment of the turn-based fight FightFragment opens (hit the head \ legs\ body protect the head \ legs\ body). after the battle, return to QuestFragment

enter image description here

class MapLvl fills with the content of FightFragment I need to change QuestFragment from classLvl to FightFragment. how to do it?

it doesn't work: class MapLvl.kt:

class MapLevels(){

fun changeLvl (bind: FragmentQuestBinding,hero: Hero, activity: GameActivity,db: Maindb) {
    when (hero.mapLvl) {
        1 -> MapLevels().mapLevel1(bind, activity, hero, db)
        2 -> MapLevels().mapLevel2(bind, activity, hero,db)
        else -> {}
    }
}

    fun mapLevel2 (bind: FragmentQuestBinding,activity: GameActivity,hero:Hero,db: Maindb) {

        bind.btnAtack.visibility= View.VISIBLE

//the problem is here:

        bind.btnAtack.setOnClickListener {
        (activity as GameActivity).supportFragmentManager
            .beginTransaction()
            .replace(R.id.placeHolder,FightFragment.newInstance())
            .commit()
        }
    }
}

error: FragmentManager has not been attached to a host

QuestFragment:

class QuestFragment : Fragment() {
    lateinit var bind:FragmentQuestBinding
        override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {
        bind = FragmentQuestBinding.inflate(inflater)
        return bind.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val hero = Hero()
        val db = Maindb.heroSetDb(requireActivity())

        hero.extractHeroData(db,hero)
        scopeMain.launch {
            delay(50)
            MapLevels().changeLvl(bind,hero,GameActivity(),db)
        }

if you make a call directly from a Fragment, then it works: (but it is necessary not from the fragment but from the class)

QuestFragment:

class QuestFragment : Fragment() {
    lateinit var bind:FragmentQuestBinding
        override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {
        bind = FragmentQuestBinding.inflate(inflater)
        return bind.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val hero = Hero()
        val db = Maindb.heroSetDb(requireActivity())

        hero.extractHeroData(db,hero)
        scopeMain.launch {
            delay(50)
            MapLevels().changeLvl(bind,hero,GameActivity(),db)
        }

        bind.btnAtack.setOnClickListener {
            (activity as GameActivity).supportFragmentManager
                .beginTransaction()
                .replace(R.id.placeHolder,FightFragment.newInstance())
                .commit()
        }

it Work:

class MapLevels(val bind: FragmentQuestBinding,
                val hero: Hero,
                val db: Maindb,
                val activity: FragmentActivity ){


    fun changeLvl() {
        when (hero.mapLvl) {
            1 -> MapLevels(bind,hero,db,activity).mapLevel1()
            2 -> MapLevels(bind,hero,db,activity).mapLevel2()
            else -> {}
        }
    }
fun mapLevel2() {
        bind.imgLocation.setImageResource(R.drawable.map_loc02)
        bind.txtLocationDiscription.text ="text"

        bind.btnAtack.visibility= View.VISIBLE
        bind.btnAtack.setOnClickListener {
            (activity as FragmentActivity).supportFragmentManager
                .beginTransaction()
                .replace(R.id.placeHolder,FightFragment.newInstance())
                .commit()

Solution

  • MapLevels().changeLvl(bind,hero,GameActivity(),db)
    

    It looks like you are creating a new GameActivity instance to pass to your changeLvl() method. YOU SHOULD NEVER DO THIS. The new activity is NOT the same one that currently is displayed on the screen. Instead, you should use the requireAcitivty() to get the fragment's parent activity:

    MapLevels().changeLvl(bind,hero,requireActivity(),db)
    

    I can't be sure this will fix your current problem because I'm not even sure what the problem is exactly. But it is one issue that you need to change.