I try to change textview under attached fragment on activity so i stored attachedFragment as variable as code below
#Override
public void onAttachFragment(android.support.v4.app.Fragment fragment) {
super.onAttachFragment(fragment);
attachedFragment = fragment;
}
then when a button is clicked I call following code
if(attachedFragment != null && attachedFragment.getView() != null)
{
TextView tvGender = (TextView) attachedFragment.getView().findViewById(R.id.tv_gender);
if(tvGender!=null)
tvGender.setText(R.string.title_step_one_gender);
}
When I start the activity and it works fine until i changed into the next fragment and pressed back; the attachedFragment.getView() always returns null
My question:
How is it possible it returns null while the first time is okay?
What is the best solution to change textview/any other control
within fragment? There are lots of fragments and I only need to
change attached fragment.
nb: All code above are under main activity
Please correct me if I misunderstood your question. It sounds like your situation is, you attach fragment A, then you attach fragment B, then you press back, leaving you with fragment A. In this case, attachedFragment is just a variable, so it continues to point to B, but since B is now detached, it is null. Pressing back will not repopulate the variable attachedFragment with fragment A.
Try using findFragmentById or findFragmentByTag. Check out this thread for more info.
Related
Problem:
I need to perform onClick on a view present in Fragment depending upon the location from which the activity was launched.
I have setArguments on Bundle in myActivity's onCreate:
final String launchedFrom = getIntent().getStringExtra(LAUNCHED_FROM);
if (launchedFrom!=null) {
bundle.putBoolean("myStr", true);
}
Now, I fetch the argument from onCreateView of Fragment and perform click on 3rd item in the list:
if (this.getArguments().getBoolean("myStr")) {
mOptions.getAdapter().getView(3, null, null).callOnClick();
}
This opens the 3rd item on the list. Now, when I press back button the onCreateView is getting called again and the control is redirected to the 3rd item in the list as the bundle arguments have not changed on backPress.
I want to navigate back to the place from where the activity was called when I press the back button.
This is the code that is called when using .callonClick()
#Override
public void onViewSelected(List<Entry> faqs) {
Fragment fragment = FragmentB.newInstance(new ArrayList<>(faqs));
getFragmentManager().beginTransaction()
.replace(R.id.activity_frame_layout, fragment)
.addToBackStack(FragmentB.TAG)
.commit();
}
Solution#1: Not the best approach, if I move the code of onCreateView to onCreate, but I think there needs to be a better approach to solve this.
I have an activity with two fragments, Fragment A and Fragment B. I want to show a view hidden in Fragment A when the user touches a button in fragment B. How can I do this? I have tried to get the whole layout of the activity and get the view but I get a null pointer exception.
My activity layout is as shown below
This is the line I am using. It throws a null pointer exception.
shadowLine = getActivity().findViewById(R.id.shadowLine);
shadowLine.setVisibility(View.VISIBLE);
The simplest way, not the safest:
You can access hosting activity in fragment B by
HostActivity activity =(HostActivity) getActivity();
activity.callOtherFragment();
In that activity, you can access fragment A, by
public void callOtherFragment() {
YourFragment A = (YourFragment)getFragmentManager().findFragmentById(R.id.fragmentA);
A.showSomeStuff();
}
then implement your method in fragment A:
public void showSomeStuff() {
shadowLine.setVisibility(View.VISIBLE);
}
I have one activity containing one container that will receive 2 fragments.
Once the activity initialises i start the first fragment with:
showFragment(new FragmentA());
private void showFragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragment, fragment.getTag())
.addToBackStack(fragment.getTag())
.commit();
}
Then when the user clicks on FragmentA, I receive this click on Activity level and I call:
showFragment(new FragmentB());
Now when I press back button it returns to fragment A (thats correct) and when i press again back button it show empty screen (but stays in the same activity). I would like it to just close the app (since the activity has no parent).
There are a lot of posts related with Fragments and backstack, but i can't find a simple solution for this. I would like to avoid the case where I have to check if im doing back press on Fragment A or Fragment B, since i might extend the number of Fragments and I will need to maintain that method.
You are getting blank screen because when you add first fragment you are calling addToBackStack() due to which you are adding a blank screen unknowingly!
now what you can do is call the following method in onBackPressed() and your problem will be solved
public void moveBack()
{
//FM=fragment manager
if (FM != null && FM.getBackStackEntryCount() > 1)
{
FM.popBackStack();
}else {
finish();
}
}
DO NOT CALL SUPER IN ONBACKPRESSED();
just call the above method!
addToBackStack(fragment.getTag())
use it for fragment B only, not for fragment A
I think your fragment A is not popped out correctly, try to use add fragment rather replace to have proper back navigation, however You can check count of back stack using:
FragmentManager fragmentManager = getSupportFragmentManager();
int count = fragmentManager.getBackStackEntryCount();
and you can also directly call finish() in activity onBackPressed() when you want your activity to close on certain fragment count.
Given an Activity that acts as a Home page (it never closes) that launches various fragments, how to know when the Activity is visible to the user?
From what I have observed, when I open a fragment the lifecycle for the Activity never changes, onPause() is not called. And when I close the fragment, onResume() is not called on my Activity.
Here is how I am starting my fragments, I am using this method and passing the fragment I want to launch to it.
public void addFragment(int containerId, Fragment fragment, boolean addToBackStack) {
// Check if the fragment has been added already. If so, then
// don't add the fragment.
Fragment temp = mFragmentManager.findFragmentByTag(fragment.getClass().getName());
if(temp != null && temp.isAdded()) {
return;
}
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.add(containerId, fragment, fragment.getClass().getName());
if(addToBackStack)
ft.addToBackStack(null);
ft.commit();
}
What is the methodology for indicating that my Activity is visible again? Thanks in advance!
in the oncreate method of your home activity, call
mFragmentManager.addOnBackStackChangedListener(this) ;
and then define
#Override
public void onBackStackChanged() {
int backStackCount = mFragmentManager.getBackStackEntryCount();
if(backStackCount == 0) {} //back to home screen
}
Your Activity is always Visible even if thousand Fragments are showing at the same time, for the sake of understanding Fragments are just Custom-Views, and the Fragment gives a helping hand in handling your View, so onPause() on your activity does not need to called when a Fragment dies or is born,just like inflating a View.
Just like Sir #Tim Mutton said, you need to check your BackStack to know if you are back, or you can use the ViewGroup method ViewGroup.indexOfChild(View child) - this method will an int of value getChildCount()-1 which means its on top of its fellow sibblings..
Hope it helps
I'll try to explain my problem:
all my fragments are using setRetainInstance(true)
In my activity onCreate I'm doing this:
if (savedInstanceState == null) {
fragment = onCreatePane();
fragment.setArguments(intentToFragmentArguments(getIntent()));
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.add(R.id.root_container, fragment, getFragmentTag());
trans.commit();
} else {
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
if ( fragment == null ) {
fragment = getSupportFragmentManager().findFragmentByTag(getFragmentTag());
}
if (fragment == null) {
fragment = onCreatePane();
fragment.setArguments(intentToFragmentArguments(getIntent()));
}
trans.add(R.id.root_container, fragment, getFragmentTag());
trans.commit();
}
So when I create the activity and savedInstance is null I create the Fragment, I set it's arguments, I begin the transaction and add my fragment to the transaction with it's own tag (to get it back later).
The user interact with the activity and change the orientation. The activity is destroyed and recreated (as normal activity lifelycle). So now it enter the else, the fragment is null and I do a fragment = getSupportFragmentManager().findFragmentByTag(getFragmentTag()); that returns the correct Fragment holded by the fragmentManager.
The problem is that this fragment hold a reference to the old Activity that has been destoyed so if I do a fragment.getActivity it returns null. How can I update the fragment reference to the acitivy to the new re-created Activity?
UPDATE: To be more precise I'm on the SearchActivity that call the onNewIntent when it get a new Search. So the actual interaction is this-> user do a search -> search is displayed correctly -> user change orientation, result is displayed correctly (if user interact with results they are fine) -> user do a new search from the search button and this call the SearchActivity's onNewIntent that dispatch the new intent to the fragment that has the search logic. Here it crashes because the reference to the activity is null
When and where are you calling getActivity()? The activity reference does get updated automatically, but not immediately. You should be safe to access it after onActivityCreated() was called.
just remove null check from else part if ( fragment == null ) { fragment = getSupportFragmentManager( ...... let update fragment with new one created on orientation change ......
If setRetainInstance(true) -- yes, it's the solution (to find fragment by tag, because instantiate it again -- is the wrong way -- there could be background routines in progress). Otherwise, if you have setRetainInstance(false) the problem can be back.
I had the similar one. I my case -- because I used Loader (in background). Solution was simple: to destroy fragment's loaders in onDestroy() method of the fragment.
In your baseAcvivity you can override onSaveInstanceStat to resolve this problem :
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//solution of fragment.getActivity() is null
outState.remove("android:support:fragments");
}