Why is this returning the "fragment already added" error and crashing the app?
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);
ft.replace(R.id.fragment_container, tempmainfrag);
ft.commit();
for(int i = 0; i < fm.getBackStackEntryCount(); i++)
{
fm.popBackStack();
}
I'm guessing it is because of the for loop as it works without it, but I am needing to clear the back stack, how can I properly do this?
I've had the same error when working with mapfragments, this is what finally solved it for me:
#Override
public void onDestroyView() {
super.onDestroyView();
SupportMapFragment f = (SupportMapFragment) getFragmentManager().findFragmentById(R.id.current_fragment);
if (f != null)
getFragmentManager().beginTransaction().remove(f).commit();
}
Hope it helps.
Related
I'm developing an application that involves fragments. There are three fragments
Item List fragment
Item details fragment
Search/Loading fragment
Everything works well until the user press onbackbutton. I would like to show the user the previous fragment before the search fragment was shown.
I tried few solutions but none of them seems to work for me. I tried to remove the search fragment manually from back stuck but I got weird situation that the previous and the current fragment were shown at the same time.
This is the function that replaces the fragments from the main activity
public void replaceFragment(Class<?> fragClass, Bundle b)
{
Fragment bf = null;
try
{
bf = (Fragment) fragClass.newInstance();
}
catch (Exception e)
{
e.printStackTrace();
}
if (b != null)
{
bf.setArguments(b);
}
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
String backStateName = bf.getClass().getSimpleName();
if (f != null && backStateName.equals(f.getClass().getSimpleName()))
{
return;
}
FragmentManager manager = getSupportFragmentManager();
_currentFragment = bf;
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_left, R.anim.exit_to_right);
if(backStateName.equals(LoadingFragment.class.getSimpleName()))
{
ft.replace(R.id.fragment_container, bf).addToBackStack(null).commit();
}
else
{
ft.replace(R.id.fragment_container, bf).addToBackStack(backStateName).commit();
}
}
onbackpress function
#Override
public void onBackPressed()
{
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START))
{
drawer.closeDrawer(GravityCompat.START);
}
else
{
super.onBackPressed();
}
}
After many hours of figuring this out. I came across a simple solution, basically each time when I'm loading a new fragment I'm checking if the current fragment is the search fragment if so I will remove it manually by using popBackStackImmediate(). Not the most elegant solution but it worked for me.
This is my new function.
public void replaceFragment(Class<?> fragClass, Bundle b)
{
BaseFragment bf = null;
try
{
bf = (BaseFragment) fragClass.newInstance();
}
catch (Exception e)
{
e.printStackTrace();
}
if (b != null)
{
bf.setArguments(b);
}
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
String backStateName = bf.getClass().getSimpleName();
if (f != null && backStateName.equals(f.getClass().getSimpleName()))
{
return;
}
FragmentManager manager = getSupportFragmentManager();
_currentFragment = bf;
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (f != null && f.getClass().getSimpleName().equals(LoadingFragment.class.getSimpleName()))
{
manager.popBackStackImmediate();
}
ft.replace(R.id.fragment_container, bf, backStateName);
ft.addToBackStack(backStateName);
ft.commitAllowingStateLoss();
}
I'm a newbie in android and using android studio 2.2
In my app I've used different fragments and they appear when user click on an ImageView and I've used addToBackStack function for the device back button. It takes me to the exactly previous fragment but it does not highlight the previous Imageview according to the statements when clicked on back button.
Here is the code for fragments
public void dates(View view)
{
if(frag != null)
{
home1.setBackgroundDrawable(getResources().getDrawable(R.drawable.home_icon));
subs1.setBackgroundDrawable(getResources().getDrawable(R.drawable.subscription_icon));
noti1.setBackgroundDrawable(getResources().getDrawable(R.drawable.noti_icon));
settings1.setBackgroundDrawable(getResources().getDrawable(R.drawable.setting_icon));
date1.setBackgroundDrawable(getResources().getDrawable(R.drawable.date_icon_black));
date.setTextColor(0xFF000000);
getSupportActionBar().setTitle("Available Dates");
frag = new AvailableDates();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.container1,frag);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
public void subscription(View view)
{
if (frag != null)
{
home1.setBackgroundDrawable(getResources().getDrawable(R.drawable.home_icon));
subs1.setBackgroundDrawable(getResources().getDrawable(R.drawable.subscription_icon_black));
noti1.setBackgroundDrawable(getResources().getDrawable(R.drawable.noti_icon));
settings1.setBackgroundDrawable(getResources().getDrawable(R.drawable.setting_icon));
date1.setBackgroundDrawable(getResources().getDrawable(R.drawable.date_icon));
subs.setTextColor(0xFF000000);
getSupportActionBar().setTitle("Subscriptions");
frag = new Subscription();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.container1,frag);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
If you want to hightlight/changes when press back, you need to control manually back press like this in your activity:
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 1) {
getFragmentManager().popBackStack();
// Now, your AvailableDates fragment resumes, you can hightlight your views again
} else {
super.onBackPressed();
}
}
I am building an android app that uses a drawer navigation and it looks and works well except i cant add the current view (fragment) to the back stack to get allow the user navigate the app more easily. at the moment the back button just exits the app when pressed. i have looked at various questions on here and none have worked.
Here is my current attempt and dont understand why it dosent work.
if (id == R.id.nav_gallery) {
// fragmentManager.beginTransaction().replace(R.id.content_frame, new GalleryFragment()).commit();
// fragmentManager.beginTransaction().addToBackStack(null);
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.content_frame, new GalleryFragment());
ft.addToBackStack(null);
ft.commit();
}
edit
onbackPressed
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
FragmentManager fragmentManager = getFragmentManager();
int backCount = fragmentManager.getBackStackEntryCount();
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
if you want to control your transaction when back button pressed of android then use below code
#Override
public void onBackPressed() {
// initialize variables
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
// check to see if stack is empty
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
ft.commit();
}
else {
if (this.lastBackPressTime < System.currentTimeMillis() - 4000) {
Toast.makeText(this, "Nochmal drücken zum Beenden!", 4000).show();
this.lastBackPressTime = System.currentTimeMillis();
} else{
super.onBackPressed();
}
}
}
instead of doing
super.onBackPressed();
Pop the top state off the back stack using the below condition
if(backCount >0){
fragmentManager.popBackStack();
}else{
super.onBackPressed();
}
Can you please try this one ?
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.content_frame, new GalleryFragment());
ft.addToBackStack("gallery_fragment");
ft.commit();
Hope this will help you.
I'm developing a kiosk app where people can walk to and order something.
I have a single activity with bunch of different fragments (order, review, pay, etc). Some replace each other, and some get added. The activity has a single fragment hardcoded R.id.fragmentContainer and the rest are programmatically added and tagged.
Now what I want is to have a function in my activity that calls one of the elements of the fragments (look at updateReceivedData()) but for some reason I'm not able to do so and I get cannot resolve method adjustPriceFunc.
I'm adding the code so someone could tell me what I'm doing wrong. The app would normally talk to some hardware so I took out a bunch of those details from the code to make it easier to read.
public class MainActivity extends FragmentActivity {
private final String TAG = MainActivity.class.getSimpleName();
List<WeakReference<Fragment>> fragList = new ArrayList<WeakReference<Fragment>>();
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
setContentView(R.layout.backbone);
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
android.support.v4.app.Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if (fragment == null) {
fragment = new Fragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment, "SystemDownFragment")
.addToBackStack(null)
.commit();
}
}
public void orderFunc() {
Log.d(TAG, "orderFunc()");
if(sendingLogFlag) attemptSend(TAG + ":orderFunc()");
for(int i = 0; i < getActiveFragments().size(); i++) {
getSupportFragmentManager().beginTransaction().remove(getActiveFragments().get(i)).commit();
}
Fragment newFragment = new Fragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.fragmentContainer, newFragment, "OrderFragment");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();
}
public void checkoutFunc() {
Log.d(TAG, "checkoutFunc()");
if(sendingLogFlag) attemptSend(TAG + ":checkoutFunc()");
for(int i = 0; i < getActiveFragments().size(); i++) {
getSupportFragmentManager().beginTransaction().remove(getActiveFragments().get(i)).commit();
}
Fragment newFragment = new Fragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.fragmentContainer, newFragment, "CheckOutFragment");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();
}
public void reviewFunc(){
Log.d(TAG, "reviewFunc()");
if(sendingLogFlag) attemptSend(TAG + ":reviewFunc()");
if(getActiveFragments().size() > 1){
Fragment frag = getSupportFragmentManager().findFragmentByTag("ReviewFragment");
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
ft.remove(frag);
ft.commit();
}
else {
Fragment newFragment = new Fragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.add(R.id.fragmentContainer, newFragment, "ReviewFragment");
ft.commit();
}
getSupportFragmentManager().executePendingTransactions();
}
public void payFunc(boolean enabled){
Log.d(TAG, "payFunc()");
if(sendingLogFlag) attemptSend(TAG + ":payFunc()");
if(!enabled){
Fragment frag = getSupportFragmentManager().findFragmentByTag("PayFragment");
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
ft.remove(frag);
ft.commit();
}
else {
Fragment newFragment = new Fragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.add(R.id.fragmentContainer, newFragment, "PayFragment");
ft.commit();
}
getSupportFragmentManager().executePendingTransactions();
}
public void doneFunc() {
Log.d(TAG, "doneFunc()");
for(int i = 0; i < getActiveFragments().size(); i++) {
getSupportFragmentManager().beginTransaction().remove(getActiveFragments().get(i)).commit();
}
Fragment newFragment = new Fragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.add(R.id.fragmentContainer, newFragment, "StartupFragment");
ft.commit();
}
#Override
public void onAttachFragment (Fragment fragment) {
fragList.add(new WeakReference(fragment));
}
public List<Fragment> getActiveFragments() {
ArrayList<Fragment> ret = new ArrayList<Fragment>();
for(WeakReference<Fragment> ref : fragList) {
Fragment f = ref.get();
if(f != null) {
if(f.isVisible()) {
ret.add(f);
}
}
}
return ret;
}
private void updateReceivedData() {
Fragment frag = getSupportFragmentManager().findFragmentByTag("PayFragment");
frag.adjustPriceFunc();
}
You are trying to use method adjustPriceFunc() from class Fragment, which is not part of it.
Use this code, where MyFragment is your proper fragment (I assume it should be PayFragment).
private void updateReceivedData() {
Fragment frag = getSupportFragmentManager().findFragmentByTag("PayFragment");
if (frag instanceof MyFragment) {
frag.adjustPriceFunc();
}
}
There is few mistakes here in the code
In orderFunc, checkoutFunc etc. add remove to the transaction and call commit once after the loop, like
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
for(int i = 0; i < getActiveFragments().size(); i++) {
transaction.remove(getActiveFragments().get(i));
}
transaction.commit();
You get compilation error in updateReceivedData because Fragmentdoes not have adjustPriceFunc() method. You need either (cleaner approach) create interface with adjustPriceFunc() method, let your fragment implement it and then your updateReceivedData will look like follows:
private void updateReceivedData() {
InterfaceWithAdjustPriceMethod frag = (InterfaceWithAdjustPriceMethod) getSupportFragmentManager().findFragmentByTag("PayFragment");
frag.adjustPriceFunc();
}
Storing reference to fragment is a bad practice, even if it is WeakReference.
Better use this way:
Fragment fragment = getSupportFragmentManager().findFragmentByTag("tag");
I am new to android working first time on fragment.I am creating an app in which I want to add a fragment on frame layout.I am able to do this but now what I want is to remove the same fragment which i added by that same button click I tried but couldn't. here is my code.
public void onClick(View v) {
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
if(v.getId() == R.id.clickme){
if(getSupportFragmentManager().findFragmentById(R.layout.fragment_one) != null){
// getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentById(R.layout.fragment_one)).commit();
Fragment fragment = new FragmenOne();
fragmentManager.beginTransaction().remove(fragment).commit();
}else{
Fragment fragment = new FragmenOne();
// android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.my_frame, fragment)
.commit();
}
}
}
You need to do in this manner
Fragment f = fragmentManager.findFragmentById(R.id.my_frame);
if(f instanceof FragmenOne) {
FragmenOne oneFragment = (FragmenOne) f;
FragmentTransaction trans = manager.beginTransaction();
trans.remove(oneFragment);
trans.commit();
fragmentManager.popBackStack();
}else{
Fragment fragment = new FragmenOne();
fragmentManager.beginTransaction()
.replace(R.id.my_frame, fragment)
.commit();
}