'Fragment switching causes fragment to recreate itself instead
So for some reason I am unable to switch between to specific fragments and when it should switch between fragments it keeps recreating the original fragment instead of replacing it with the intended fragment.
This is my fragment from where I want to switch to a different fragment:
package ikanda.cleverspace.fragments
import android.content.Context
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import ikanda.cleverspace.R
import ikanda.cleverspace.activities.MainActivity
import ikanda.cleverspace.base.AppNavigation
import ikanda.cleverspace.models.*
import ikanda.cleverspace.ui.BookingsViewModel
import ikanda.cleverspace.ui.CompanyViewModel
import ikanda.cleverspace.ui.DeviceViewModel
import ikanda.cleverspace.ui.RoomViewModel
import ikanda.cleverspace.utils.GuiUtil
import ikanda.cleverspace.utils.PreferenceUtil
import kotlinx.android.synthetic.main.fragment_book_a_room.*
import kotlinx.android.synthetic.main.fragment_bookings.*
import java.time.*
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
/**
* A simple [Fragment] subclass.
* Use the [BookingsFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class BookingsFragment : Fragment() {
private lateinit var navigationCallback: AppNavigation
private lateinit var deviceViewModel: DeviceViewModel
private lateinit var bookingsViewModel: BookingsViewModel
private lateinit var roomViewModel: RoomViewModel
private lateinit var companyViewModel: CompanyViewModel
private lateinit var bookings: List<Booking>
private lateinit var currentDevice: Device
private lateinit var currentRoom: Room
private lateinit var currentCompany: Company
private val runnableBookings: Runnable = object : Runnable {
override fun run() {
bookingsViewModel.retrieveBookings(
currentDevice.companyId,
currentRoom.email
)
txt_clock_date.text =
LocalDate.now().format(
DateTimeFormatter.ofPattern(
"EEE dd/MM/yyyy"
)
)
//This basically reruns this runnable in 60 seconds
handler?.postDelayed(this, 60000)
}
}
private val runnableDevice: Runnable = object : Runnable {
override fun run() {
//deviceViewModel.retrieveDevice(PreferenceUtil.getDeviceId()!!)
var deviceId = PreferenceUtil.getDeviceId()
if(deviceId!=null) deviceViewModel.retrieveDevice(deviceId)
else {
handler?.removeCallbacksAndMessages(null)
check_out.setOnClickListener { null }
check_in.setOnClickListener { null }
book_room.setOnClickListener(null)
bookingsViewModel.bookings.removeObservers(this)
bookingsViewModel.updateSuccess.removeObservers(this)
roomViewModel.currentRoom.removeObservers(this)
deviceViewModel.currentDevice.removeObservers(this)
companyViewModel.activeCompany.removeObservers(this)
navigationCallback.replaceFragments(ActivationFragment::class.java, "activate","bookings")
}
txt_clock_date.text =
LocalDate.now().format(
DateTimeFormatter.ofPattern(
"EEE dd/MM/yyyy"
)
)
//This basically reruns this runnable every 5 minutes
handler?.postDelayed(this, 300000)
}
}
private var handler: Handler? = Handler(Looper.getMainLooper())
override fun onAttach(context: Context) {
super.onAttach(context)
navigationCallback = context as AppNavigation
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
deviceViewModel = ViewModelProvider(requireActivity()).get(
DeviceViewModel::class.java
)
roomViewModel = ViewModelProvider(requireActivity()).get(
RoomViewModel::class.java
)
bookingsViewModel = ViewModelProvider(requireActivity()).get(
BookingsViewModel::class.java
)
companyViewModel = ViewModelProvider(requireActivity()).get(
CompanyViewModel::class.java
)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_bookings, container, false)
}
private fun initListeners() {
txt_clock_date.text = LocalDate.now().format(
DateTimeFormatter.ofPattern("EEE dd/MM/yyyy")
)
deviceViewModel.currentDevice.observe(this, {
var deviceId = PreferenceUtil.getDeviceId()
if(it!=null && deviceId != null) {
currentDevice = it
companyViewModel.getCompany(currentDevice.companyId)
} else {
handler?.removeCallbacksAndMessages(null)
check_out.setOnClickListener { null }
check_in.setOnClickListener { null }
book_room.setOnClickListener(null)
bookingsViewModel.bookings.removeObservers(this)
bookingsViewModel.updateSuccess.removeObservers(this)
roomViewModel.currentRoom.removeObservers(this)
deviceViewModel.currentDevice.removeObservers(this)
companyViewModel.activeCompany.removeObservers(this)
navigationCallback.replaceFragments(ActivationFragment::class.java, "activate","bookings")
}
})
companyViewModel.activeCompany.observe(this, {
var deviceId = PreferenceUtil.getDeviceId()
if(it!=null && deviceId!=null) {
currentCompany = it
roomViewModel.retrieveRoom(currentDevice.id)
}
})
roomViewModel.currentRoom.observe(this, {
// code to show room information and retrieve bookings info
})
bookingsViewModel.bookings.observe(this, {
// a lot of code to show booking information
})
book_room.setOnClickListener {
handler?.removeCallbacksAndMessages(null)
check_out.setOnClickListener { null }
check_in.setOnClickListener { null }
book_room.setOnClickListener(null)
bookingsViewModel.bookings.removeObservers(this)
bookingsViewModel.updateSuccess.removeObservers(this)
roomViewModel.currentRoom.removeObservers(this)
deviceViewModel.currentDevice.removeObservers(this)
companyViewModel.activeCompany.removeObservers(this)
navigationCallback.replaceFragments(BookARoomFragment::class.java, "bookaroom","bookings")
}
handler?.postDelayed(runnableDevice, 300000)
handler?.postDelayed(runnableBookings, 60000)
deviceViewModel.retrieveDevice(PreferenceUtil.getDeviceId()!!)
}
override fun onStart() {
super.onStart()
initListeners()
}
override fun onStop() {
super.onStop()
}
companion object {
@JvmStatic
fun newInstance() = BookingsFragment()
}
}
the navigationcallback is the AppNavigation interface which the MainActivity overrides the replaceFragments method.
The Mainactivity looks like this:
package ikanda.cleverspace.activities
import android.content.Context
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.ViewModelProvider
import ikanda.cleverspace.R
import ikanda.cleverspace.base.AppNavigation
import ikanda.cleverspace.constants.*
import ikanda.cleverspace.fragments.ActivationFragment
import ikanda.cleverspace.fragments.BookingsFragment
import ikanda.cleverspace.ui.DeviceViewModel
import ikanda.cleverspace.utils.DeviceUtil
class MainActivity : AppCompatActivity(), AppNavigation {
private lateinit var activationFragment: ActivationFragment
private lateinit var bookingsFragment: BookingsFragment
private lateinit var deviceViewModel: DeviceViewModel
private var uniqueID: String? = null
private var deviceID: String? = null
private var isActive: Boolean = false
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
instance = this
deviceViewModel = ViewModelProvider(this).get(DeviceViewModel::class.java)
activationFragment = ActivationFragment.newInstance()
bookingsFragment = BookingsFragment.newInstance()
/**
* show de main activity
*/
setContentView(R.layout.activity_main)
isActive = true
/**
* Check if the activity uses the layout container frame if so, add the first fragment.
*/
val fragment = supportFragmentManager.findFragmentById(R.id.frg_ctr_main)
if(fragment == null) {
/**
* otherwise we don't need to do anything en we can step out,
* otherwise we could have layered fragments which we don't want
*/
if(savedInstanceState != null) {
return
}
deviceID = deviceViewModel.deviceId.value
uniqueID = deviceViewModel.uuid.value
val active = !deviceID.isNullOrEmpty()
showBootPage()
}
}
/**
*
*/
override fun onBackPressed() {
if(canPop) supportFragmentManager.popBackStack()
else finish()
}
/**
* Set the initial fragment
*
* When device is not activated show the activationScreen
*/
private fun showBootPage() {
if(deviceID.isNullOrEmpty()){
/**
* Add the activation fragment to the layout container 'frame'
*/
supportFragmentManager.beginTransaction().add(R.id.frg_ctr_main, activationFragment, "activate").commit()
} else {
/**
* Add the bookings fragment to the layout container 'frame'
*/
supportFragmentManager.beginTransaction().add(R.id.frg_ctr_main, bookingsFragment, "bookings").commit()
}
}
override fun replaceFragments(fragmentClass: Class<*>, fragmentNewName: String, fragmentOldName: String) {
var fragment: Fragment? = null
try {
fragment = fragmentClass.newInstance() as Fragment
} catch (e: Exception) {
e.printStackTrace()
}
// Insert the fragment by replacing any existing fragment
supportFragmentManager.beginTransaction().replace(R.id.frg_ctr_main, fragment!!, fragmentNewName).addToBackStack(fragmentOldName)
.commit()
}
override fun popFragment() {
supportFragmentManager.popBackStack()
}
/**
* Companian object of de [MainActivity] to make global communication possible.
*/
companion object {
/**
* For global use of context
*/
private var instance: MainActivity? = null
/**
* Keeps track of whether the current fragment can pop to previous fragment
* or it can finish the application
*/
private var canPop: Boolean = false
/**
* returns the [Context] of the mainactivity
*/
fun getContext(): Context {
return instance!!.applicationContext
}
/**
* Sets the canpop variable so it can determine what action the backbutton executes
*/
fun setCanpop(boolean: Boolean) {
canPop = boolean
}
}
}
So as far as I can see there is no reason as to why my BookingsFragment would keep recreating itself in a loop, afterall it is able to switch to the BookARoomFragment without any issues so why I am unable to switch to the Activation fragment is a mystery to me.
If anyone has an idea as to what might be happening here, please let me know before i break my head on this problem since it is a really important part of the application.
Thanks in advance!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
