I have one activity, with many fragments on it.
Since I sometimes need the activity (for example to get getFragmentManager, etc.), I call the activty's singleton instance from fragment.
It means :
in my activity there's a static variable called instance.
However, sometimes I get crashes in fragments because MyActivity.getInstance() is null.
1. How is it possible? Could it be because the activity is singleton?
2. the activity-as-singleton - could it lead to certain problems(like **memory leak** ?, etc..)
3. Can I count on getActivity always? I think sometimes that too returned null.
haven't come across such situation but rather than accessing resources like getFragmentManager() in fragment for fragment transaction, try Interface pattern and give callback to your activity and let activity handle all of this.
Related
i am trying to alter the activity content from fragment. for that i want to pass the activity handle inside fragment and do the required changes.
If i can do that why there is more difficult way of interface etc.
You can call getActivity() from the Fragment.
If you want to get your activity specifically you can cast it
((MyActivity) getActivity()).someMethod()
This will tightly couple your Fragment to your activity and prevent you using the fragment in a different activity easily so be careful.
Also you need to be careful with lifecycles and such as a fragment can become detached from an activity causing a NullPointerException from time to time. So it is recommended to wrap this in a null check
I'm trying to access a function in one Fragment (f1) from another Fragment (f2). It seems that i have to make my function in f1 public and static to be able to access it from f2.
I've read that it's not a good idea to access one Fragment from another, so i've tried to make f2 access my Activity, which then connects to the function in f1. Although, even doing it this way, i still have to make my function in f1 public and static.
I don't reuse the Fragments, i simply have them in a ViewPager for swiping back and forth through the Fragments.
At the moment i have a lot of static variables because i have to make my functions static to access them from other Fragments.
Am i going about this the wrong way? Is there a better way?
Thanks in advance.
You're going down a road of much pain unless you are very controlled about what you do.
First of all, sharing state through static methods and variables is a fairly awful way of doing things, and static members won't be able to access anything in the instance of the fragment. If you really think you need to use static methods, don't bother putting them in the fragment classes. They don't provide an advantage there. Put them in a common class that they all reference.
Second of all, if you're using a ViewPager with fragments, you can't be guaranteed that any given fragment's view hierarchy even exists at any moment in time. This is because ViewPager typically only keeps fragment views alive that are on the current page or on +/- 1 offset from the visible page. So if you need to tell a fragment at offset +2 from the current fragment, you won't be able to make visible changes to it.
Instead, the easiest thing to do is create an object that maintains whatever state you want to share between the fragments, and have them all make changes to that one object. If you need instant changes to other fragments, you can use something like an event bus to have those changes communicated to other active fragments.
What you're trying to do is in general fairly complex. Expect to spend a lot of time designing a correct solution, and be sure to learn how fragments and ViewPager works very well.
You got two questions
1. Am i going about this the wrong way?
Yes, its not recommended to have the methods & variables declared static just to make them used to access from outside of your class.
2. Is there a better way?
Yes, declare the methods as public (but not static) inside its fragments.
From the activity (which is hosting the fragments) get the reference to the fragments using FragmentManager classes methods findFragmentById() or findFragmentByTag() then call the methods.
Sample :
Fragment fragment =
fragmentManager.findFragmentByTag.findFragmentById
(R.id.fragment);
or
Fragment currentFragment =
fragmentManager.findFragmentByTag("fragmentTag");
If you really require both of your functions to be isolated, you can use Broadcasts. Just send a Broadcast from one fragment and have the Broadcast receiver in the other fragment.
For some reason my understanding was that a headless Fragment lives for the duration of your application. With this understanding, in my attempt to persist an object between startActivityForResult() I put the object in a Headless Fragment like this
private HeadlessFragment modelFragment;
modelFragment = (HeadlessFragment)
getSupportFragmentManager().findFragmentByTag(Constants.HEADLESS_FRAGMENT_TAG);
if (modelFragment == null){
modelFragment = new HeadlessFragment();
}
modelFragment.setInvoice(invoice);
I can confirm that the custom object was set, however when I go to the next activity and try to get the same object by calling findFragmentByTag with same tag the object is null.
Does a Headless Fragment survive between two Activities life cycle? I did set setRetainInstance(true) on that Headless Fragment. I was hoping that I will not have to implement Parceable on my custom object.
For some reason my understanding was that a headless Fragment lives for the duration of your application.
No. Fragments are owned by activities and are not application-wide constructs.
I can confirm that the custom object was set, however when I go to the next activity and try to get the same object by calling findFragmentByTag with same tag the object is null.
There are at least two reasons for this:
First, at least in the code that you are showing, you never add the fragment to the FragmentManager via a FragmentTransaction. As such, the activity that created the fragment will not be able to find the fragment via findFragmentByTag(), because the FragmentManager does not know about it.
Second, each activity has its own FragmentManager, and fragments from one activity are not accessible in another activity.
I was hoping that I will not have to implement Parceable on my custom object.
Then don't pass the object. Pass the information (e.g., a key or ID) by which the other activity can retrieve the object (from a singleton POJO cache, by querying the database, etc.).
Or, do not make them separate activities, but have them as separate (regular) fragments in one activity.
Or, implement Serializable, though Parcelable executes more quickly.
Lets say I will be using several fragments(Action1Fragment, Action2Fragment etc.) within an activity(ActionActivity). I want to access some elements of activity object, or call some methods of ActionActivity. It is generally offered to create a event callback . What if I keep a reference to ActionActivity within Action1Fragment instead of keeping a reference to CallBackInterface which is actually implemented by ActionActivity since I will be using these fragments only within a particular activity.
I am kinda confused by the idea that Activity might be dead while reference of interface might still be alive(it sounds ridiculous when I read it again but it is OK if I managed to explain myself).
The Android Developer tutorials recommend that you use a callback interface on your fragments. The activity that hosts the fragment must implement the callback interface. The fragment does getActivity() and casts it to the callback interface, and then makes the callback.
This is the recommended way to promote a more modular design. It would not matter if your fragments will only ever work inside one activity. But if you want to make more generic fragments that could be used by different activities, then the above design pattern starts to become useful. (For example: a telephones fragment inside an person fragment and a company fragment.)
Suppose you do it the other way: the fragment does getActivity() and casts it to PersonActivity. The fragment then has access to all the public methods of PersonActivity. But this design pattern becomes much more ugly when you need the other activity to also use the fragment. The fragment would then have to be changed to first try and cast to PersonActivity, and if that throws, try the CompanyActivity.
The recommended design pattern basically gives you a way to make an activity compatible with the fragment instead of vice versa. The fragment only knows about the callback interface and not about any of the activities itself. The activities do know about the fragment because they implement the callback interface but they already knew about it because they constructed and initialized an instance of it.
Does that make sense?
My launch activity starts up another activity whose launch is set to single instance. In this 2nd activity, I have a public method. I then start up a 3rd activity and that activity needs to access the public method in the 2nd activity. I don't want to use startActivity and pass it extras because I assume the onCreate will get called (or am I wrong?) and I need to avoid the 2nd activity from reinitializing itself.
When an activity is started using startActivity, is it possible to gain access to the underlying class instance itself and simply call the method?
I actually came up with a simple solution. As a matter of fact you can access the underlying class of an activity. First, you create a class that is used to hold a public static reference to activity 2. When activity 2 is created, in its onCreate method you store "this" in the static reference. Activity 2 implements an interface with the methods that you want available to any other activity or object. The static reference you hold would be of a data type of this interface. When another activity wants to call a method in this activity, it simply accesses the public static reference and calls the method. This is no hack but is intrinsic to how Java operates and is totally legitimate.
It is not a good idea.
As I can understand method from second activity is actually not connected to particular activity while you want to call it from another one. So carry the method out to other (non-activity) class (maybe static method) and use it from both activities.
It's not directly possible to gain access to activity object started using startActivity (without using some hacks). And frankly you shouldn't even trying to accomplish this.
One Activity component can cycle through several Activity java object while its alive. For example, when user rotates the screen, old object is discarded and new activity object is created. But this is still one Activity component.
From my experience, when you need to do things you described, there is something wrong with your architecture. You either should move part of activity's responsibilities to Service or to ContentProvider, or use Intents, etc. Its hard to recommend anything more specific without knowing more details.
No there is no way to pass a reference via startActivity() however you can use some sort of shared memory to keep reference to your Activity. This is probably a bad design. However passing an extra with your Intent will not cause onCreate, that is completely related to the lifecycle.