How to the Find the current fragment - android

FragmentManager fm = getSupportFragmentManager();
Fragment Home = fm.findFragmentByTag("Home");
Fragment rec = fm.findFragmentByTag("Recents");
Fragment search = fm.findFragmentByTag("Search");
I am trying to get the current fragmenTag like this, i am checking whether its loaded or not. The condition inside does not execute at all. Am i doing the right way.
if(Home != null){
// Do the following
}

You can check whether your current fragment is visible or not by following:
if (Home.isVisible()) {
// write your "home" fragment code here
}

Related

Removing a fragment and then re-adding it

I've written a method, setLoading in my activity that is responsible for setting the "loading" status of my app. This method is responsible for instantiating a LoadingFragment, removing any existing instances of it (Using FragmentManager) and then depending on it's first parameter loading, adding it to one of two possible containers (Depending on the top parameter).
protected LoadingFragment loadingFragment;
public void setLoading(boolean loading, boolean top) {
FragmentManager fragmentManager = getFragmentManager();
// Create LoadingFragment instance if it has not already been created
if (loadingFragment == null || !(loadingFragment instanceof LoadingFragment)) {
loadingFragment = new LoadingFragment();
}
// Remove the fragment first if it is present
fragmentManager
.beginTransaction()
.remove(loadingFragment)
.commit();
// Only if loading is true should we display the fragment
if (loading) {
// Decide which container we're going to put the fragment in
int id = top ? R.id.topContainer : R.id.container;
// Place the fragment in the right position
fragmentManager
.beginTransaction()
.add(id, loadingFragment)
.commit();
}
}
public void setLoading(boolean loading) {
setLoading(loading, true);
}
I am triggering setLoading(true) from elsewhere in my activity and I have commented out it's corresponding setLoading(false) while testing.
What I want to happen is for my LoadingFragment to appear every time setLoading(true) is called. The first call shouldn't remove anything since it at that point it doesn't exist. All subsequent calls should remove the existing LoadingFragment and add it again.
What happens is that the first call to setLoading(true) does indeed create the LoadingFragment and put it in the correct container. However, subsequent calls to setLoading(true) remove the fragment, but it never seems to be re-added. I have checked to see that the fragment does indeed exist and is of type LoadingFragment at the point it is added and I have also checked to ensure that it's onCreateView method is being called.
Am I doing something wrong?
Edit
Using the answer given below by H Raval as a base I have now come up with the following:
public void setLoading(boolean loading, boolean top) {
FragmentManager fragmentManager = getFragmentManager();
Fragment currentLoadingFragment = fragmentManager.findFragmentById(R.id.loadingFragment);
if (currentLoadingFragment != null) {
fragmentManager
.beginTransaction()
.remove(currentLoadingFragment)
.commit();
}
if (loading) {
int id = top ? R.id.topContainer : R.id.container;
fragmentManager
.beginTransaction()
.add(id, new LoadingFragment())
.commit();
}
}
This seems to work as expected. It seems that the primary difference is that this code is creating a new LoadingFragment instance each time (When loading = true) whereas originally I was trying to use the same instance and just adding/removing it using the FragmentManager.
Out of interest, is there a reason I need to create a new instance after using remove? Is this the correct way to do it? Or should it still work when using the same instance? Additionally, if it's recommended to create a new instance each time, is there anything I should do in terms of clean-up, freeing up resources etc. (Perhaps there's a way of gracefully destroying the obsolete instances)?
well i have made some changes in your code and works perfect for me..let me know if you face any difficulty
public void loadFragment(boolean loading, boolean top){
FragmentManager fragmentManager = getSupportFragmentManager();
loadingFragment = new LoadingFragment();
// Only if loading is true should we display the fragment
if (loading) {
// Decide which container we're going to put the fragment in
int id = top ? R.id.topContainer : R.id.container;
if(top){
if(fragmentManager.findFragmentByTag("loadingFragment")!=null)
fragmentManager.beginTransaction().remove(fragmentManager.findFragmentByTag("loadingFragment")).commit();
fragmentManager
.beginTransaction()
.replace(R.id.topContainer, loadingFragment,"toploadingFragment")
.commit();
}else{
if(fragmentManager.findFragmentByTag("toploadingFragment")!=null)
fragmentManager.beginTransaction().remove(fragmentManager.findFragmentByTag("toploadingFragment")).commit();
fragmentManager
.beginTransaction()
.replace(R.id.container, loadingFragment,"loadingFragment")
.commit();
}
}

Fragment Transaction load empty view but fragment is shown after rotating device

I am building a navigation drawer as designed by the google documentation however I have an issue where the fragment is not being replaced. http://developer.android.com/training/implementing-navigation/nav-drawer.html
When the app first loads, the default fragment is loaded.
Clicking on another item on the drawer list leaves an empty view
However on rotating the device, loads the fragment chosen.
public void selectNavActivty(int position){
// TODO Changing between the different screens selection
fragment = null;
switch (position) {
case 0:
fragment = OverLay.newInstance();
break;
case 1:
fragment = Dummy.newInstance();
break;
}
if(fragment != null) {
// attach added to handle viewpager fragments
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.content_frame, fragment).attach(fragment)
.addToBackStack(null);
trans.commit();
getFragmentManager().executePendingTransactions();
} else {
Log.d("Drawer Activity","Error in creating Fragment");
}
}
For navigation menu fragment transactions I use the following approach, this way the fragment will be added and placed on top.
String name = "myFragment";
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content_frame, fragment, name)
.commit();
Look up the attach() function. It follows a different fragment lifecycle.
Also make sure that your layout files framelayout is visible.
Modify your code as below:
if(fragment != null) {
// attach added to handle viewpager fragments
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.content_frame, fragment);
trans.addToBackStack(null);
trans.commit();
} else {
Log.d("Drawer Activity","Error in creating Fragment");
}
If the solution doesn't work for you, share the xml code along with your fragment code.
After adding Fragment it will be added to activity state and its view
will be added to defined Container view. But by attaching nothing will
be displayed if fragment was not already added to UI. It just attaches
to fragment manager. However if view was already added to a container
in UI and detached after that, by attaching it will be displayed again
in its container. Finally you can use attach and detach if you want to
destroy fragment View temporarily and want to display and build its
view on future without losing its state inside activity.
https://stackoverflow.com/a/18979024/3329488
My solution is to tag all the fragment with unique tag on fragment replacement. Make sure you also assign a unique tag to the default fragment during it creation. A more efficient way is to identify the fragment before you recreate the same one.
public void selectNavActivty(int position){
// TODO Changing between the different screens selection
FragmentManager fragmentManager = getSupportFragmentManager();
fragment = fragmentManager.findFragmentById(R.id.content_frame);
String fragmentTag = null;
switch (position) {
case 0:
fragmentTag = "case0Tag"; // please change to better tag name
break;
case 1:
fragmentTag = "case1Tag"; // please change to better tag name
break;
default:
Log.d("Drawer Activity","Error in creating Fragment");
return;
}
if (fragmentTag != null && !fragment.getTag().equals(fragmentTag))
fragmentManager.beginTransaction().replace(R.id.content_fragment, fragment, tag).commit();
}
In my case after rotating a device a blank fragment was shown. I understood that in an Activity.onCreate() I always called creating a blank Fragment and after that a needed one. So I changed it's behaviour to this:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
openEmptyFragment()
openAnotherFragment()
}
}
I recommend to check savedInstanceState != null before adding new fragments, as written in Why won't Fragment retain state when screen is rotated?.

Fragment Back button

I know how to add a Fragment to the backstack but how do I know, when the user presses the back Button, which fragment I left and which I went to? I need to do a certain action depending on this so I need to know from and to which fragment I am going. Specifically I need to know which fragment I left so if it is a certain fragment, I can remove a button.
Override onBackPressed in Activity:
#Override
public void onBackPressed(){
FragmentManager fm = getSupportFragmentManager();
Fragment f = fm.findFragmentById(R.id.content_frame); // get the fragment that is currently loaded in placeholder
Object tag = f.getTag();
// do handling with help of tag here
// call super method
super.onBackPressed();
}
You can add the Fragment like this :
ArticleMain articalemain = new ArticleMain();
getFragmentManager().beginTransaction().add(R.id.fragment_Top, articalemain, "MY_FRAGMENT").commit();
While Removing the Fragments do like this :
ArticleMain myFragment = (ArticleMain) getFragmentManager()
.findFragmentByTag("MY_FRAGMENT");
if (myFragment.isVisible()) {
// add your code here
myFragment.getFragmentManager().beginTransaction()
.remove(myFragment).commit();
}

getFragmentByTag() never returns null

I've five fragments in my activity. On the click of fragment drawer list, I'm calling setFrament() method.
It removes the previous fragments from the activity, and adds the new one as per the requirement.
Here's my code for setFragment method.
protected void setFragment(final int position) {
// Remove currently active fragment
if (mActiveFragment != null) {
Fragment previous;
while ((previous = mFragmentManager
.findFragmentByTag(mActiveFragment.toString())) != null) {
mFragmentManager.beginTransaction().remove(previous).commit();
Log.e("in loop", "stuck");
}
}
// It's enum, generated according to position
FragmentType type = getFragmentType(position);
Fragment fragment = mFragmentManager.findFragmentByTag(type.toString());
if (fragment == null) {
fragment = createFragment(type);
}
mFragmentManager
.beginTransaction()
.replace(R.id.containerFrameLayout, fragment,
type.toString()).commit();
// Sets the current selected fragment checked in
// Drawer listview
mFragmentDrawerList.setItemChecked(position, true);
// set Actionbar title
getActionBar().setTitle(type + "");
mActiveFragment = type;
}
Here, while changing the fragment, it keeps prining "stuck" in while loop forever,
my question is,
why remove(Fragment) method doesn't remove the previous fragment from the activity ?
commit() is an asynchronous call that is only executed when the Android system regains control. The fragments won't be removed until some time after you leave the method.
If you want to remove the previous fragment (assuming there's only one), then you can add them to the backstack. Then you can call popBackStack(null, 0) which will pop everything on the back stack. The side catch though is pressing the "back" button will also pop the backstack if the user were to do that. You'll have to override the onBackPressed() and handle it yourself if you don't want that to happen.
EDIT:
One method would be to keep track of all IDs or TAGs and call remove on them individually.
LinkedList<Integer> fragmentIds = new LinkedList<Integer>();
/*** Add fragment to FragmentManager ***/
fragmentIds.add(/** ID of fragment */);
/** Removing all fragments from FragmentManager **/
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
Fragment fragToRemove;
for(Integer id : fragmentIds)
{
fragToRemove = fm.findFragmentById(id);
transaction.remove(fragToRemove);
}
transaction.commit()
fragmentIds.clear();
However, you don't have to call remove on any of them so long as you use replace() method on the same container. replace() will pop the previous fragment and add in the new one. So long as the transaction isn't pushed to the backstack, the previous fragment is detached from the Activity and discarded.

Android how to compare fragments?

I have been using jfeinstein's SlidingMenu. I am currently trying to find if a certain fragment is visible to the user. I first tried:
if(mainfrag.isVisible()){
Log.d("Frag","Main is visible");
}else{
Log.d("Frag","Main is NOT visible");
}
Which always printed that the fragment was NOT visible. I then tried:
android.support.v4.app.FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
Log.d("Frag","CurFrag: "+fragmentManager.findFragmentById(R.id.content_frame).toString());
MainFragment mf = new MainFragment();
if(fragmentManager.findFragmentById(R.id.content_frame) == mf){
Log.d("Frag","This is Main");
}else{
Log.d("Frag","This is NOT Main :(");
}
This prints
So I know that the findFragmentById will tell me the current fragment but I don't know how I can logically compare it so I can do things only if it is visible.
I have never dived into the details of SlidingMenu and couldn't tell you what's wrong in the first problem.
But in your second problem, you are comparing two different objects.
MainFragment mf = new MainFragment();
fragmentManager.findFragmentById(R.id.content_frame) == mf
Here you create a new MainFragment, and try to compare it with a old instance. It can never be true. When comparing Objects, the address are compared. It will only return true if they are the same objects.
If you just want to check the class of object, use the following code:
Fragment f = fragmentManager.findFragmentById(R.id.content_frame);
if(f instanceof MainFragment)
// code here.
Get the fragment by tag or by I'd
Get the fragment's view
Get window visibility on the view will provide visibility

Categories

Resources