The main fragment activity in my application has the following function
private final void insertFragmentIntoView(final SherlockFragment fragment,
String tag) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_content, fragment, tag);
ft.commit();
}
The R.id.fragment_content is a frame layout and i basically insert a new fragment into this frame. Now the frame that i insert has a button that should take me onto a new screen. What i want is that all navaigation in my application should take place in my FragmentActivity. How can i call my FragmentActivity from with a child fragment ?
Kind Regards
Make a listener class in your fragment and your parent activity will implement that listener .
Now register listener in your fragment and call method in which you want to perform some action.
More you can see this link http://developer.android.com/training/basics/fragments/communicating.html
Example how fragment and activity communicate.
class MyFragment extends Fragment{
class interface MyFragmentListener {
doSomeAction();
}
MyFragmentListener myListener;
onAttach(){
myListener=(MainActivity )getActivity();
}
onButtonClick(){
myListener.doSomeAction();
}
}
class MainActivity extends FragmentActivity implements MyFragment.MyFragmentListener
{
doSomeAction(){
//TODO perform some action from your fragment to activity
}
}
Using listeners is the recommended way of communicating between Fragment and your activity.
See this Android documentation section for infromation. Long story short they just implement a listener interface by the Activity class and cast getActivity() result in a fragment to a listener.
From my personal experience this is very convenient because lets you to:
Easilly switch underlying activity (e.g. you host entire fragment in a wrapper activity for compatibility in pre-3.0 and host this fragment along with others in 11+)
Easilly control if the wrapper activity supports callbacks or not. Just check is it does implement the listener and do your app specific actions if it doesn't.
Related
Problem in short:
I have an MainActivity that holds BottomNavigationView and FrameLayout on top of it. BottomNavigationView has 5 tabs and when tab is clicked, I add some fragment on that FrameLayout. But, from some fragment, I need to open another fragment. From that another fragment, I need to open the other one. Every time when I need to show fragment, I notify MainActivity from fragment, that it needs to add the another one. Every fragment checks does its activity implement interface. And it is annoying. So, if I have 100 fragments, MainActivity implements too many interfaces. It leads to boilerplate code. So, how to properly navigate between fragments if you have a lot?
Problem in detail:
Please, read problem in short section first.
As I've said I have BottomNavigationView that has 5 tabs. Let's call the fragments that responsible for each tab as FragmentA, FragmentB, FragmentC, FragmentD, FragmentE. I really know, how to show these fragments when tab is clicked. I just replace/add these fragments in activity. But, wait, what if you wanna go from FragmentA to FragmentF? After that from FragmentF to FragmentG? This is how I handle this problem: from FragmentF or FragmentG I notify MainActivity that I wanna change the fragment. But how they communicate with MainActivity? For this, I have interfaces inside of each fragment. MainActivity implements those interfaces. And here is problem. MainActivity implements too many interfaces that leads to boilerplate code. So, what is the best way to navigate through Fragments? I don't even touch that I also need to handle back button presses :)
Here is how my code looks like:
MainActivity implementing interfaces to change fragments if necessary:
class MainActivity : AppCompatActivity(), DashboardFragment.OnFragmentInteractionListener,
PaymentFragment.BigCategoryChosenListener, PaymentSubcategoryFragment.ItemClickedListener, PayServiceFragment.OnPayServiceListener, ContactListFragment.ContactTapListener, P2PFragment.P2PNotifier
Here is my PaymentFragment's onAttach method for example:
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof BigCategoryChosenListener) {
listener = (BigCategoryChosenListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement BigCategoryChosenListener");
}
}
And using this listener I notify activity to change fragment. And in EACH fragment I should do so. I don't think that it is best practice. So, is it ok or there is a better way?
Ok What you need is something like this in activity where you would initialized on your BottomNavigationView.
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_1://Handle menu click -
//Call Navigator helper to replace Fragment to Fragment A
break;
case R.id.menu_2:
//Call Navigator helper to replace Fragment to Fragment B
break;
case R.id.menu_3:
//Call Navigator helper to replace Fragment to Fragment C
break;
}
return true;
}
});
I have one Activity Called A. The activity has 1 Frame Layout in which Fragments are used. I have two Fragments, Fragment1 and Fragment2. When the Activity is launched, Fragment 1 fills the Frame Layout.
Fragment1 also contains a button that when clicked replaces it with Fragment2 within that same Frame Layout. My question is this, when I click that Button in Fragment1 should I implement that code so that
A) Activity A gets notified of the onClick in the Fragment through an interface using some type of Boolean value and then proceeds to replace it with Fragment2.
OR
B)Implement the code that replaces Fragment1 with Fragment2 within Fragment1 itself For example:
private FragmentTransaction ft;
private Button registerButton, resetButton;
private Fragment fragment;
public LoginFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_login, container, false);
registerButton = (Button)view.findViewById(R.id.register_button);
resetButton = (Button) view.findViewById(R.id.reset_button);
registerButton.setOnClickListener(this);
resetButton.setOnClickListener(this);
return view;
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.register_button: {
fragment = new RegisterFragment();
ft = getFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(null);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();
break;
}
}
}
Could someone explain why one over the other? Thanks so much!
Generally, what I do is use an interface of some sort that lives in the fragment being replaced (in this case Fragment 1). Your parent activity then would implement this interface, and thus building a contract between the activities that are the parent of that particular fragment.
When you press your button (or whatever event happens to signal replace), you grab your activity casting it to that interface, and call the particular method.
e.g. Signaling event within the fragment
( (MyFragmentListener) getActivity()).onActionHappens();
Where MyFragmentListener is the inner class of your Fragment and onActionHappens() is the method that sends the signal. This effectively creates a contract between your fragment and any Activity that hosts the fragment. When your action happens, you let the activity know and the activity then overrides the appropriate method to handle the event.
There are other ways to do this, but at the simplest level this is how it can be done.
Why not option B
Option B creates a tight coupling between fragments, which you don't necessarily want. In practice you want the coupling to be between the fragment, and it's host (or parent) which is the Activity. Also, there could be many activities that use that fragment so you abstract away details about the particular activity that uses it by just calling getActivity(). In this case, coupling the fragment and the Activity is acceptable, since of course the two are coupled anyways. We know this because a fragment cannot live without an associated Activity, so it is okay to take advantage of the that tight coupling.
Summary
Pick option A. It is the cleanest route, and avoids assuming implementation details that you have to do in option B.
It is also the basic solution you have without any external libraries or details required. If you want a more advanced solution, checkout Otto (made by Square) Link to the library here
I'm trying to call this function public void arrowClick()
is inside my main fragment public class CounterMain extends Fragment implements View.OnClickListener{
the fragment is extend android.support.v4.app.Fragment
I want to call this function from another Custmoe Dialog fragment
public class CustmoeDialog extends DialogFragment {
I tried ((CounterMain)getActivity()).arrowClick();
but I can't use it it says android.support.v4.app.Fragment cannot be cast to my.example.CounterMain
and the
CounterMain x = new CounterMain(); x.arrowClick();
it makes my app to stop working when I call it
any help?
You can call activity method by this way
((YourActivityClassName)getActivity()).yourPublicMethod();
and from activity you can directly call by this way
FragmentManager fm = getSupportFragmentManager();//if added by xml
YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentById(R.id.your_fragment_id);
fragment.yourPublicMethod();
if you added fragment via code and used a tag string when you added your fragment, use findFragmentByTag instead:
YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentByTag("yourTag");
First of all, you can not cast from ACTIVITY to FRAGMENT
But to cast from GLOBAL ACTIVITY to your ACTIVITY
Or create INTERFACE and implement it in ACTIVITY
Then cast it in FRAGMENT from ACTIVITY to INTERFACE
And on the question:
See here the right way how to implement
Basic communication between two fragments
I have a tabbed view which I have implemented using Action Bar tabs, now there are one or two pages which navigate away from this tab view. At some point of time I want to call one of the fragments in the foreground again. But I am not finding any example of how to do this.
Class Definition(Fragment1_2):
public class Fragment1_2 extends Fragment {
Class Definition(AdhocEdit.class):
public class AdhocEdit extends Activity{
Activity to Fragment Intent so far:
Fragment1_2 fragmentB = (Fragment1_2)getFragmentManager().findFragmentById(R.id.fragemnt1_2);
/* Intent mainIntent;
mainIntent = new Intent(AdhocEdit.this,Fragment1_2.class);
AdhocEdit.this.startActivity(mainIntent);
AdhocEdit.this.finish(); */
// startActivity(new Intent(AdhocEdit.this, Fragment1_2.class));
Commented because none of them works. Also do I need to add this Fragment1_2 into the Manifest, if so how?
You can't start a fragment like you do for activity.
Fragment is hosted by a activity. You need to add the fragment to the container.
Example from docs
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
fragment_container is the id of the container which is usually a FrameLayout and you add the desired fragment the container
More info #
http://developer.android.com/guide/components/fragments.html
I would like to add a FragmentActivity in the activity layout. In order to make fragment transactions (such as add, remove, or replace a fragment), the api guides say that I first need to get an instance of FragmentTransaction from your Activity and then add a fragment using the add() method specifying the fragment to add and the view in which to insert it. Ok pretty straightforward so far, but what should I do in the FragmentActivity case?
AllEventsFragments events;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if ( savedInstanceState == null )
{
events = new AllEventsFragments();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.content_frame, events,"events");
// Commit the transaction
transaction.commit();
}
}
in which AllEventsFragments is defined as follows:
public class AllEventsFragments extends FragmentActivity implements ActionBar.TabListener
{
...
}
Since the add method accepts a Fragment as second argument the error returned is:
The method add(int, Fragment, String) in the type FragmentTransaction is not applicable for the arguments (int, AllEventsFragments, String)
I would like to add a FragmentActivity in the activity layout.
You are trying to nest activities. That is not supported via fragment transactions, and what little support there ever was for it has been deprecated for ~2.5 years.
However, you can move much of the AllEventsFragments logic into a Fragment, which can then be used from both AllEventsFragments and wherever else you are trying to use it.