Creating Fragments in Android? - android

#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if(tab.getPosition()==0)
{
FragmentA frag = new FragmentA();
ft.replace(android.R.id.content, frag);
}
else
{
FragmentB frag = new FragmentB();
ft.replace(android.R.id.content, frag);
}
}
The above code loads in fragments, the problem is it creates a new instance of each fragment, so going to and from tabs, the fragment reloads. What is the best way to make it so it does not create a new instance of each fragment eahc time and only uses the origial instance?
Thanks

Use an attribute in your class
private frag = new Fragment();
...
if(tab.getPosition()==0)
{
ft.replace(android.R.id.content, frag);
}

You will need to add a method to push a fragement to the backstack or pop items off so we may reuse a fragment already in the back stack. The "name" param in the following function provides the best way to locate and pop back (if needed)
private void popToOrPushFragmentWithName(Fragment fragment, String name, FragmentTransaction ft) {
FragmentManager manager = getSupportFragmentManager();
// Scan the back stack for an entry with the given fragment name
int count = manager.getBackStackEntryCount();
FragmentManager.BackStackEntry entry = null;
while (--count >= 0) {
FragmentManager.BackStackEntry check = manager.getBackStackEntryAt(count);
if (check.getName() != null && check.getName().equals(name)) {
entry = check;
break;
}
}
if (entry == null) {
// There is no entry, so push the fragment
ft.replace(R.id.fragment_container, fragment);
ft.addToBackStack(name);
// might not need this next line (since you are using tabselected override)
ft.commit();
} else {
// Pop back to the existing fragment (0 = not inclusive, so our fragment by index is on top)
manager.popBackStackImmediate(entry.getId(), 0);
}
}
Your onTabselected should look something like this :
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if(tab.getPosition()==0)
{
FragmentA frag = new FragmentA();
popToOrPushFragmentWithName(frag, "FragmentA", ft);
}
else
{
FragmentB frag = new FragmentB();
popToOrPushFragmentWithName(frag, "FragmentB", ft);
}
}
I hope this helps. :)

Related

How to show a fragment inside a specific Fragment Container in Android

Whenever I want to change fragment depending on the item selected I use:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
But now I want to make it so that I can simply show the different fragments instead of creating new ones every time I re-select them, so I found .show instead of .replace, but the problem with .show is that I can not declare where I want that fragment to be shown... or perhaps I'm maybe doing it wrong:
getSupportFragmentManager().beginTransaction().show(fragment).commit();
If you want to use show/hide method, you need to add a fragment before this, as you can see the container is available here. I just showed an example of how to show or hide one fragment. If you have a lot of fragments you can for example save the list and then hide others in the loop. If interested, I added from below.
public void showFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if (fragment.isAdded()) {
fragmentTransaction.show(fragment);
} else {
fragmentTransaction.add(R.id.container, fragment);
}
fragmentTransaction.commit();
}
public void hideFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if (fragment.isAdded()) {
fragmentTransaction.hide(fragment);
}
fragmentTransaction.commit();
}
If there are many fragments
public class MainActivity extends AppCompatActivity {
HashMap<String, Fragment> fragments = new HashMap<>();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/*
* call this method when you want to add a new fragment
* Example: addFragment(new A(), "TAG_A")
* */
public void addFragment(Fragment fragment, String fragmentTag) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
/*Before add fragment we hide others*/
for (String fTag : fragments.keySet()) {
Fragment fragmentInStack = fragments.get(fTag);
if (fragmentInStack.isAdded() && !fragmentInStack.isHidden()) {
fragmentTransaction.hide(fragmentInStack);
}
}
if (!fragment.isAdded()) {
fragments.put(fragmentTag, fragment);
fragmentTransaction.add(R.id.container, fragment, fragmentTag);
} else {
fragmentTransaction.show(fragment);
}
fragmentTransaction.commit();
}
/*
* call this method when you want to show fragment which are on the list
* Example: We have current fragment C and you want to show fragment A, that to call showFragment("TAG_A")
* */
public void showFragment(String fragmentTag) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
/*hide others fragment besides the one we need to show*/
for (String fTag : fragments.keySet()) {
Fragment fragmentInStack = fragments.get(fTag);
if (!fTag.equals(fragmentTag) && fragmentInStack.isAdded()) {
fragmentTransaction.hide(fragmentInStack);
}
}
Fragment fragment = fragments.get(fragmentTag);
if (fragment != null && fragment.isAdded()) {
fragmentTransaction.show(fragment);
}
fragmentTransaction.commit();
}
}

How to check if the fragment exists

I am trying to talk to the fragments from activity.
Here in my MainActivity I am adding multiple fragments ok so for fine.
My main requirement is I don't want to add if fragment is already added.
So how can we check this condition?
Please help me some one.
code:-
private void intializingFragments(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
private View.OnClickListener intialization() {
return new View.OnClickListener() {
#Override
public void onClick(View v) {
int getId = v.getId();
if (getId == R.id.first) {
intializingFragments(new Fragment1());
} else if (getId == R.id.second) {
intializingFragments(new Fragment2());
} else if (getId == R.id.third) {
intializingFragments(new Fragment3());
}
}
};
}
You can use findFragmentByTag() or findFragmentById() functions to get a fragment. If mentioned methods are returning null then that fragment does not exist.
Fragment fragmentA = fragmentManager.findFragmentByTag("frag1");
if (fragmentA == null) {
// not exist
} else {
// fragment exist
}
for example:- http://wiki.workassis.com/android-load-two-fragments-in-one-framelayout/
You may find fragment in fragmentmanager:
List<Fragment> frags = getSupportFragmentManager().getFragments();
for (Fragment f : frags) {
<find what you want>...
}
Or you may add fragment with tag:
getSupportFragmentManager()
.beginTransaction()
.add(R.id.frame, new MyFragment(), "frag1")
.commit();
And find by tag
getSupportFragmentManager().findFragmentByTag("frag1");
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
Fragment topFragment = fragmentManager.findFragmentById(R.id.container);
FragmentA fragmentA = new FragmentA();
if(topFragment!= null)
{
transaction.remove(topFragment);
transaction.add(R.id.container, fragmentA, "FA");
transaction.commit();
}
else
{
transaction.add(R.id.container, fragmentA, "FA");
transaction.commit();
}
try this
private void intializingFragments(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment topFragment = fragmentManager.findFragmentById(R.id.container);
if(topFragment!= null)
{
fragmentTransaction.remove(topFragment);
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
else
{
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
How to check whether a fragment exists, without knowing its resource ID or tag:
// MyActivity.kt
val exists: Boolean = supportFragmentManager
.fragments
.filterIsInstance<MyFragment>()
.isNotEmpty()
There are many ways by which you can track the last added fragment. The simplest one is by finding the tag within fragment manager. Here is the sample code of it:
public boolean isFragmentPresent(String tag) {
Fragment frag = getSupportFragmentManager().findFragmentByTag(tag);
if (frag instanceof HomeFragment) {
return true;
} else
return false;
}
Alternatively, you can use your own variable to check whether the last added fragment is the same as the current fragment. Here is the sample code for it:
public boolean isCurrentFragment(Fragment fragment) {
if (fragment instanceof HomeFragment && getLastAddedFragment() instanceof HomeFragment) { // getLastAddedFragment() is a method which return the last added fragment instance
return true;
} else
return false;
}
And you can use it like:
if (isCurrentFragment(new HomeFragment())) {
// Last added Fragment is the HomeFragment
}
You can go for popBackStack Pop the last fragment transition from the manager's fragment back stack. If there is nothing to pop, false is returned. enter link description here
You can get the list of previously added fragments from the fragment manager. Then just check whether the list contains your fragment object or not.
getSupportFragmentManager().getFragments().contains(yourFragment);
This one doesn't work
!getSupportFragmentManager().getFragments().contains(fragment)
This works for me
getSupportFragmentManager().findFragmentByTag(fragment::class.java.getSimpleName()) == null

Android Fragments - remove fragment from back stack if already exists

I have some fragments which will be replaced by following method. I think there's something wrong with my code because I want to prevent from adding multiple times a fragment into the back stack. If I click on fragment B twice, all instances will be added to the back stack and pressing back button will be passed through the two created instances.
public void replaceFragment(Fragment fragment, boolean addToBackStack, boolean customAnimation) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
String tag = fragment.getClass().getSimpleName();
if (customAnimation) {
transaction.setCustomAnimations(R.anim.slide_in_bottom, R.anim.slide_out_bottom, R.anim.slide_in_bottom, R.anim.slide_out_bottom);
}
transaction.replace(R.id.fragment_container, fragment, tag);
// remove from back stack if exists
// always return false!
boolean f = manager.popBackStackImmediate(tag, 0);
if (addToBackStack) {
transaction.addToBackStack(tag);
}
transaction.commit();
}
Keep it simple and just add to the back stack if needed.
If the Fragment being added is the same class as the current Fragment, don't add to the back stack:
public void replaceFragment(Fragment frag) {
FragmentManager manager = getSupportFragmentManager();
if (manager != null){
FragmentTransaction t = manager.beginTransaction();
Fragment currentFrag = manager.findFragmentById(R.id.content_frame);
//Check if the new Fragment is the same
//If it is, don't add to the back stack
if (currentFrag != null && currentFrag.getClass().equals(frag.getClass())) {
t.replace(R.id.content_frame, frag).commit();
} else {
t.replace(R.id.content_frame, frag).addToBackStack(null).commit();
}
}
}
try this on your activity onBackPressed method :
#Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
if (fm.getBackStackEntryAt(fm.getBackStackEntryCount() - 1).getName().equals("your fragment tag")) {
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}

Back Button on fragment not working

I have a fragment activity from where i can start my fragments which contain a viewpager. In my fragment activity I have added this piece of code.
fragment = new ItemPagerFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_frame, fragment);
transaction.addToBackStack(null);
transaction.commit();
Now when I press back button only blank screen appears and it does not lead me to my fragment activity.
What wrong i might be doing?
Use this in activity that holds fragment.
#Override
public void onBackPressed() {
if (fragmentManager.getBackStackEntryCount() > 1) {
fragmentManager.popBackStack();
} else
finish();
}
Try this way,
// Create new fragment and transaction
Fragment newFragment = new ItemPagerFragment();
// consider using Java coding conventions (upper first char class names!!!)
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.content_frame, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
Modify your code
#Override
public void onBackPressed() {
if(some condition) {
// do something
} else {
super.onBackPressed();
}
}
Please follow this link
Handling back button press Inside Fragments
You have to tell to the fragment manager that the back button was pressed. Override onBackPressed on your Activity
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 0) {
super.onBackPressed();
} else {
getFragmentManager().popBackStack();
}
}
private void changeFragment (Fragment fragment){
String backStackName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStackName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStackName );
ft.commit();
}
}
While launching fragment assign a TAG to each fragment.When you want to back press check the existence of an fragment using assigned TAG name and then do corresponding action.for example:
private final static String TAG_FRAGMENT = "TAG_FRAGMENT";
//when want to add fragment to view
private void showFragment() {
final Myfragment fragment = new MyFragment();
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment, fragment, TAG_FRAGMENT);
transaction.addToBackStack(null);
transaction.commit();
}
//in activity back pressed check the existence of fragment by TAG
#Override
public void onBackPressed() {
final Myfragment fragment = (Myfragment) getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT);
if (fragment.allowBackPressed()) { // and then you define a method allowBackPressed with the logic to allow back pressed or not
super.onBackPressed();
}
}

How to make a fragment be in the exact same way I left it when I return to it from another fragment?

I have a few fragments in my app, but my code opens a new fragment every time I click the button.
I want to know how can I change this, and make the fragment return to the exact same state I left it in.
The code im using right now:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragments);
MainActivity fragment = new MainActivity();
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.add(R.id.fragment_place, fragment);
transaction.commit();
turnGPSOn();
}
public void onSelectFragment(View view) {
if (view == findViewById(R.id.add))
{
newFragment = new Add();
}
else if (view == findViewById(R.id.map))
{
newFragment = new MainActivity();
}
else
{
newFragment = new Add();
}
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.replace(R.id.fragment_place, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}
Thanks!
You are getting a new fragment each time because you are calling to new XXX() each time.
I think you could use findFragmentByTag in order to solve this problem. As you can see here the replace function can accept a third parameter that is a String, this String can be used as an id to identify different fragments you have used previously.
So to sum up you can:
Call Fragment f = getSupportFragmentManager().findFragmentByTag("FragAdd"); for example in order to retrieve the first fragment.
If f is null, that means that you haven't used that fragment yet, so you have to call to new Add() if not, use that fragment to replace the old one. For example like this:
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.replace(R.id.fragment_place, newFragment, "FragAdd"); //or whatever other string you want to use
transaction.addToBackStack(null);
transaction.commit();
Hope it helps :)
I faced this issue a time ago, and managed to solve it for applications with one visible fragment at a time; for activities with several visible fragments, you'll need to make some adjustments. This is what I did.-
Create a custom ParentActivity, so that all my activities extend it. ParentActivity knows about which is the current Fragment that is showed, and how to show a new one.
public String currentFragmentTag;
public ParentFragment getCurrentFragment(int fragmentWrapperResId) {
ParentFragment res = null;
FragmentManager fragmentManager = getSupportFragmentManager();
res = (ParentFragment) fragmentManager.findFragmentById(fragmentWrapperResId);
if (res != null && res.isHidden()) {
if (currentFragmentTag != null) {
res = (ParentFragment) fragmentManager.findFragmentByTag(currentFragmentTag);
}
}
return res;
}
public void openFragment(ParentFragment fragment, int fragmentWrapperResId, int enterAnim, int exitAnim, int popEnterAnim, int popExitAnim, boolean addToBackStack) {
FragmentManager fragmentManager = getSupportFragmentManager();
ParentFragment currentFragment = getCurrentFragment(fragmentWrapperResId);
if (currentFragment != null && currentFragment.getTagName().equals(fragment.getTagName())) {
return;
}
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim);
if (currentFragment != null) {
transaction.hide(currentFragment);
}
if (fragment.isAdded()) {
transaction.show(fragment);
} else {
transaction.add(fragmentWrapperResId, fragment, fragment.getTagName()).setBreadCrumbShortTitle(fragment.getTagName());
}
if (addToBackStack) {
transaction.addToBackStack(fragment.getTagName());
} else {
currentFragmentTag = fragment.getTagName();
}
transaction.commit();
}
Create a ParentFragment, to be extended by the rest of Fragments, with a tag getter
public String getTagName() {
return getClass().getSimpleName() + System.identityHashCode(this);
}
As you can see, the main idea is not replacing visible fragments, but just adding them and show/hide whenever it's needed. This way, the fragments will keep their states, as they're not destroyed until you remove them from the bakstack.

Categories

Resources