I am new to the world of Android Programming,Here is my question.
Suppose I've an Activity named A and a Fragment named F. I know that the interaction between Activity and Fragment should be done through an Interface. I used to set the Interface in the onAttach() of Fragment like this
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mListener = (MyListenerInterface) activity;
}
and now am heard about the Static Factory Method from here.
My question is : Which is the best approach to init. a listener ? onAttach() method or initialize the listener through the static factory method ,like this?.
public static MyFragment newInstance(MyListenerInterface mListener) {
MyFragment f = new MyFragment();
this.mListener = mListener;
...........
return f;
}
I think, it is better to initialize the listener through the static factory method instead of casting from the activity,so we could avoid a null pointer exception.
Yes you do not need to cast anything via factory, but onAttach is better in my opinion because you have less chance of leaking an activity context. Let's say you make an instance with the factory and never use that fragment, it will leak the context of the Activity and there by everything in it. Also don't forget to destroy the interface in the onDetach.
Also you can have many instances of that fragment and with option one, they will all have the same listener, not good.
Also you should make what you could call a BaseActivity, an abstract activity all other extend from and define the interface methods there and you will avoid always casting to a lot of different classes. This will also come in handy if you need to quickly change something in every activity of your app.
First option (Initializing the listener in the OnAttach()) is a better one because
In first option the MyListenerInterface is an non-static variable, so each fragment has its own listener.
Whereas the second option's MyListenerInterface variable is an static that is reference maintained at the class level and common for all the other fragment instances this causes the problem when you need the same fragment in different activity then the listener of one activity will be overrided with another activity.
Related
The only thing I could find that seemed to be relevant was "onAttachFragment". But when I added debug messages, the order was like this.
onAttachFragment()
end of activity's onCreate()
beginning of the fragment's onAttach()
So, onAttachFragment was called before onAttach. What if I need to do something in the activity after the onAttach has been called for the fragment? This is because the fragment's dependency is injected in onAttach, and I need to call a method of the fragment in the activity, after the fragment's dependency has been injected.
PS: The example I saw was calling AndroidSupportInjection.inject(this) in onAttach() of a fragment, so I followed it. But, perhaps I could call that in onCreate() of the fragment?
There's no way to do that with lifecycle methods apart from using onAttachFragment (I'd say use onAttachFragment but that doesn't work for you) , what you can do is simply devise an interface communication between fragment and activity. Create an interface in your fragment:
interface OnFinishAttachCallback{
void finishedAttached();
}
Create a global variable :
OnFinishAttachCallback callback;
Override (you're already doing this) onAttach:
#Override
public void onAttach(Context context) {
super.onAttach(context);
callback = (OnFinishAttachCallback) context;
}
Make your activity implement the interface and simply call callback.finishedAttached() when you want to indicate to your activity that your fragment is ready.
As documentation we must cast Activity to Interface in onAttach() to communicate between Fragment-to-Fragment.
OnHeadlineSelectedListener mCallback = (OnHeadlineSelectedListener) activity;
After this we can implement that interface in Activity class and use it's methods.
But, i want to know that, as that interface is implemented by Activity class.
Then, why don't we instantiate it in Fragment onAttach() like below:
OnHeadlineSelectedListener mCallback = new ActivityClass();// After this all methods are also available in fragment class.
Using this way we can also pass the data by using Interface methods. But, why don't we use this?
Thanks.
You cannot create a new instance of an Android component (Activity, Service, BroadcastReceiver, Provider) using the new keyword. Only the Android framework can create these components, because they need to have their Context set up by the Android framework during construction. Although the compiler will let you do this, and your code will run, at some point you will get crashes because the methods in these components always assume that they have a valid Context.
I have noticed that I can create a callback by using two methods:
Receive an interface at the constructor of the class implementing the callback.
Receive the activity itself at the constructor of the class implementing the callback.
First Approach
For example I could do this:
public MyClass(MyInterface listener) {
this.listener = listener;
}
And I could call myCallBackFunction() defined in MyActivity (which implements MyInterface) by writing listener.myCallBackFunction()
Second Approach
Or I could do this:
public MyClass(MyActivity activity) {
this.activity = activity;
}
And I could call myCallBackFunction() defined in MyActivity by writing activity.myCallBackFunction()
My concern: Is one approach better than the other? And if so, why?
Usually speaking, you'd better use first approach. The reason is here:
Suppose you have 4 classes, first is Vehicle, second is Bicycle, third is Bus and third is Subway. Bicycle, Bus and Subway are subclasses of Vehicle. There may be a method call drive(), which should have a parameter. Which one do you think best for parameter type? Bicycle, Bus, Subway, or Vehicle?
Apparently, passing Vehicle is best because you may want to add other kinds of vehicles in the future or you don't want to write nearly same code for different kinds of vehicles in your project. It is same to use Interface rather than specific class.
As a result, passing an interface to a method is always correct and better than passing a specific type of object to it. You can always implement the interface in other classes and they will also be parameter of that method. You don't need to think about actual type of the parameter, which will confuse you and make you think more about specific code for specific type. Instead, only one type, one piece of code macroscopically.
So the conclusion is: using MyActivity is good, but using MyInterface is better.
I think it can depend on what you're trying to achieve: the first approach may in general be better suited since MyClass is not required to know anything about the implementation of that interface method, so it's great for passing different objects (e.g. a RecyclerView Adapter being created with an OnItemClickedListener injected in the constructor can be re-used in different activities/fragments implementing the interface, whilst the adapter doesn't need to change). It helps to prevent coupling.
The second approach leaves one wondering: is MyClass tied to the activity lifecycle? It may still hold a reference to the activity after that activity has actually been destroyed by the system, which would leak memory as the Activity object is not garbage-collected. It's a matter of design, and can be seen as code smell, can you not achieve what you wanted within the activity itself, and rely on the lifecycle callbacks onCreate/.../onDestroy?
Is one approach better than the other? And if so, why?
Using Interface is the best way..
Assume that you are having
1) Activity MyActivity
2) class which extends Activity or View or Asynctask is Myclass.
Both MyActivity and Myclass are Implements MyInterface
If you are passing Activity you need to add one more constructor
public MyClass(MyActivity activity) {
this.activity = activity;
}
public MyClass(Myclass myclass) {
this.myclass= myclass;
}
If you are using interface
public MyClass(MyInterface listener) {
this.listener = listener;
}
that's it.
In one approach you are creating an instance of Interface and in another an instance of implementing activity. what is best is:
Interface interface;
public myClass(Activity acitivity)
{
interface = (Interface)activity;
}
i.e. typecast activity to interface. Now you can callback the overridden functions in Activity.
This way you can now loose information of Activity's functions and just access the overriden functions of interface from the activity.
You can avoid typecasting and create an object of Activity, if you need access to interface callbacks AND the activity's function/variables.
It depends on your needs.
I wonder what way to call for parent's(Activity) function is the proper way to go, I have a activity which starts a fragment, from this fragment I want to call aFunction() in MyActivity.
is:
((MyActivity) getActivity()).aFunction();
or simply create an interface:
public class aFragment extends Fragment {
OnExampleListener mCallback;
// MyActivity must implement this interface
public interface OnExampleListener{
public void aFunction();
}
}
the best way to go about doing this?
It's not per se wrong, but it's discouraged as it makes your fragment dependent of the activity, which isn't the case if you're using interfaces. Use it for testing purposes, if you're serious about writing apps, use an interface.
Read the section about Fragment to Activity communication here to use interfaces: http://developer.android.com/training/basics/fragments/communicating.html
I have a Fragment, which should execute a (public) Method reset() from the Activity in the Fragment it is called from.
I found, for example, this page:
Calling Activity methods from Fragment
The other way there's no problem:
Input_tap Input_tap = (Input_tap) getFragmentManager().findFragmentById(R.id.input);
Input_tap.reset();
Does someone has any idea how to do it the other way?
and: Does the Method has to be public - its a "void" Method?
A Fragment can call getActivity() to retrieve the activity that is hosting it.
If there is only one possible activity that can host the fragment, just cast the Activity to the proper class (e.g., MyActivity) and call a method on it:
((MyActivity)getActivity()).someMethod();
If there might be more than one activity that can host the fragment, you are best served by implementing a common interface on all those activities, so you can cast getActivity()'s result to that interface:
((MyInterface)getActivity()).someMethod();