Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions app/src/main/java/com/example/androidconcepts/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,61 @@ package com.example.androidconcepts

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.androidconcepts.fragments.problems.problem1.FragProbOneFragment
import com.example.androidconcepts.fragments.problems.problem2.FragProbTwoFragment

class MainActivity : AppCompatActivity() {

enum class CURRENT_BUILD {
FRAG_PROBLEM_1, FRAG_PROBLEM_2
}

// change this to modify app's state.
private val currentBuild = CURRENT_BUILD.FRAG_PROBLEM_2

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

// AndroidThreadSpammer().execute()

if (currentBuild == CURRENT_BUILD.FRAG_PROBLEM_1) {
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.root_fragment_container, FragProbOneFragment())
.commit()
}
} else if (currentBuild == CURRENT_BUILD.FRAG_PROBLEM_2) {
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.root_fragment_container, FragProbTwoFragment())
.commit()
}
}
}

override fun onBackPressed() {

// ------------------------------
// ---------- for FRAG PROBLEM 1

// if (currentBuild == CURRENT_BUILD.FRAG_PROBLEM_1) {

// SOLUTION : manually remove the unintended fragments attached.

// val currentFragment = supportFragmentManager.findFragmentById(R.id.root_fragment_container)
// ?: return

// Log.d("frag problem", "current frag : " + (currentFragment as FragProbOneFragment).number)

// this does the main fix, i.e remove currently unintended shown fragment from the fm.

// supportFragmentManager.beginTransaction().remove(currentFragment).commit()
// }

// ---------- for FRAG PROBLEM 1
// ------------------------------

super.onBackPressed() // internally does popBackStackImmediate or finish activity.
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.example.androidconcepts.fragments.problems.problem1

import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.FrameLayout.LayoutParams
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.example.androidconcepts.R
import com.google.android.material.button.MaterialButton

class FragProbOneFragment : Fragment() {

private lateinit var button: MaterialButton

var number = 0

private fun getInstance(number: Int): FragProbOneFragment {
return FragProbOneFragment().apply {
val bundle = Bundle()
bundle.putInt("number", number)
this.arguments = bundle
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
number = arguments?.getInt("number", 0) ?: 0
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val rootView = FrameLayout(requireContext())

rootView.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)

rootView.setBackgroundColor(Color.WHITE) // hides the other fragments, due to this I never found this issue.
rootView.isClickable = true // prevents clicking through the current fragment.

button = MaterialButton(requireContext())
button.text = "Fragment Problem : $number"
val lp = LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
)
lp.gravity = Gravity.TOP
lp.topMargin = number * 50
button.layoutParams = lp

rootView.addView(button)

return rootView
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

Log.d("frag problem", "frags size : " + requireActivity().supportFragmentManager.fragments.size
+ " backstack count : " + requireActivity().supportFragmentManager.backStackEntryCount)

button.setOnClickListener {
val ft = requireActivity().supportFragmentManager.beginTransaction()
ft.replace(R.id.root_fragment_container, getInstance(number + 1))

if (number % 2 == 1) // only add if current fragment number is odd. eg: frag 3 to 4 is added but 4 to 5 isn't.
ft.addToBackStack(null)

ft.commit()
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.example.androidconcepts.fragments.problems.problem2

import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import com.example.androidconcepts.R
import com.google.android.material.button.MaterialButton

class FragProbTwoFragment : Fragment() {

private lateinit var button: MaterialButton

var number = 0

private fun getInstance(number: Int): FragProbTwoFragment {
return FragProbTwoFragment().apply {
val bundle = Bundle()
bundle.putInt("number", number)
this.arguments = bundle
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
number = arguments?.getInt("number", 0) ?: 0
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val rootView = FrameLayout(requireContext())

rootView.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)

rootView.setBackgroundColor(Color.WHITE) // hides the other fragments, due to this I never found this issue.
rootView.isClickable = true // prevents clicking through the current fragment.

button = MaterialButton(requireContext())
button.text = "Fragment Problem : $number"
val lp = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT
)
lp.gravity = Gravity.TOP
lp.topMargin = number * 50
button.layoutParams = lp

rootView.addView(button)

return rootView
}

override fun onSaveInstanceState(outState: Bundle) {
Log.d("frag problem", "$number onSaveInstanceState")
super.onSaveInstanceState(outState)
}

override fun onStart() {
// state is set to false here. eg : minimize app, state = true, reopen, state = false.
Log.d("frag problem", "$number onStart, isStateSaved : $isStateSaved")
super.onStart()
}

override fun onResume() {
Log.d("frag problem", "$number onResume, isStateSaved : $isStateSaved")
super.onResume()
}

override fun onPause() {

// as far as experimented, isStateSaved is false in onPause.
Log.d("frag problem", "$number onPause, isStateSaved : $isStateSaved")

super.onPause()

// very common case in which we do a fragment transaction on a network call result.
// user initiates the network call and minimises the app and before opening again the result is fetched
// and hence a frag transaction is committed.
// then perhaps, the app would crash throwing "java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState".

button.postDelayed({
val fm = requireActivity().supportFragmentManager
fm.beginTransaction()
.replace(R.id.root_fragment_container, this.getInstance(number + 1))
.addToBackStack(null)
.commit()
}, 1500L)
}

override fun onStop() {
// weirdly, isStateSaved is true here even when onSaveInstanceState is called yet.
// also if I commit frag transactions in onStop then isStateSaved is false.
Log.d("frag problem", "$number onStop, isStateSaved : $isStateSaved")
super.onStop()
}

override fun onDestroyView() {
Log.d("frag problem", "$number onDestroyView, isStateSaved : $isStateSaved")
super.onDestroyView()
}

}
42 changes: 4 additions & 38 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,9 @@
android:background="@color/white"
tools:context=".MainActivity">

<!-- <com.example.androidconcepts.ui.retroDesign.RetroLayout-->
<!-- android:id="@+id/neopop"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_margin="20dp"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent">-->

<!-- <LinearLayout-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_gravity="center"-->
<!-- android:orientation="horizontal">-->

<!-- <TextView-->
<!-- android:id="@+id/tv"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_gravity="center"-->
<!-- android:padding="20dp"-->
<!-- android:paddingEnd="0dp"-->
<!-- android:text="OKAY"-->
<!-- android:textColor="@color/black"-->
<!-- android:textSize="20dp"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent" />-->

<!-- <ImageView-->
<!-- android:layout_width="32dp"-->
<!-- android:layout_height="32dp"-->
<!-- android:layout_gravity="center"-->
<!-- android:layout_margin="12dp"-->
<!-- android:src="@drawable/ic_baseline_arrow_circle_right_24" />-->

<!-- </LinearLayout>-->

<!-- </com.example.androidconcepts.ui.retroDesign.RetroLayout>-->
<FrameLayout
android:id="@+id/root_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ fun measureTime(action: () -> Unit): Long {
action.invoke()
val endTime = System.currentTimeMillis()
val measuredTime = endTime - startTime
println("measure time = " + measuredTime + "ms")
println("measured time = " + measuredTime + "ms")
return measuredTime
}
Loading