I have my app working with fragment called into the main activity. Everything works great but i would like to be able to control the menu above the fragment layout.
So lets say you navigate to fragment blog posts i would like to the text view i set in the menu above the fragment to update or hide a button or show a button with set visibility.
I have no clue how to control the things who are not in the current fragment.
How should i go about this.
Thanks
Define an interface in your fragment and have your Activity implement that interface.
public interface MyInterface {
// add methods here
}
In onAttach, get the interface:
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof MyInterface) {
mMyInterface = (MyInterface) activity;
} else {
throw new ClassCastException(activity + " must implement interface MyInterface");
}
}
#Override
public void onDetach() {
mMyInterface = null;
super.onDetach();
}
Then simply call mMyInterface methods as needed.
Related
I have implemented a master-detail view. With two fragments being displayed side by side on a large 10-inch screen. Fragment A Displays a list of orders. When an order is selected the details of that order are displayed in Fragment B. In fragments B after processing the order items. I want to notify Fragment A to update the UI and colour the processed order in the list of orders.
The current method that I have tried was creating an interface in Fragment B implementing the interface in Fragment A. However, this method does not seem to work as when I try and set the instance of the interface in the onAttach method the application crashes as the context is still the context of Fragment A.
#Override
public void onAttach(#NonNull Context context)
{
super.onAttach(context);
if (context instanceof OnStockAddedListener)
{
onStockAddedListener = (OnStockAddedListener) this.getActivity();
} else
{
throw new ClassCastException(context.toString());
}
}
How can i go about doing this.
Your fragments are hosted in an Activity, and that activity is what's passed to onAttach(). So your activity needs to be responsible for dispatching communication between your fragments.
So, in FragmentB, you cast your Activity to your listener interface when you're attached:
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.onStockAddedListener = (OnStockAddedListener) context;
}
And you implement the interface in your Activity:
public class MyActivity implements OnStockAddedListener {
#Override
public void onStockAdded(Stock stock) {
FragmentA fragmentA = (FragmentA) getSupportFragmentManager()
.findFragmentByTag(/* insert tag here */);
fragmentA.handleStockAdded(stock);
}
}
And you receive these messages in FragmentA:
public class FragmentA {
public void handleStockAdded(Stock stock) {
// update ui, or whatever else you need
}
}
The main thing is to not think about FragmentA talking to FragmentB, or FragmentB talking to FragmentA. Instead, FragmentA and FragmentB both talk to the Activity, and the Activity can talk (as required) with either FragmentA or FragmentB. Everything flows through the activity.
I basically have a MainActivity that has multiple tabs. Each tab is a ShowListFragment and it extends Fragment. Now, each tab contains data that I fetch from a database. I have a MOVE-button that moves data from one tab to another in each Fragment:
#Override
public void onClick(DialogInterface dialog, int listIndex) {
database.add(listIndex,object);
database.remove(listIndex,object);
}
The fragment does not update directly, but after a few swipes in between the tabs (3 exactly). How do I force the Fragment to update instantaneous after I clicked the button? I don't want to manage it through onPageSelected in the ViewPager, since it does not update the fragment I'm currently on, but after I've swiped to the next fragment. And also I don't want to update the data after each swipe.
I know that I maybe need to use some kind of observer pattern like this: How do I make a Class extend Observable when it has extended another class too?
But still, I'm still not sure how to update the fragment directly, and how to apply the observer/event pattern in my application.
Updated Answer:
With Android architecture components, doing this is much simpler.
The recommended pattern is using a ViewModel with LiveData members. Your fragments will register observers on the LiveData members which will automatically be coordinated with lifecycle events, e.g. unregistering in onDestroy() etc. https://developer.android.com/topic/libraries/architecture/livedata
When using the Navigation component, you can pass data when navigating to a fragment: https://developer.android.com/guide/navigation/navigation-pass-data
You can also return data from the navigated fragment: https://developer.android.com/guide/navigation/navigation-programmatic
Old answer (superseded by Architecture Components):
Since the fragments can access the activity easily enough with getActivity(), I would make the activity be the central hub for dispatching updates.
It sounds like you already have the persistence part handled with the database and all you need is some update events. So here goes:
Define a listener interface. I usually do this as an inner interface within the activity:
public interface DataUpdateListener {
void onDataUpdate();
}
Add a data structure to your activity to keep track of listeners:
private List<DataUpdateListener> mListeners;
Don't forget to initialize in the constructor:
mListeners = new ArrayList<>();
Add the register/unregister methods to the activity:
public synchronized void registerDataUpdateListener(DataUpdateListener listener) {
mListeners.add(listener);
}
public synchronized void unregisterDataUpdateListener(DataUpdateListener listener) {
mListeners.remove(listener);
}
Add the event method to your activity:
public synchronized void dataUpdated() {
for (DataUpdateListener listener : mListeners) {
listener.onDataUpdate();
}
}
Have your fragments implement DataUpdateListener:
public class MyFragment extends Fragment implements DataUpdateListener {
and implement the method
#Override
public void onDataUpdate() {
// put your UI update logic here
}
Override onAttach() and onDestroy() in the fragments to register/unregister:
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((MainActivity) activity).registerDataUpdateListener(this);
}
#Override
public void onDestroy() {
super.onDestroy();
((MainActivity) getActivity()).unregisterDataUpdateListener(this);
}
Fire the event in your fragment's UI update event:
#Override
public void onClick(DialogInterface dialog, int listIndex) {
database.add(listIndex,object);
database.remove(listIndex,object);
((MainActivity) getActivity()).dataUpdated();
}
I have two fragmnent.Say fragment A and fragment B.Now after clicking on certain button in fragment A I am starting fragment B using below code
getFragmentManager()
.beginTransaction()
.replace(R.id.framelayout, companyDetailsFragment)
.addToBackStack(null)
.commit();
Now I have another back button in fragment B.After clicking that button
I am removing that particular fragment using below code
getFragmentManager().popBackStack()
Now what I want is when the user click on back button I want to pass some certain data to previous fragment A.And the problem is
onStart() method is not getting called,so I am not getting any values.
So how to get the data?Any help will be appreciated.
I am able to solve it.Here is my answer
1.Create an interface
public interface OnButtonPressListener {
public void onButtonPressed(String msg);
}
2.Implemented this in Fragment B
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
buttonListener = (OnButtonPressListener) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement onButtonPressed");
}
}
back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getFragmentManager().popBackStack();
buttonListener.onButtonPressed("Message From First Fragment");
}
});
3.Used that listener in the Activity class
public class ParentActivity extends FragmentActivity implements OnButtonPressListener {
#Override
public void onButtonPressed(String msg) {
FragmentA Obj=(FragmentA) getSupportFragmentManager().findFragmentById(R.id.framelayout);
Obj.setMessage(msg);
}
}
4.Created the method in Fragment A class
public void setMessage(String msg){
System.out.print("got it");
}
Got the reference from this .Hope this will help others.If anyone has other good solution please answer this question.
You have a few options:
Store the value you want to pass in a globally scoped variable (SharedPrefs, using a singleton accessible from your Application class, etc).
Start a new instance of your Fragment, and include the variable as a Intent Extra.
AFAIK, there is not a way to add extras to a fragment when starting from the stack (you would access this in the onResume() if the variable could be passed).
I am writing an Android app (4.4) that uses Fragments. Each Fragment is in it's own .java file (and its own class), and each one has it's own .XML (layout) file. In the main FragmentActivity, my "getItem" routine reads the "position" argument, and creates instances of these classes as needed.
When the app starts, when Fragment 0 (zero) starts up, it runs some code in the "onCreateView." Based on what happens in that code, I need to change the UI of the Fragment 1 (buttons appear & disappear based on that logic).
However, the code RUNS with no errors, but the UI changes do not take effect. I'm thinking that perhaps I need to run my "startup" code somewhere else with a wider scope. I could be wrong.
Can anyone suggest a way for me to be able to control the UI of various layouts at startup?
Thanks!
If you can post some of your code, would be easier.
anyway if I got your problem, you need to change the UI of the fragment 1 from the fragment 0.
What you need is what is explained in the document Communicating with Other Fragments
you should do something like:
public class MyActivity extends FragmentActivity implements MyInterface{
#Override
public void changeUI(String sometext) {
Fragment1 fragment1 = (Fragment1) getFragmentManager().findFragmentByTag("tagCommittedFragment1");
fragment1.applyChange(sometext);
}
}
public class Fragment0 extends Fragment{
MyInterface mMyInterface;
public interface MyInterface {
public void changeUI(String sometext);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mMyInterface = (MyInterface) activity;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mMyInterface.changeUI("newtext");
}
}
public class Fragment1 extends Fragment{
public void applyChange(String sometext){
// do your work
}
}
You must make an interface to communicate between Fragments which would be implemented by your MainActivity:
public interface Communicator {
public void respond(String data);
}
Now you need to use this Interface to send data from FragmentA:
Communicator comm = getAcitivity(); //your activity must implement this interface
comm.respond(data);
As your MainActivity implements the above interface, it will also implement the respond() method which can be used to pass data to FragmentB:
public void respond(String data){
FragmentManager manager = getSupportFragmentManager();
FragmentB fragB = manager.findFragmentById(R.id.fragment_b);
fragB.changeData(data);
}
Now all you need to do is collect this data and make changes in FragmentB using a changeData() method:
public void changeData(String data){
textView.setText(data);
}
NOTE: As FragmentB has no use of the Interface, it should not be visible to it, therefore you can also create the interface inside FragmentA instead.
I have a custom DialogFragment with a couple of options inside of it. The user is simply presented with a "Done" button in the Dialog to signal that they have completed their choice and to resume the activity. I have a textView on the activity below the dialog. My first thought was to use either a database (overkill) or sharedPreferences, but sharedPreferences is not an option in my specific case. So, my question is how do I setText on an textView from a DialogFragment with no sharedPreferences. Thanks
This can be easily done via Interface:
In your DialogFragment class:
public interface OnDoneClickListener {
void onDoneClicked() {}
}
#Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
try {
mCallback = (OnDoneClickListener) activity;
} catch (ClassCastException e) {
Log.d("Error", "activity must implement OnDoneClickListener");
}
}
Now simply put mCallback.onDoneClicked() in your desire onClick event.
Back to your Activity which need to implement OnDoneClickListener,
#Override
public void onDoneClicked() {
tv.setText("Done Clicked!!");
}
If you're using an AlertDialog (simplest) then you just need to provide an onClickListener:
http://developer.android.com/reference/android/app/DialogFragment.html#AlertDialog
That page also has an example when using a more "standard" Fragment, basically call a method on the activity.