This question already has answers here:
Call an activity method from a fragment
(18 answers)
Closed 9 years ago.
I am trying to call a method in an activty from a Fragment screen.
I have a method called myMethod() which is in an activity called MyActivity;
I have a fragment called Screen1Fragment.
I would like to call MyActivity.myMethod() from inside the Screen1Fragment but I am not sure how to do this.
Previously the Screen1Fragment was an activity and so I was extending MyActivity so that I could directly call
myMethod().
But I have had to change the activity to a fragment for sliding tabs usage.
Thanks in advance.
Use getActivity() in your fragment.
MyActivity activity = (MyActivity) getActivity();
activity.myMethod();
if you are not sure if your fragment is attached to MyActivity then
Activity activity = getActivity();
if(activity instanceof MyActivity){
MyActivity myactivity = (MyActivity) activity;
myactivity.myMethod();
}
You should make your fragment totally independant of the activity you are attaching it to. The point of Fragments is that you can re-use them in different contexts with different activities. To achieve that and still being able to call methods from your Activity the following pattern in recommended in the official documentation.
In your fragment:
define a public interface with the method
public interface MyFragmentCallback{
public void theMethod();
}
define a field and get a cast reference:
private MyFragmentCallback callback;
public void onAttach(Activity activity){
callback = (MyFragmentCallback) activity
super.onAttach(activity);
}
In your Activity
implement MyFragmentCallback in the class definition.
implement theMethod() in your activity (Eclipse will ask you to do so)
Then, from your fragment, you can call callBack.theMethod()
The difference between this and simply calling your method on getActivity() is that your fragment is not paired with this specific activity anymore. So you may re-use it with other activity for example one for phones and the other for tablets.
If the method is the static method of MainActivity, something like:
public static void someMethod(){}
Then, it is pretty straightforward. Just call
MainActivity.someMethod()
However, I guess what you really want is to access some function from the Activity class. Then you can use the following code in the Fragment view creater
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
container.getContext().someMethod();
}
Related
The this.getActivity() is NULL in my fragment, and is called from the actual activity itself. This doesnt always happens but how can I fix this?
sportButton.setBackgroundColor(ViewHelper.getColor(this.getActivity()));
EventActivity.java
eventsFragment.setUpEvents(getEventApplication());
EventsFragment.java
public void setUpEvents(Application application) {
sportButton.setBackgroundColor(ViewHelper.getColor(this.getActivity()));
just remove this from this.getActivity() and if you extends your
Activity from AppCompatActivity then you have to cast it with same
like below
(AppCompatActivity) getActivity()
If its fragment which runs inside a parent activity then in that case you can create a static Activity object in EventActivity and reference that in fragments instead of getActivity(), because its guaranteed to be available to the fragments.
EventActivity.class
protected Activity activity;
onResume()
{
activity = this;
}
EventsFragment.class
sportButton.setBackgroundColor(ViewHelper.getColor(EventActivity.activity));
hope it helps
I have a main fragment with a viewpager inside it. This viewpager has 2 pages (list fragments). When I start the activty, the main fragment is shown and I also show the first paged fragment. This paged fragment displays data from a db using AsyncTask.
In the main fragment I have:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
onPageSelected(0);
}
#Override
public void onPageSelected(int position) {
Fragment fragment = (Fragment) pagerAdapter.instantiateItem(viewPager, position);
if (fragment instanceof IPagedFragment) {
((IPagedFragment) fragment).onShown(getActivity());
}
}
And the interface is:
public interface IPagedFragment {
void onShown(FragmentActivity activity);
}
The first issue I have is that I have to pass the activity as a parameter because when onShown gets called, the activity is still null.
Furthermore, the paged fragments use progressbar logic similar to the LoginActivity sample. I also get the following exception:
IllegalStateException: Fragment PagedFragment1{4201f758} not attached to Activity
at android.support.v4.app.Fragment.getResources(Fragment.java:620)
So what is the correct stage to start retrieving data from db once the paged fragment is fully available to the UI?
Issues like yours is the reason some developers are starting to question if fragments are really that good or useful.
Also "the correct" is debatable as you can do it in a variety of places and different developers will give you different answers, But let me try to supply you some useful info.
The attach/detach callbacks:
public void onAttach(Activity activity);
public void onDetach();
between those two methods any call to getActivity() will return the non-null activity the fragments is connected to. You can override them and use a private boolean isAttached to keep track of that call.
Also useful is the:
public void onActivityCreated (Bundle savedInstanceState)
this method is called AFTER the Activity.onCreate method. That is very important if you rely on some initialisation that happened there.
Also it's important to remember that on the moment the fragment transaction happens, the Fragment.onCreate happens after the Activity.onCreate and during rotation it happens before it.
As a general rule of thumb I use the Fragment.onStart() / Fragment.onStop() for getting/listening to data. On those calls, all the UI have been created, the fragment is attached to the activity and those callbacks don't get called if there's a dialog/popup (pause/resume does)
From the documentation:
public void onActivityCreated (Bundle savedInstanceState)
[...] tells the fragment when it is fully associated with the new activity instance.
source: http://developer.android.com/reference/android/app/Fragment.html#onActivityCreated(android.os.Bundle)
To get the reference of your activity, create a local object of fragmentActivity and get your activity reference as shown below.
private FragmentActivity fragmentActivity;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
fragmentActivity=activity;
}
I am trying to find a callback for my FragmentActivity that happens 'after' all of the fragments have called 'onCreateView'.
The reason for this is that my Fragment implement my interface:
public interface LifeCycleFragment {
public void onResumeFragment();
}
and when i call the fragment from MyActivity:
class MyActivity extends Activity
onCreate()
fragment.onResumeFragment()
getActivity() ends up being null:
class MyFragment extends Fragment implements LifeCycleFragment
#Override
public void onResumeFragment() {
Log.e(TAG, "- ON RESUME -");
FragmentActivity activity = getActivity();
// *****ACTIVITY IS NULL HERE AND THAT'S A PROBLEM ***//
I am not sure how to tackle this problem and any help would be appreciated.
Place getActivity() in override onActivityCreated method, and save it in the class for onResumeFragment(). I hope the Activity is still kept the same during onPause().
Would you like sample code to communicate between Fragment and Activity? I posted an answer in SO about it # Passing data between fragments contained in an activity. The respective Google webpage is # Communicating with Other Fragments.
Good luck and have fun...
I'm writing an app that has a parent Activity and several child Fragments. I am trying to get the Fragment to communicate back to the parent Activity. I know there are several ways to do this, including making an interface and implementing that in the parent Activity. However, I am interested in this method:
ParentActivity activity = (ParentActivity) getActivity();
activity.someMethod();
This approach takes less code and is less complex. However, is this cast safe to do in production code? Or is an interface safer?
You can use this -
private ParentActivity callback;
#Override
public void onAttach(Activity activity)
{
//callback = (ParentActivity ) activity;
// make sure there is no cast exception
callback = (ParentActivty.class.isAssignableFrom(activity
.getClass())) ? (ParentActivity) activity : null;
super.onAttach(activity);
}
#Override
public void onDetach()
{
callback = null;
super.onDetach();
}
now when you do any method call , call it like this -
if(callback!=null)
{
callback.someMethod();
}
this method is safe .
It is safe (i.e. you won't get a ClassCastException), as long as you make sure that only ParentActivity ever creates/adds your Fragment.
These classes are now effectively coupled, which is, in general, not a good thing.
By casting to a specific Activity class (ParentActivity), you are losing the ability to re-use the fragment with different activities. It's safe to cast, as long as you only use the fragment with that one activity.
Using an interface allows the fragment to be used with multiple activities - you just need to implement the interface in the activities that use the fragment.
Another option is to use an Event Bus - like GreenRobot's EventBus or Square's Otto
Directly from the Android documentation:
To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity. The Fragment captures the interface implementation during its onAttach() lifecycle method and can then call the Interface methods in order to communicate with the Activity.
Here is an example of Fragment to Activity communication:
// HeadlinesFragment.java
public class HeadlinesFragment extends ListFragment {
OnHeadlineSelectedListener mCallback;
public void setOnHeadlineSelectedListener(Activity activity) {
mCallback = activity;
}
// Container Activity must implement this interface
public interface OnHeadlineSelectedListener {
public void onArticleSelected(int position);
}
// ...
}
// MainActivity.java
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
// ...
#Override
public void onAttachFragment(Fragment fragment) {
if (fragment instanceof HeadlinesFragment) {
HeadlinesFragment headlinesFragment = (HeadlinesFragment) fragment;
headlinesFragment.setOnHeadlineSelectedListener(this);
}
}
}
It is safe if you know that the fragment won't be used in another activity. You can also do checks with instanceof so you can be sure that it will be the right type.
There are some possibilities where getActivity() might return null (when the fragment is not attached) so it's a good habit to check if the activity is null, or even better: myFragment.isAdded(). Otherwise you would get a NullPointerException when calling activity.someMethod().
So the safe code would be:
if (isAdded() && getActivity() instanceof ParentActivity){
ParentActivity activity = (ParentActivity) getActivity();
activity.someMethod();
}
Of course there are some other approaches, like passing listeners to the fragments or using a shared eventbus like Guava or Otto, which also have their pros and cons. The easiest way is the one described above, and if you use it carefully (check against null, correct class) it will work as expected.
I guess ParentActivity is derived from Activity.
getActivity() will provide you a pointer to the parent activity. So, there's no problem in the cast.
It is not "the Android way" to do things, but anyway, neither Google does lots of thing "the Android way" and this cast will surely continue to work ok in future Android versions.
As you said yourself, this not a good approach, google own documentation recommends using the interface, but if you choose to use this approach try something like:
Activity mActivity;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mActivity = activity;
}
to avoid the type NullPointerException error
if(this.mActivity != null){
this.mActivity.someMethod();
}
Sorry if this been asked before but I couldn't find an answer to my specific case. Also sorry that I'm new and a little stupid.
Problem:
I'm showing a dialog from a fragment and passing along a context in my constructor method because I need a context in my dialog to register for broadcastrecievers etc.
DialogFragment fragmentDialog = MyDialog.myConstructor(getActivity());
fragmentDialog.show(getFragmentManager(), "dialog");
Then in MyDialog class I store the context in a instance variable.
The problem arises when rotating the device and I get a nullPointerException when I try to use the context again in the dialog.
Can this be solved in some easy way?
If the device is rotated the Activity will be destroyed and recreated. So the Context you passed to your Fragment points on the Activity which was destroyed.
You could use setRetainInstance(true) in your Fragment. This way your Fragment will survive the recreation of the Activity.
To solve the NPE you have to pass the Context to the Fragment, if the Activity is recreated. Then the Context belongs to the new Activity.
In fact, without this update every line of code which points on the Activity like getActivity() or getFragmentManager() will lead in a NPE.
You get the NullPointerException because activites are destroyed and recreated when rotating the screen.
The SO post below gives more info...
https://stackoverflow.com/a/1673374/
Please be careful with the order of events if you rotate a FragmentActivity, because this can also be a source of NullPointerExceptions.
This is not documentated:
When the FragmentActivity is created the first time,
public class MyActivity extends FragmentActivity implements
MyFragment.OnFragmentInteractionListener {
private int var1;
private int var2;
#Override
protected void onCreate(Bundle savedInstanceState) {
//before
var1 = 3;
super.onCreate(Bundle savedInstanceState)
//after
var2 = 5;
}
//Interface Methods
public int getVar1() { return var1; }
public int getVar2() { return var2; }
}
both of the [before] and [after] code will be run before the fragments are attached and created. So, if you get the vars in the onCreate() call of the Fragment you get both vars. But when you rotate your device, the Activity is recreated from the savedInstanceState in the super call. Now, the fragments are reattached and created anew in this call! That means, this time the Methods of the Listener Interface are called before your [after] code. So, if you pass the Context of the activity to the fragment and get Information through the Interface like it is shown in: https://developer.android.com/training/basics/fragments/communicating.html
you get a NullPointerException for var2 because the interface methods are called from the fragments onCreate() onAttach() ... functions before the [after] code in the Activity's onCreate() is executed! So, take care that you set your Information the InterfaceFunctions are accessing before the super call.
Depending on what you're doing in your initialization you could consider creating a new class that extends Application and moving your initialization code into an overwridden onCreate method within that class.
public class MyApplicationClass extends Application {
#Override
public void onCreate() {
super.onCreate();
// TODO Put your application initialization code here.
}
}
And you are not stupid, even experts need help from time to time.