How to manage BottomNavigationView backstack in Android Navigation Component - android

I am using navigation component and BottomNavigationView, i am facing a problem, that is when i go to from fragment 1>2>5>4>3 and when i press back button i get fragment 1. I know this is the default behavior but i don't want this, i want to save them in backstack so when i press back button it should go to fragment 4 not 1. I have been trying and searching but i couldn't find any solution. Can i put fragment manually into backstack in kotlin?
My code:
activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout
.......................
.......................>
<androidx.appcompat.widget.Toolbar
................
................/>
<fragment
android:id="#+id/app_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:navGraph="#navigation/app_nav"
..............
............../>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/app_bottom_nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#drawable/white_grey_border_bottom"
app:menu="#menu/bottom_nav_menu"
app:labelVisibilityMode="unlabeled"
...........
.........../>
</androidx.constraintlayout.widget.ConstraintLayout>
app_nav.xml
<navigation
...........
...........
android:id="#+id/app_nav"
app:startDestination="#id/homeFragment">
<fragment
android:id="#+id/homeFragment"
android:name="com.example.instagram_clone.ui.HomeFragment"
android:label="HomeFragment"
tools:layout="#layout/fragment_home"/>
.............
.............
.............
.............
</navigation>
MainActivity.kt
class MainActivity : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
val bottomNavView = binding.appBottomNavView
val navController = findNavController(R.id.app_nav_host_fragment)
bottomNavView.setupWithNavController(navController)
}
}

As per the documentation on onNavDestinationSelected() (the method that setupWithNavController() uses when selecting a MenuItem):
By default, the back stack will be popped back to the navigation graph's start destination. Menu items that have android:menuCategory="secondary" will not pop the back stack.
So just add android:menuCategory="secondary" to each of the menu items used with your BottomNavigationView.

Related

Back button always goes to home fragment, popping up dialog-fragment also [duplicate]

I am using navigation component and BottomNavigationView, i am facing a problem, that is when i go to from fragment 1>2>5>4>3 and when i press back button i get fragment 1. I know this is the default behavior but i don't want this, i want to save them in backstack so when i press back button it should go to fragment 4 not 1. I have been trying and searching but i couldn't find any solution. Can i put fragment manually into backstack in kotlin?
My code:
activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout
.......................
.......................>
<androidx.appcompat.widget.Toolbar
................
................/>
<fragment
android:id="#+id/app_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:navGraph="#navigation/app_nav"
..............
............../>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/app_bottom_nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#drawable/white_grey_border_bottom"
app:menu="#menu/bottom_nav_menu"
app:labelVisibilityMode="unlabeled"
...........
.........../>
</androidx.constraintlayout.widget.ConstraintLayout>
app_nav.xml
<navigation
...........
...........
android:id="#+id/app_nav"
app:startDestination="#id/homeFragment">
<fragment
android:id="#+id/homeFragment"
android:name="com.example.instagram_clone.ui.HomeFragment"
android:label="HomeFragment"
tools:layout="#layout/fragment_home"/>
.............
.............
.............
.............
</navigation>
MainActivity.kt
class MainActivity : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
val bottomNavView = binding.appBottomNavView
val navController = findNavController(R.id.app_nav_host_fragment)
bottomNavView.setupWithNavController(navController)
}
}
As per the documentation on onNavDestinationSelected() (the method that setupWithNavController() uses when selecting a MenuItem):
By default, the back stack will be popped back to the navigation graph's start destination. Menu items that have android:menuCategory="secondary" will not pop the back stack.
So just add android:menuCategory="secondary" to each of the menu items used with your BottomNavigationView.

How to close current fragment in Android while using Navigation?

after setting listener on button I create navigationOnClickListener, which set startDestination to current fragment, after .navigate() it changes the destination to another fragment, but the view is not changed
onClickListener
navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment)
view.findViewById<Button>(R.id.fragment_button).setOnClickListener {
navController.navigate(R.id.Camera2VideoFragment_To_FirstFragment)
}
closeFragment()
private fun closeFragment()
{
closePreviewSession()
closeCamera()
parentFragmentManager.popBackStack()
updatePreview()
}
main.xml (navigation graph)
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="#+id/main.xml"
app:startDestination="#id/cameraFragment"
>
<fragment
android:id="#+id/cameraFragment"
android:name="com.example.camera2videotextureview.Camera2VideoFragment"
android:label="Camera2VideoFragment"
tools:layout="#layout/fragment_camera2_video">
<action
android:id="#+id/navigateToSecondFragment"
app:destination="#id/firstFragment" />
</fragment>
<fragment
android:id="#+id/firstFragment"
android:name="com.example.camera2videotextureview.FirstFragment"
android:label="FirstFragment"
tools:layout="#layout/fragment_first" />
</navigation>
Main fragment is the camera fragment using Camera2 API. FirstFragment is just blank kotlin class where layout contains just one TextView.
EDIT: Now I have edited onClickListener, I am not able to change the current view, I need to use popBackStack on current fragment, but donot know how.
Navigation.findNavController(mActivity, R.id.nav_host_fragment).popBackStack();
I resolved my issue, which was that I have tried to implemented 3 different styles of Navigation. The whole navigation has changed in the past 4 years and I also found out that I have mixed up different versions from lower APIs with higher APIs.
I am not using closeFragment() method anymore.
Following declaration in code and the code itself has to be implemented in MainActivity:
navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment)
view.findViewById<Button>(R.id.fragment_button).setOnClickListener {
navController.navigate(R.id.Camera2VideoFragment_To_FirstFragment)
}
Also you have to setup correctly nav_host_fragment in xml file for MainActivity:
<androidx.fragment.app.FragmentContainerView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost="true"
app:navGraph="#navigation/main"
/>

How to save state of Bottom Navigation Fragment - Android Navigation Component With a Single Nav Graph

How do I save the state of each bottom navigation fragment while using Android Navigation Component JetPack.
I know there is a way to do it using an Navigation Extension provided by the Android Team - Navigation Extension. - While it works, it requires you to create multiple nav_graph for each fragment and also does not have the back stack I want. Also, switching between fragment seems slow using their approach.
How do I do save the state using a single nav_graph and maintain each back stack.
I am following this tutorial and its working but not saving the state of each fragment. Each instance of the fragment is created on Click of the bottom nav item. - Bottom Nav Tutorial Like Instagram And Youtube
activity_home.xml
<fragment //I get a warning here, when I change to FragmentContainerView, app crashes//
android:id="#+id/nav_host_fragment_2"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#+id/bottom_navigation"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graph_2" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?android:attr/windowBackground"
app:itemTextColor="#color/white"
app:itemIconSize = "30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:labelVisibilityMode="unlabeled"
app:menu="#menu/bottom_navigation"/>
menu/bottom_navigation.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/feedRandomFragment"
android:icon="#drawable/home_bottom_nav_selector"
android:title="#string/home"
android:menuCategory="secondary"
/>
<item
android:id="#+id/exploreAndSearchFragment"
android:icon="#drawable/explore_bottom_nav_selector"
android:title="#string/global_explore"
android:menuCategory="secondary"
/>
<item
android:id="#+id/uploadChooseFragment"
android:icon="#drawable/ic_upload"
android:title="#string/upload"
android:menuCategory="secondary"
/>
<item
android:id="#+id/allChallengesFragment"
android:icon="#drawable/challenges_bottom_nav_selector"
android:title="#string/challenges"
android:menuCategory="secondary"
/>
<item
android:id="#+id/profileCurrentUserFragment"
android:icon="#drawable/profile_bottom_nav_selector"
android:title="#string/profile"
android:menuCategory="secondary"
/>
HomeActivity.kt
if(savedInstanceState==null){
setUpBottomNavigationBarBase()
}
private fun setUpBottomNavigationBarBase(){
binding.bottomNavigation.setupWithNavController(Navigation.findNavController(this,
R.id.nav_host_fragment_2))
binding.bottomNavigation.setOnNavigationItemSelectedListener {item ->
onNavDestinationSelected(item, Navigation.findNavController(this, R.id.nav_host_fragment_2))
}
binding.bottomNavigation.itemIconTintList = null
binding.bottomNavigation.setOnNavigationItemReselectedListener {
//do something
}
}
According to the Tutorial, to Maintain backstack, we have to extend all bottom nav fragments from a util class BaseBottomTabFragment which I did and works well.
BaseBottomFragment
open class BaseBottomTabFragment : Fragment() {
var isNavigated = false
fun navigateWithAction(action: NavDirections) {
isNavigated = true
findNavController().navigate(action)
}
fun navigate(resId: Int) {
isNavigated = true
findNavController().navigate(resId)
}
override fun onDestroyView() {
super.onDestroyView()
if (!isNavigated)
requireActivity().onBackPressedDispatcher.addCallback(this) {
val navController = findNavController()
if (navController.currentBackStackEntry?.destination?.id != null) {
findNavController().popBackStackAllInstances(
navController.currentBackStackEntry?.destination?.id!!,
true
)
} else
navController.popBackStack()
}
}
private fun NavController.popBackStackAllInstances(destination: Int, inclusive: Boolean): Boolean {
var popped: Boolean
while (true) {
popped = popBackStack(destination, inclusive)
if (!popped) {
break
}
}
return popped
}
}
So, All my bottom tab fragments extends from that util class - BaseBottomTabFragment like this :
class ExploreAndSearchFragment : BaseBottomTabFragment()
Also, accoriding to the tutorial, to maintain the state of fragment and avoid recreation, each fragment has to have a unique ID which I also did - Sadly, this does not stop the fragment from recreating onClick.
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".fragments.main.bottomnav.home.view.FeedRandomFragment"
android:fillViewport="true"
android:background="#color/white"
android:id="#+id/homeId">
I set a unique id to All fragment, but it didnt work. Please Help me!
As I had a similar problem, I copied the Navigation Advanced Sample from their GitHub page and started troubleshooting.
My goal was to use multiple back stacks while having an Instagram-like bottom navigation bar. So I wanted to combine MAD Skills' tutorial Navigation: Multiple back stacks with
Furkan Aşkın's Instagram-like back stack guide.
As I implemented both components, the project compiled perfectly but multiple back stacks didn't seem to work as the states of the bottom tabs weren't saved. I double-checked the version to be 2.4.0-alpha01 or newer.
What ended up being the problem was secondary menuCategory defined in menu items:
android:menuCategory="secondary"
This was probably overwriting the multiple back stacks expected behaviour and upon deleting the lines, multiple back stacks work perfectly. Also, redundant back stacks are removed while navigating in different bottom navigation top level fragments.

by navGraphViewModels creates java.lang.IllegalArgumentException: No destination with ID <destination id> is on the NavController's back stack

When a configuration change happens and my Activity and Fragment are recreated because of it, my nav Graph scoped ViewModel is unavailable while the Fragments have already been created again.
It seems like the Fragment gets recreated, before the navGraph does.
I am using this code to initialize my navGraph scoped ViewModel from my Fragment:
private val myViewModel: MyViewModel by navGraphViewModels(R.id.nav_graph_id)
If I try to use myViewModel in the Fragments onViewCreated function, I get a IllegalArgumentException after a Configuration change. The Exception:
java.lang.IllegalArgumentException: No destination with ID <destination id> is on the NavController's back stack
How do I handle this?
I have already checked that my ID isn't used anywhere else.
Edit1:
Here is my activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/main_nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:navGraph="#navigation/main_nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
And here is my main_nav_graph.xml:
<navigation
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:id="#+id/main_nav_graph"
app:startDestination="#id/main_nav_graph_1">
<navigation
android:id="#+id/main_nav_graph_1"
android:label="#string/nav_graph_1_label"
app:startDestination="#id/nav_graph_1_start_fragment">
<!-- nav graph stuff -->
</navigation>
<navigation
android:id="#+id/main_nav_graph_2"
android:label="#string/nav_graph_2_label"
app:startDestination="#id/nav_graph_2_start_fragment">
<fragment
android:id="#+id/nav_graph_2_start_fragment"
android:label="#string/nav_graph_2_start_fragment_label"
android:name="my.package.ui.NavGraph2StartFragment"
tools:layout="#layout/fragment_nav_graph_2_start">
</fragment>
<!-- In here is where I get the problem -->
</navigation>
</navigation>
My Problem was the following:
After a Configuration change the NavGraph returned to its start destination, but the Fragment that was last active gets loaded anyway. This meant that the Fragment that was actually started and the current destination of the navGraph were out of sync.
When my Fragment then tried to load the navGraph scoped ViewModel, it failed because the navGraph thought it was on a different Fragment then it actually was.
To fix my problem I had to save and restore the state of the navController using the activities savedInstanceState Bundle. (source: https://stackoverflow.com/a/59987336)
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putBundle("nav_state", fragment.findNavController().saveState())
}
// restore in RestoreInstanceState
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
fragment.findNavController().restoreState(savedInstanceState.getBundle("nav_state"))
}
// or restore in onCreate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState?.containsKey("nav_state") == true) {
fragment.findNavController().restoreState(savedInstanceState.getBundle("nav_state"))
}
}
For anyone else coming here, I experienced this issue when a dialog was currently displayed and I issued a navController.navigate() call to a Fragment which uses by navGraphViewModels() before the dialog was dismissed.
It's as if the Navigation library couldn't understand that there is a destination with that ID available when a dialog is being displayed.
And for more clarity, this dialog is displayed using the <dialog> attribute in my nav graph XML.
My fix (for now) is to ensure the dialog is dismissed before making a further call to navigate elsewhere by way of view.postDelayed({ navController.navigate(elsewhere)}, 300)
This isn't the first time I've experienced issues with the NavController trying to navigate when a dialog is displayed.
Solved Easy by change this :
private val myViewModel: MyViewModel by hiltNavGraphViewModels(R.id.nav_graph_id)
To:
private val viewModel: AuthViewModel by activityViewModels{ defaultViewModelProviderFactory }

Navigation Host becomes null while navigating (Android Navigation Component)

I am creating a game where the user goes through a series of 5 screens. At the last screen, the user has the choice to end the game, at which point they are taken back to the starting screen. My problems come in when a user ends the game and then starts again. While navigating through the app, the navigation host fragment cannot be found.
The first time through the app, it navigates at usual, but the second time, the navigation host cannot be found.
I have tried using different views to find the navigation host, and while debugging, I saw that for the fragment where it can not be found, the parent is equal to null.
This is where I navigate, in the fragments onViewCreated()
viewModel.getGameUpdates().observe(activity!!, Observer { updatedGame ->
if(updatedGame.playerList.size == 0){
Log.d("END","END")
viewModel.endGame()
}
adapter?.players = updatedGame.playerList
if(updatedGame.started){
Navigation.findNavController(view).navigate(R.id.action_waitingFragment_to_gameFragment)
}
})
and this is the moment where the user clicks to navigate back to the first screen:
btn_end_game.setOnClickListener {
viewModel.endGame()
timer.cancel()
Navigation.findNavController(view).navigate(R.id.action_gameFragment_to_startFragment)
}
The layout for my MainActivity that holds the navigation host fragment is:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graph" />
</FrameLayout>
I do realize that I am just adding on top of the back stack when I would rather pop back to the first fragment. I am just lost as to how the fragment is null.
The following is the nav_graph.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/nav_graph" app:startDestination="#id/startFragment">
<fragment android:id="#+id/startFragment" android:name="com.dangerfield.spyfall.start.StartFragment"
android:label="StartFragment">
<action android:id="#+id/action_startFragment_to_joinGameFragment" app:destination="#id/joinGameFragment"/>
<action android:id="#+id/action_startFragment_to_newGameFragment" app:destination="#id/newGameFragment"/>
</fragment>
<fragment android:id="#+id/newGameFragment" android:name="com.dangerfield.spyfall.newGame.NewGameFragment"
android:label="NewGameFragment">
<action android:id="#+id/action_newGameFragment_to_waitingFragment" app:destination="#id/waitingFragment"/>
</fragment>
<fragment android:id="#+id/joinGameFragment" android:name="com.dangerfield.spyfall.joinGame.JoinGameFragment"
android:label="JoinGameFragment">
<action android:id="#+id/action_joinGameFragment_to_waitingFragment" app:destination="#id/waitingFragment"/>
</fragment>
<fragment android:id="#+id/waitingFragment" android:name="com.dangerfield.spyfall.waiting.WaitingFragment"
android:label="WaitingFragment">
<action android:id="#+id/action_waitingFragment_to_gameFragment" app:destination="#id/gameFragment"/>
<action android:id="#+id/action_waitingFragment_to_startFragment" app:destination="#id/startFragment"/>
</fragment>
<fragment android:id="#+id/gameFragment" android:name="com.dangerfield.spyfall.game.GameFragment"
android:label="GameFragment">
<action android:id="#+id/action_gameFragment_to_startFragment" app:destination="#id/startFragment"/>
</fragment>
</navigation>
This is the message given after crash:
java.lang.IllegalStateException: View android.widget.ScrollView{637e4ce VFED.V... ......ID 0,0-1440,2308} does not have a NavController set
LiveData remembers the current data and will automatically redeliver it when the observer becomes started again, making it inappropriate for events that trigger navigation operations: your operation to navigate() is going to be triggered every time your Fragment is started, making it impossible to actually pop back to that Fragment.
Note that Fragments are not destroyed while on the back stack. If you're changing the underlying data that your Fragment relies on while that Fragment is on the back stack, you should use the viewLifecycleOwner instead of this (representing the Fragment) for your LifecycleOwner passed to observe() when observing in onViewCreated(). This ensures that you will no longer get observer callbacks once your view is destroyed (i.e., you go onto the back stack).
activity!! is absolutely always wrong to use as the LifecycleOwner from within a Fragment, since that means the observer will not be cleaned up even if the Fragment is completely destroyed (it'll only be cleaned up when the activity is destroyed).
As per the conditional navigation documentation, the recommended approach is to ensure that your LiveData is tracking state rather than events. That way, after you call navigate(), you can update the state to ensure that when the callback happens a second time, you don't call navigate() a second time. This approach is recommended over the SingleLiveEvent approach.
Even I Was facing the same issue when I used to navigate from current fragment to the next fragment, and on the back press of hardware navHost would be null, The mistake I was doing is that I had made the variable navController global where I used to instantiate like this in onCreate()
Before:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
navController = this.findNavController(R.id.myNavHostFragment)
NavigationUI.setupActionBarWithNavController(this,navController)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp()
}
}
After:
now it's working after this change
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
navController = this.findNavController(R.id.myNavHostFragment)
NavigationUI.setupActionBarWithNavController(this,navController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.myNavHostFragment)
return navController.navigateUp()
}
}
Dont why navController would be null if made it global??

Categories

Resources