Issue with fragmentmanager.popbackstack(); - android-fragments

unable to solve the issue with Fragments back stack. When I try to pop, it throws errors :
Could not find class
'android.support.v4.app.FragmentTransitionCompat21$1', referenced from
method android.support.v4.app.FragmentTransitionCompat21.setEpicenter
Could not find class
'android.support.v4.app.FragmentTransitionCompat21$3', referenced from
method
android.support.v4.app.FragmentTransitionCompat21.setSharedElementEpicenter
and on backpressed again, it crashes.
My code :
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_place, fragment, fragmentTag);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Pop :
int stackCount = getSupportFragmentManager().getBackStackEntryCount();
if (stackCount > 0) {
getSupportFragmentManager().popBackStackImmediate();
}

Related

SIGABRT: Object reference not set to an instance of an object SetStatusBarColor Xamarin iOS

I get the crash SIGABRT: Object reference not set to an instance of an object when submitting the App to the AppStore. I checked the log file from Apple. Noticed at this point:
protected override void OnAppearing()
{
base.OnAppearing();
var statusbar = DependencyService.Get<IStatusBarPlatformSpecific>();
statusbar.SetStatusBarColor(Color.FromHex("f1f1f1"));
}
IStatusBarPlatformSpecific.cs
public interface IStatusBarPlatformSpecific
{
void SetStatusBarColor(Color color);
}
Most affected OS: 15.4.1
Looking forward to a solution from everyone. Thank you
You should get the statusbar like below:
UIView statusBar = new UIView(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame);
if(statusBar == null)
{
//throw a meaningful exception or give some useful feedback!
return;
}
else
{
statusBar.BackgroundColor = color.AddLuminosity(0).ToUIColor();
UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
}

Navigation Drawer: how make fragments persistent (keep alive) while switching (not rotating)

With Fragment:setRetainInstance(true); the fragment is not re-instantiated on a phones orientation change.
And of course i want my fragments to be kept alive while switching from one fragment to another.
But the Android Studio 4 provides a wizard-template with only
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
From hours of debugging and searching the net if think it would need to inherent from the class FragmentNavigator so i can overwrite FragmentNavigator:naviagte where a new fragment gets created via final Fragment frag = instantiateFragment(.. and then is added with ft.replace(mContainerId, frag);
So i could find my old fragment and use ftNew.show and ftOld.hide instead.
Of course this is a stupid idea, because this navigate method is full of other internal stuff.
And i have no idea where that FrameNavigator is created.
I can retrieve it in the MainActivity:OnCreate with
NavigatorProvider navProvider = navController.getNavigatorProvider ();
Navigator<NavDestination> navigator = navProvider.getNavigator("fragment");
But at that time i could only replace it with my derived version. And there is no replaceNavigtor method but only a addNavigator method, which is called where ?
And anyways this all will be far to complicated and therefore error prone.
Why is there no simple option to keep my fragments alive :-(
In older Wizard-Templates there was the possibility of
#Override
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment;
switch (position) {
case 1:
fragment = fragment1;
break;
case 2:
fragment = fragment2;
break;
case 3:
fragment = fragment3;
break;
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if(mCurrentFragment == null) {
ft.add(R.id.container, fragment).commit();
mCurrentFragment = fragment;
} else if(fragment.isAdded()) {
ft.hide(mCurrentFragment).show(fragment).commit();
} else {
ft.hide(mCurrentFragment).add(R.id.container, fragment).commit();
}
mCurrentFragment = fragment;
}
but i have no idea how to do this with the Android 4.0 template where my MainActivity is only derived as:
public class MainActivity extends AppCompatActivity {
private AppBarConfiguration mAppBarConfiguration;
Ideas welcome :'(
Hi there & sorry for my late answer! I had a similar problem with navigation drawers and navigation component. I tried around a little and found a working solution, which might be helpful for others too.
The key is the usage of a custom FragmentFactory in the FragmentManager of the MainActivity. See the code for this below:
public class StaticFragmentFactory extends FragmentFactory {
private myNavHostFragment1 tripNavHostFragment;
private myNavHostFragment2 settingsNavHostFragment;
#NonNull
#Override
public Fragment instantiate(#NonNull ClassLoader classLoader, #NonNull String className) {
if (MyNavHostFragment1.class.getName().equals(className)) {
if (this.myNavHostFragment1 == null) {
this.myNavHostFragment1 = new MyNavHostFragment1();
}
return this.myNavHostFragment1 ;
} else if (MyNavHostFragment2.class.getName().equals(className)) {
if (this.myNavHostFragment2 == null) {
this.myNavHostFragment2 = new MyNavHostFragment2();
}
return this.myNavHostFragment2;
}
return super.instantiate(classLoader, className);
}
}
The FragmentFactory survives the navigation between different fragments using the NavigationComponent of AndroidX. To keep the fragments alive, the FragmentFactory stores an instance of the fragments which should survive and returns this instance if this is not null. You can find a similar pattern when using a singleton pattern in classes.
You have to register the FragmentFactory in the corresponding activity by calling
this.getSupportFragmentManager().setFragmentFactory(new StaticFragmentFactory())
Please note also that I'm using nesten fragments here, so one toplevel fragment (called NavHostFragmen here) contains multiple child fragments. All fragments are using the same FragmentFactory of their parent fragments. The custom FragmentFactory above returns the result of the super class method, when the fragment to be instantiated is not known to keep alive.

DialogFragment not found in fragmentTransaction

I am displaying DialogFragment from a manager. DialogFragment display multiple times.
I want to know is there a way to check from transaction whether this fragment already displaying. So don't display it.
#Override
public void show(FragmentManager manager, String tag) {
try {
FragmentTransaction ft = manager.beginTransaction();
Fragment prev = manager.findFragmentByTag(tag);
if (prev == null) {
ft.add(this, tag);
///ft.addToBackStack(tag);
ft.commitAllowingStateLoss();
}
} catch (IllegalStateException e) {
Log.d("ABSDIALOGFRAG", "Exception", e);
}
}
I am calling my Fragment like
CustomerFeedbackDialog feedbackDialog = CustomerFeedbackDialog.newInstance(genaric.getData(), type);
feedbackDialog.show(getSupportFragmentManager(), "feedbackDialog");
I have call findFragmentByTag but it is always null. I don't want to show already displayed Fragment. otherwise it duplicate . Mulitple dialogFragment opens
I know I can do it using a flag in sharedprefs
EDIT Solution found
Thanks for your help. Problem solved and I posted answer below
If your problem is the same DialogFragment over another you can try adding a variable to your Manager:
#Nullable
private DialogFragment mCurrentDialogFrag;
And then whenever you add a new DialogFragment you set mCurrentDialogFrag to the new DialogFragment and then check before adding if current DialogFragment is the same as the new one.
I finally able to handle it by overriding show method
and addToBackStack(null) and executePendingTransactions
Firstly to put tag in findFragmentByTag addToBackStack is must otherwise tag is not added in fragmentTransaction.
#Override
public void show(FragmentManager manager, String tag) {
try {
FragmentTransaction ft = manager.beginTransaction();
Fragment prev = manager.findFragmentByTag(tag);
if (prev == null) {
ft.add(this, tag);
ft.addToBackStack(null);
ft.commitAllowingStateLoss();
manager.executePendingTransactions();
}
} catch (IllegalStateException e) {
Log.d("ABSDIALOGFRAG", "Exception", e);
}
}
Now if fragment is already in transaction. It will not display again..
If I look into DialogFragment's public void show(FragmentManager manager, String tag) method implementation, I can see this:
public void show(FragmentManager manager, String tag) {
this.mDismissed = false;
this.mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();
}
In order to know my dialog is already part of FragmentManager transactions, I'm simply doing this:
if (getFragmentManager().findFragmentByTag("...the tag") == null) {
fragment.show(getFragmentManager(), "...the tag");
}
I have to mention the above is strictly appcompat experience, and it works. Obviously you can put this check code inside override of show as well.

add multiple fragment to cheesesquare demo

I am using an open source project(https://github.com/chrisbanes/cheesesquare) to develop my own application.
what I want is:
1.In the Home Fragment, there is a tablayout below to the toobar,and when the recycelview scroll, the Toolbar can hide, but the FloatingActionButton always stay;
2. In the Message Frgment, the is no Tab and on FloatingActionButton, only a simple blank Fragment with a Toolbar.
I try to do this in MainActivity:
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
menuItem.setChecked(true);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment fragment = null;
int id = menuItem.getItemId();
if (id == R.id.nav_home) {
fragment = new HomeFragment();
} else if (id == R.id.nav_message) {
fragment = new MessageFragment();
} else if (id == R.id.nav_friends) {
fragment = new FriendsFragment();
} else if (id == R.id.nav_discussion) {
fragment = new DiscussionFragment();
}
ft.replace(R.id.viewpager, fragment);
ft.commit();
mDrawerLayout.closeDrawer(GravityCompat.START);
return true;
}
});
}
but this not work, because the tablayout stay both in HomeFragment and MessageFragment.
When I try to do change the tablayout to the layout xml of HomeFragment, I also meet some problem because the below code should write in MainActivity
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
I feel puzzled, what should I do to achieve my goals?
I try to solve the problem like this, implement the basic functions.

How to prevent a fragment from being added multiple times?

It's common for a Fragment to be added to a layout when a UI element, such as a button is tapped. If the user taps the button multiple times very quickly, it can happen that the Fragment is added multiple times, causing various issues.
How can this be prevented?
I created a helper method that ensures that the fragment is only added if it doesn't yet exist:
public static void addFragmentOnlyOnce(FragmentManager fragmentManager, Fragment fragment, String tag) {
// Make sure the current transaction finishes first
fragmentManager.executePendingTransactions();
// If there is no fragment yet with this tag...
if (fragmentManager.findFragmentByTag(tag) == null) {
// Add it
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(fragment, tag);
transaction.commit();
}
}
Simple call as such from an Activity or another Fragment:
addFragmentOnlyOnce(getFragmentManager(), myFragment, "myTag");
This works with both the android.app.* and the android.support.app.* packages.
Here my solution, I have try to click show dialog fragment by tap button multiple time and quickly.
FragmentManager fm = getSupportFragmentManager();
Fragment oldFragment = fm.findFragmentByTag("wait_modal");
if(oldFragment != null && oldFragment.isAdded())
return;
if(oldFragment == null && !please_wait_modal.isAdded() && !please_wait_modal.isVisible()){
fm.executePendingTransactions();
please_wait_modal.show(fm,"wait_modal");
}

Resources