I created an Activity and added 3 fragments into it. One is HomeFragment, second is ProductDetailFragment, and third is CartFragment. I have added multiple quantities of a product from ProductDetailFragment and I want the quantity detail to be saved even if I am back to HomeFragment and again coming back to ProductDetailFragment. But as soon as I press back to go to HomeFragment, ProductDetailFragment is destroyed and if coming again to ProductDetailFragment quantity values are all wiped out.
I have tried onSaveInstanceState to store the state even if fragment is destroyed but not working in this case. Lemme show you my code:
ProductDetailFragment
lateinit var binding: FragmentProductDetailBinding
var quantityValue = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Toast.makeText(activity,"onCreateCalled",Toast.LENGTH_SHORT).show()
if(savedInstanceState == null) {
quantityValue = 0
} else {
quantityValue = savedInstanceState.getInt("quantity",0)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
/// return inflater.inflate(R.layout.fragment_product_detail, container, false)
binding = FragmentProductDetailBinding.inflate(inflater,container,false)
binding.productDetails1 = arguments?.getParcelable("product")
var productDetail = binding.productDetails1
// var priceAmount = binding.priceAmount.text.toString().toFloat()
Log.d("PriceAmount", binding.priceAmount.text.toString())
// Log.d("ProductTitle", binding.productDetails1.title)
binding.addButton.setOnClickListener {
// Log.d("ProductDetail",initialValue.toString())
if (productDetail == null) return@setOnClickListener
quantityValue = quantityValue + 1
binding.totalPriceText.text = "Total price"
binding.quantityText.text = quantityValue.toString()
binding.priceAmount.text = (productDetail.price * quantityValue).toString()
// Log.d("ProductDetail",priceAmount.toString())
}
binding.removeButton.setOnClickListener {
if (quantityValue != 0) {
if (productDetail == null) return@setOnClickListener
quantityValue = quantityValue - 1
binding.quantityText.text = quantityValue.toString()
// binding.priceAmount.text = (priceAmount*quantityValue).toString()
binding.priceAmount.text = (productDetail.price * quantityValue).toString()
}
}
binding.addCartButton.setOnClickListener{
val bundle = Bundle()
bundle.putString("quantity_text", String.format("%d",quantityValue))
val cartFragment = CartFragment()
cartFragment.arguments = bundle
val ft = fragmentManager?.beginTransaction()
ft?.replace(R.id.flFragment,cartFragment)
ft?.addToBackStack("")
ft?.commit()
// Create the transaction
// Create the transaction
}
Toast.makeText(activity,"onCreateViewCalled",Toast.LENGTH_SHORT).show()
return binding.root
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt("quantity", quantityValue)
}
HomeFragment
class HomeFragment : Fragment() {
lateinit var binding: FragmentHomeBinding
private val viewModel: HomeFragmentViewModel by lazy {
ViewModelProvider(this).get(HomeFragmentViewModel::class.java)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
binding = FragmentHomeBinding.inflate(inflater,container,false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.viewModel = viewModel
binding.lifecycleOwner = viewLifecycleOwner
val clickListener = object: ClickListener{
override fun onClick(itemProduct: ProductDataModel) {
val productDetailFragment = ProductDetailFragment().apply {
arguments = bundleOf(Pair("product",itemProduct))
}
val ft : FragmentTransaction = fragmentManager!!.beginTransaction()
ft.replace(R.id.flFragment, productDetailFragment,"PRODUCT_DETAIL_FRAGMENT")
ft.addToBackStack(null)
ft.commit()
}
}
viewModel.products.observe(viewLifecycleOwner){
if (it.size>0){
//Log.d("HomeFragment",it.get(0).title)
//Log.d("HomeFragment", it.get(0).image)
binding.productRecyclerView.adapter = ProductListAdapter(it,clickListener)
}
}
}
override fun onResume() {
super.onResume()
(activity as AppCompatActivity?)!!.supportActionBar!!.hide()
}
override fun onStop() {
super.onStop()
(activity as AppCompatActivity?)!!.supportActionBar!!.show()
}
override fun onDestroy() {
super.onDestroy()
Toast.makeText(activity,"onDestroyHomeFrag",Toast.LENGTH_SHORT).show()
}
}
MainActivity ( In which all fragments are there )
class MainActivity : AppCompatActivity() {
private val viewModel:MainViewModel by viewModels()
`enter code here`var productDetailFragment = ProductDetailFragment()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
installSplashScreen().apply {
setKeepOnScreenCondition{
viewModel.isLoading.value
}
}
setContentView(R.layout.activity_main)
val homeFragment = HomeFragment()
//Starting the fragment transaction from SupportFragmentManager class
val ft : FragmentTransaction = supportFragmentManager.beginTransaction()
ft.add(R.id.flFragment, homeFragment,"HOME_FRAGMENT")
ft.addToBackStack(null)
ft.commit()
enter code here
}
}
You can use SharedViewModel since both fragments share same activity. You can add data that you want to preserve and when you go to the detail page view model still has the data you want because it depends on activity' lifecycle.
Offical doc: https://developer.android.com/topic/libraries/architecture/viewmodel#sharing