I have been reading very much about the nested Fragments onActivityResult issues.
I got the next conclusions.
1) At the Fragment, should call this.startActivityForResult() instead of this.getActivity.startActivityForResult()
2) Overwriting onActivityResult() at the parent Activity calling super.onActivityResult() to propagate the response through fragments.
Until here, the normal way to configure onActivityResult in Fragments.
But I use one implementation of nested fragments. Then I should do some more steps.
3) Here we can see the full process.
First, all my fragments are in root level, doesn't exist another fragment levels.
Then, to try solved the problem, I extend this fix Activity in the main Activity.
CommonActivity
Here, only one difference, I've replaced ActionBarActivity by FragmentActivity.
4)Finally, in the result ListActivity I have the next test code.
Intent output = new Intent();
output.putExtra("pos", position);
this.setResult(Activity.RESULT_OK, output);
this.finish();
THE QUESTION, debbuging, I can see when this.startActivityForResult() is called from Fragment, CommonActivity.startActivityFromFragment(..) is working. But, when response is throw from result ListActivity CommonActivity.onActivityResult(..) never is called.
Why?, Where can be the problem?
When called startActivityForResult, results always go to the same Activity from where was called or to Activity the Fragment was attached to(your case), so you can try Override onAttach (Activity activity) - function of Fragment, and see to which Activity was attached the Fragment.
Or other way to call startActivityForResult as public function of CommonActivity, so results always will go to CommonActivity.onActivityResult. Good Luck with that!
Related
Has a MainActvity,the fragment is inside. The Fragment startActivityForResult to another Activity,and get data setResult() to the Fragment. The Mainctivity's launchMode is defult.
But,the Fragment's Method onActivityForResult() is not implement.
Make sure to call super.onActivityResult in your MainActivity if you override onActivityResult
That's the most common mistake but there are more cases which are covered here
I create an application as below:
Main activity includes FragmentTabHost which includes two ContainerFragments which include two Fragments separately.
Now I startActivityForResult from UserFragment, but onActivityResult in UserFragment cannot be called! What's wrong? How to resolve?
The project in https://github.com/VictorS-Zhao/TabHostAndNestedFragment.
Thanks in advance!
Supplement:
This is a strange behavior, the 1st nested fragment Community Fragment's onActivityResult can be called every time, but the 2nd nested fragment User Fragment's cannot be called. When startActivityForResult from UserFragment, but the onActivityResult in CommunityFragment is called.
Solution:
Finally I found solution in onActivityResult() not called in new nested fragment API
According to this answer, should override onActivityResult in ContainerFragment, and use getParentFragment().startActivityForResult in UserFragment. That's nice!
Provided that the UserFragment is your child fragment (a child of ContainerFragment), onActivityResult method does not execute once you return from your activity which has been started with
startActivityForResult.
It was a bug in the support library, I came over similar situation a while ago and it still was not fixed. Honestly, I am not sure whether it is fixed at the moment, you have to find out.
Here is a solution describing how to handle that:
http://inthecheesefactory.com/blog/how-to-fix-nested-fragment-onactivityresult-issue/en
https://gist.github.com/artem-zinnatullin/6916740
Basically the easiest way to make onActivityResult method executed in the child fragment is to start the activity from Activity level getActivity().startActivityForResult() or Parent Fragment getParentFragment().startActivityForResult() and notifying manually every fragment belonging to the calling Activity about invoked Activity's result.
Alternatively you can use some open source:
https://github.com/nuuneoi/StatedFragment
Hope that helps somehow.
Response to the Supplement:
Just as stated above, BaseContainerFragments belong to MainActivity, for those fragments onActivityResult method is called normally.
The problem begins when a child fragment is added to a parent fragment. For the child fragments onActivityResult is not called and you have to handle it manually in the Activity or the ParentFragment.
See :
onActivityResult() not called in new nested fragment API
onActivityResult is not being called in Fragment
I've found a lot of questions about that, but none of these can help me.
I have a "MainActivity" which have 4 fragments.
I need to access to one of these fragments, called "my_fragment", in an other simple activity, let's call "SecondActivity".
So, I try to put a property android:tag="my_fragment" in the LinearLayout markup XML of "my_fragment".
And after that, I do that in "SecondActivity":
Fragment frg = getFragmentManager().findFragmentByTag("my_fragment");
... in order to get my fragment. But frg is always null.
I try a lot of others ways, but in vain. This one seems better and easier to do, but perhaps I'm wrong.
Any help would be appreciate. Thank you in advance.
Fabien
EDIT
Since your answers that indicate that's isn't possible, I want to specify what I need.
I just want to get this fragment for reload it. I found something like that on an other subject on Stackoverflow:
frg= getFragmentManager().findFragmentByTag(my_fragment);
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(frg);
ft.attach(frg);
ft.commit();
By the way, I just try to get the fragment in the fragment himself and it's still return null. With the method :
findFragmentById(R.layout.my_fragment)
it's the same result.
And after, I did :
findFragmentById(this.getId())
But it's make an infinite looper, I don't understand the reason...
EDIT2
Alright, let’s give some details :
I have MainActivity with ViewPager with 4 fragments. It’s not fragments at the xml sense. Sorry if I’m confused, I was training to Android very recently and somethings are not clear for me again. So, before yesterday and the read of #Bruce edit, I was thinking that fragments were the components of a ViewPager. So, #Bruce, this is why I can’t use your solution. I was trying to use findFragmentByTag with the tag applicate on my principal LinearLayout markup of my fragment - that is not, I repeat, an xml markup fragment.
This is my approach :
In my MainActivity, I click on the third fragment. I make a research for find some points around me. After an action of the user, still from the third fragment, I open the SecondActivity for authentification and on the user connection, I close this SecondActivity. Now, I need to reload the fourth fragment that will adapt his components in terms of the user situation, while keeping the same state on the third fragment, with points loaded. It’s why can’t use your solution #menion.asamm : I can’t reinstantiate the MainActivity, even if I simulate a click on the third fragment because it will come back in his initial state, without points loaded.
Thank you both of you #Bruce and #menion.asamm for your time in helping me !
Fragments are always owned by one activity, so you cannot directly access a different activity's fragments. The call you are making is looking for fragments within your SecondActivity.
Why do you want to do this? Once some UI is off screen (MainActivity), you usually don't want to do anything with those UI objects, because Android may have removed them from memory. If there is data in "my_fragment" that is needed by SecondActivity, one approach might be to save the data in SharedPreferences or a database in my_fragment, and then load it in SecondActivity.
EDIT
I'm not sure you're getting that it is important which activity you are running in. Here are two options for how to proceed:
If you just want to run the SAME instance of your fragment that was already running inside MainActivity, then maybe what you want to do is finish your SecondActivity to return to MainActivity.
If you want a NEW copy of the same fragment inside SecondActivity, then you can include the fragment inside SecondActivity's layout (or add it to some container later).
Also, notice that for your call to findFragmentById, the ID needs to be the ID that was specified in the layout file as the value of android:id (not the R.layout.my_fragment). It might be better to use a fragment tag, which you can either specify in your layout file or when you add the fragment.
Mainly I think you need to read Google's guide on fragments.
EDIT2:
Ah, I see, I have a similar fragment-refresh situation in my app. You basically need to get data from SecondActivity back to the fragment inside MainActivity. The approach I use is this:
Save the data from SecondActivity in storage (DB or SharedPreferences).
Finish SecondActivity so that MainActivity and your fragment are shown again.
Override onResume in your fragment to fetch the data you saved in SecondActivity.
Another option is to launch SecondActivity using startActivityForResult, and then process the results in MainActivity, passing them to its fragment.
Regarding how to find the fragment by tag, you first need to set the fragment's tag. If you are declaring your fragment in a layout XML, then you can do it there (and you can also declare
<fragment class="com.xyz.MyFragment"
android:tag="MyFragment"
android:id="#+id/my_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Now from inside MainActivity you can either do findFragmentById(R.id.my_fragment) or findFragmentByTag("MyFragment").
If you are NOT declaring the fragment in XML, but adding it directly, you can set the fragment's tag as part of the add call:
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.frag_parent, new MyFragment(), tag);
EDIT3: Ah, you're using ViewPager to hold fragments. Now I understand better. They're still fragments, but getting access to them is indeed tricky, because Android constructs a fragment tag in some internal code. Here is another SO question on this issue:
Retrieve a Fragment from a ViewPager
Hmm if you really need just refresh of fragment attached to different activity, I suggest:
first activity start second activity with
startActivityForResult(intent, MY_CODE);
second activity when wants to refresh fragment in first activity, finish it's state with
Intent data = new Intent();
data.putExtra("REFRESH_FRAGMENT", true);
setResult(RESULT_OK, data);
finish();
back in first activity, you may catch this result by
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// check request code
if (requestCode == MY_CODE) {
// check result
if (resultCode == RESULT_OK) {
// check data
if (data != null && data.getBooleanExtra("REFRESH_FRAGMENT", false)) {
refreshFragment();
}
}
}
}
Possible?
I have been asked an interview question: Can a fragment exist without activity? I searched for answers but didn't get a proper answer and explanation. Can someone help?
Yes, you can do this anywhere:
new YourFragment();
As fragments must have a parameter-less constructor.
However its lifecycle doesn't kick in until it is attached. So onAttach, onCreate, onCreateView, etc. are only called when it is attached. So most fragments do nothing until they are attached.
It can exist as an object in memory (by creating it with new), but it needs to be attached to an Activity in order to appear on the screen, assuming it has any UI (fragments don't have to have UI).
A Fragment can exist independently, but in order to display it, you need the help of an Activity. The Activity will act like a container for the Fragment(s).
A fragment is not required to be a part of the Activity layout; you may also use a fragment without its own UI as an invisible worker for the Activity but it needs to be attached to an Activity in order to appear on the screen.
As soon as you create an instance of the Fragment class, it exists, but in order for it to appear on the UI, you must attach that fragment to an activity because a fragment's lifecycle runs parallel to an activity's lifecycle. Without any call to Activity's onCreate(), there will be no call for onAttach(), onCreate(), onCreateView() and onActivityCreated() of fragment and so it can't be started.
I read above top rated answer , i am not disagreeing but android already provides to make independent fragment without activity DialogFragment , which extends fragment . if you want show in full screen first extends DialogFragment then
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setStyle(STYLE_NO_FRAME, android.R.style.Theme_Holo_Light);
}
Android app must have an Activity or FragmentActivity that handles the fragment.
Fragment can't be initiated without Activity or FragmentActivity.
I have the following arrangement: CatActivity -> FragA -> FragB; where, FragA launches FragB using fragB.show(getChildFragmentManager(), "FragB”);.
FragB launches the gallery intent with
Intent img = new Intent(Intent.ACTION_GET_CONTENT);
img.setType("image/*");
startActivityForResult(Intent.createChooser(img, “Choose Photo”),PHOTO_REQUEST_CODE);
The problem is that the FragB’s onActivityResult is never reached. Does anyone know why?
FYI: neither CatActivity nor FragA implements its respective onActivityResult method.
as far as my experience goes I've come to terms with the fact that onActivityResult is a complete mess.
For your particular situation I believe you should call startActivityForResult from fragA via getParent method in FragB. Then get the result in FragA and pass it onto the child fragment using getChildFragmentManager().getFragments().
I have followed this pattern for a FragmentTabHost where the individual tabs are child Fragments. There doesn't seem to be any default code to pass the activity result onto child fragments.