Is it possible for two (switch) buttons to have synchronized behavior between fragments? i.e: When button A is switched on in fragment A, I want button B's appearance in fragment B to also appear switched on.
How would I do that? The end goal is to have a global button on either fragment.
You can use a boolean flag in your activity and set it false by default and when any of switch is pressed on in either fragment then set its value to true, and when you navigate to another fragment then check flag value and if its true then switch it on or else off.
That would depend on whether both fragments are on same activity. If they are, then all you need is a boolean flag on the said activity and synchronise depend on that.
If not, then maybe create an boolean preference and synchronise based on that. Hope this helps. If you need code examples, let me know.
public interface Listener {
public boolean getFlag();
public void setFlag(boolean enable);
}
public class SomeActivity extends AppCompatActivity implements Listener {
// getFlag, setFlag implementation
}
public class FragmentA {
private boolean state;
private Listener listener;
private Switch switchBtn;
public void onAttach(Context ctx){
listener = (Listener) this.getActivity();
// check for ClassCast Exception
}
public void onActivityCreated() {
state = listener.getFlag();
switchBtn.setChecked(state);
}
}
For details view this page
Sample of communication between Fragments. Example below is modified from Communicating with Other Fragments
Step 1. Create an interface
public interface ButtonCallback{
void onClick(boolean val)
}
Step 2. In the HostActivity which hosts both fragment A and B, make HostActivity implements interface ButtonCallback.
public class HostActivity extends AppCompatActivity implements ButtonCallback{
void onClick(boolean val){
}
}
Step 3. In fragment A & B, initialize the callback with casting the activity
class FragmentA extends Fragment{
ButtonCallback callback;
#Override
public void onAttach(Context context) {
super.onAttach(context);
//Make sure activity host implement ButtonCallback interface
try {
callback= (ButtonCallback ) context;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement ButtonCallback");
}
}
//public method to update fragment's button state
public void setGlobalButtonState(boolean val){
//globalButton has been initialized in onCreateView function
globalButton.setEnabled(val);
}
}
class FragmentB extends Fragment{
ButtonCallback callback;
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
callback= (ButtonCallback ) context;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement ButtonCallback");
}
}
public void setGlobalButtonState(boolean val){
//globalButton has been initialized in onCreateView function
globalButton.setEnabled(val);
}
}
Step 4. In Fragment A, call ButtonCallback.onClick(boolean) when user click on the button
globalButton.setOnClickListener(new View.OnClickListener(View v){
Boolean value = !v.isEnabled();
callback.onClick(value)
});
Step 5. In HostActivity's onClick function, find a way to get Fragment B that suis your context, and update the button in Fragment B via the setGlobalButtonState function
void onClick(boolean val){
//get Fragment B.
fragmentB.setGlobalButtonState(val);
}
Additional note, if the button meant to be global, it might worth to consider to put the button on the host Activity instead if that suits your context.
Here is the developer guide on communicating with other fragments: https://developer.android.com/training/basics/fragments/communicating .
In the activity have the shared attribute. In each fragment, go to the parent activity to get that attribute on button click.
To reduce dependency, use an interface to obtain the data from the activity, as shown in the link provided
Related
long story short.
I have the mainActivity with two Fragments. So instead of the mainActivity there are the two Fragments.
In the first Fragment there is a Switch.
Is it possible to update the background from the mainActivity when the switch is checked or unchecked? The Background is set in the content_main.xml, because then you have no transition when changing the fragments.
So is it at all possible?
I thought this would work:
if(switch.isChecked()) {
SharedPreferences sharedPref = getActivity().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt("background1", R.drawable.background2);
editor.apply();
}
And in the MainActivity:
SharedPreferences sharedPref = getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
int bg = sharedPref.getInt("background1", R.drawable.background1);
getWindow().setBackgroundDrawableResource(bg);
Or is it just not possible because the fragment isn't loading itself new?
If so. How is it possible?
Thanks in advance guys
source:
Changing background of an activity from another activity
Use callback interface to communicate between fragment and your activity
Please see the below code snippet :
public class YourFragment extends Fragment{
OnCallbackReceived mCallback;
// Implement this interface in your Activity.
public interface OnCallbackReceived {
public void Update(boolean state);
}
In your fragment :
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (OnCallbackReceived) activity;
} catch (ClassCastException e) {
}
}
// You can Call the event from fragment as mentioned below
// mCallback is the activity context.
mCallback.Update(switch.isChecked());
Activity :
public class MainActivity extends Activity
implements YourFragment.OnCallbackReceived {
// Implemented method.
public override void Update(boolean state) {
// Update bg here
}
Original:
How to send data from fragment to activity
use Otto event bus,It's easy and simple
Click this link
add this to your dependencies
implementation compile 'com.squareup:otto:1.3.8'
Activity or Fragment onCreate add this one
Bus bus = new Bus();
You can post event like this from your activity or fragment
bus.post(new AnswerAvailableEvent(42));
if you want to get events even when your fragment is in the foreground or background, Subscribe to the events like below
#Subscribe public void answerAvailable(AnswerAvailableEvent event) {
// TODO: React to the event somehow!
}
Don't forget to register and unregister in onStart and onStop
#Override
protected void onStart(){
super.onStart();
bus.register(this);
}
#Override
protected void onStop(){
super.onStop();
bus.unregister(this);
}
Yes, it's possible to achieve that. I think the easiest way to do so is through a listener/callback.
First of all, create your listener class:
public interface MyCallback {
void onSwitchStateChanged(boolean isChecked);
}
After that, make your Activity implement that interface, and implement your background changing logic inside the onSwitchStateChanged method.
Now, inside your Fragment's onAttach() method, do the following (this example is in Kotlin):
override fun onAttach(context: Context?) {
super.onAttach(context)
if (context is MyCallback) {
myListener = context as MyCallback
}
else {
throw RuntimeException("Must implement MyCallback!")
}
}
Where myListener is a variable inside your fragment.
Now add a setOnCheckedChangeListener on your switch, like it's described on this answer, and use the callback inside it. For example (in Java):
mySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
myListener.onSwitchStateChanged(isChecked);
}
});
I am new to Android and I am trying to build an app containing three fragments: let's say A, B, and C. I want a button on A to show me B when clicked, and a button on B to show me C when clicked. I understand that one way is to use FragmentManager like this: in fragment A, I can have a button click listener that does
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, new B())
.commit();
However, I do not want A to know about fragment B, or B to know about C. I was thinking of creating some kind of FragmentController to solve this problem such that the Controller would know about the necessary transitions and maintain a state machine.
Is this a common pattern in Android? I tried googling but I didn't see many code examples for this pattern. How can I decouple the different fragments so that the fragments don't have to worry about the transitions?
Thanks.
Yes, it is a common pattern, you need understand how to work the comunnication between fragments.
Taking on, your fragments are contained in an activity, maybe you can do the next:
The Fragment listener
public interface FragmentNavigationListener {
public void onNavigateTo(int fragment);
}
The Activity which implements callback
public static final int Fragment FRAGMENT_A = 0;
public static final int Fragment FRAGMENT_B = 1;
#Override
public void onNavigateTo(int fragment){
switch fragment{
case FRAGMENT_A :
...
case FRAGMENT_B :
...
}
}
Each Fragment
must encore that parent activity implements the listener
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (FragmentNavigationListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement FragmentNavigationListener");
}
}
In OnclickListener from each button in each fragment you call the listener.
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
mCallback.onNavigateTo(FRAGMENT_B);
}
});
Write fragmentInteraction interfaces, define methods in this interface, then onAttach of the fragment lifeCycle do this
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
That way every activity to which this fragment gets attached to must implement the OnFragmentInteractionListener. Now in your onClick method do mListener.onClick(view) assuming you have a method called onClick(View v) defined in your interface. And in your activity's implementation of the onClick function do the fragmentTransaction
In my main Activity, I have a DialogFragment that contains a FragmentTabHost. I have two tabs, one that is a DialogFragment and one that is a ListFragment. When either the 'OK' button is pressed in the inner DialogFragment or when an element in the ListFragment is pressed, I want to pass two Strings (that are entered in two TextView's in the inner DialogFragment and are displayed in each element in the ListFragment) back to the Activity, but I am unsure of how to do this with multiple levels of Fragments.
Any help is appreciated!
There's no magic.
You can achieve with two approaches.
Use callback.
Create interface and class to pass the data through child Fragment to Activity. You don't need to modify bridged TabHostFragment as Fragment always rely on its mother Context (Activity) no matter how many fragments wrap the fragment.
public class TwoStrings {
public TwoStrings(String one, String two){
this.one = one;
this.two = two;
}
public String one;
public String two;
}
First, declare interface.
public interface DataPassListener {
void dataPassed(TwoStrings data);
}
And, implement interface in Activity.
public class MainActivity extends Activity implements DataPassListener {
#Override
public void dataPassed(TwoStrings data) {
// do something with data.
Log.d("string one", data.one);
Log.d("string two", data.two);
}
}
Finally, let child Fragment acknowlege that mother Activity has the callback listener.
public class DialogFragment1 extends DialogFragment {
DataPassListener listener;
#Override
public void onAttach(Activity activity) {
if (activity instanceOf DataPassListener)
listener = (DataPassListener) activity;
}
public void setDataPassListener(DataPassListener listener){
listener = ((DataPassListener) listener);
}
public void doSomeThing(){
if(listener != null) // important to prevent NullPointerException
listener.dataPassed("a", "b");
}
}
Use EventBus.
I prefer to use Otto in order to publish and subscribe data.
To subscribe event for listening in Activity,
public class MainActivity extends Activity {
#Override
public void onResume() {
super.onResume();
BusProvider.getInstance().register(this);
}
#Override
public void onPause() {
super.onPause();
BusProvider.getInstance().unregister(this);
}
#Subscribe
public void onUpdateTwoStrings(TwoStrings event) {
// do something with data.
Log.d("string one", data.one);
Log.d("string two", data.two);
}
}
And, publish event in anywhere in Fragment.
bus.post(new TwoStrings("a", "b"));
Take a look at setTargetFragment() and getTargetFragment() methods. You could connect fragments with each other through it without any additional callbacks and libs.
For Fragment-Activity communication, this is the suggested way of doing it, by using a listener.
In my case I have two fragments and a button at each and I would like them to do the exact same thing when pressed.
Should I create a separate listener class that the Activity implements and then instantiate a listener in each fragment or there is a better design that I am not aware of?
EDIT
I am sorry, I probably didn't communicate that properly. I am not looking for communication between fragments. I have a Fragment A with a buttonA and a Fragment B with a buttonB. When I click on buttonA, there is a listener in my Activity and method doSomething() is called. Now I want buttonB calling doSomething() too. Should I A) create a second listener and have the activity implement that too, B) create one separate listener class and use this one for both or C) a better choice ??
For communication between fragment to frament or activity to fragment communication via events. There are few alternatives are there e.g. this otto eventbus I know. and the tutorial about this can be found Here or just google it.
As from the documentation :
Two Fragments should never communicate directly.
So you best follow the pattern explained in the article and communicate thru the activity on which the fragments are attached.
When a listener is called from fragment A then get the fragment B from the fragmentManger
YourFragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_b);
fragment.doSomething();
I'm using this pattern and it works well for me:
public class Fragment1 extends Fragment {
FragmentListener mCallback;
public interface FragmentListener {
public void onAction1();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof FragmentListener) {
mCallback = (FragmentListener) activity;
}
}
public void onAction2() {
// do your stuff...
}
}
public class Fragment2 extends Fragment {
FragmentListener mCallback;
public interface FragmentListener {
public void onAction2();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof FragmentListener) {
mCallback = (FragmentListener) activity;
}
}
public void onAction1() {
// do your stuff...
}
}
public class MainActivity implements Fragment1.FragmentListener, Fragment2.FragmentListener {
private Fragment1 fragment1;
private Fragment2 fragment2;
/**
* Listening to events from first fragment and forwarding to second fragment
*/
#Override
public void onAction1() {
fragment2.onAction1();
}
/**
* Listening to events from second fragment and forwarding to first fragment
*/
#Override
public void onAction2() {
fragment1.onAction2();
}
}
The Activity listens to "events" from the fragments and if needed forward it to the other fragment(s).
I have two Fragments in my Activity: fragment A with button X and fragment B with button Y.
How can I change button X's background image when I click button B? Is it possible?
From the documentation,
Because each fragment defines its own layout and its own behavior with its own lifecycle callbacks, you can include one fragment in multiple activities, so you should design for reuse and avoid directly manipulating one fragment from another fragment.
That being said, what you want to do is create event callbacks to the activity. A good way to do that is to define a callback interface inside the fragment and require that the host activity implement it. When the activity receives a callback through the interface, it can share the information with other fragments in the layout as necessary. This is the recommended way to share events between two separate Fragments--that is, sharing the event through the activity.
Check out the link above... it provides a couple nice examples. If you are still having trouble, let me know and maybe I can be more explicit.
Edit #1:
Let's say you click a button in fragment A and you want this to cause changes to a button in fragment B. Here's some sample code illustrating the concept:
The callback interface:
public interface OnButtonClickedListener {
public void onButtonClicked();
}
The activity:
public class SampleActivity extends Activity implements OnButtonClickedListener {
/* Implementation goes here */
public void onButtonClicked() {
// This method is called from fragment A, and when it is called,
// it will send information to fragment B. Remember to first
// check to see if fragment B is non-null.
/* Make call to a method in fragment B that will update its display */
}
}
Fragment A:
public class FragmentA extends Fragment {
OnButtonClickedListener mListener;
/* Implementation goes here */
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnButtonClickedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnButtonClickedListener ");
}
}
public void clickButton() {
// When the button is clicked, notify the activity.
// The activity will then pass the information to fragment
// B (if it has been created).
mListener.onButtonClicked();
}
}
Edit #2:
Now, you might be wondering, "Why would anyone ever go through all of this trouble? What's the point of creating a separate activity callback method when you could just have fragment A directly manipulate fragment B?"
The main reason you want to do this is to ensure that each fragment is designed as a modular and reusable activity component. This is especially important because a modular fragment allows you to change your fragment combinations for different screen sizes. When designing your application to support both tablets and handsets, you can reuse your fragments in different layout configurations to optimize the user experience based on the available screen space. For example, on a handset, it might be necessary to separate fragments to provide a single-pane UI when more than one cannot fit within the same activity. Making use of activity callbacks ensures that you will easily be able to reuse your fragments in situations where fragment B is not visible on the screen. For example, if you are on a handheld device and there is not enough room to display fragment B, then you can easily have your activity check to see if fragment B is currently being shown on the screen.
Sorry if this isn't clear... I'm finding it difficult to describe :P. Working your way through this tutorial might help... Activity callbacks make your life especially easier as a developer when you are working with interactive multi-pane layouts.
Base on Alex Lockwood's answer:
The activity:
public class SampleActivity extends Activity{
public interface OnButtonClickedListener {
public void onButtonClicked();
}
private OnButtonClickedListener onButtonClickedListener = null;
public OnButtonClickedListener getOnButtonClickedListener () {
return onButtonClickedListener
}
public void setOnButtonClickedListener (
OnButtonClickedListener onButtonClickedListener {
this.onButtonClickedListener = onButtonClickedListener;
}
}
Fragment A:
public class FragmentA extends Fragment {
private OnButtonClickedListener onButtonClickedListener = null;
private OnClickListener actionBarClickListener = new OnClickListener() {
#Override
public void onClick(View view) {
if (onButtonClickedListener == null){
onButtonClickedListener = ((SampleActivity) getActivity()).onButtonClickedListener ();
}
if (onButtonClickedListener != null) {
onButtonClickedListener
.onButtonClicked();
}
}
};
}
Fragment B:
public class FragmentB extends Fragment {
private OnButtonClickedListener onButtonClickedListener = new OnButtonClickedListener() {
#Override
public void onButtonClicked() {
Toast.makeText(getActivity(), "Button clicked", Toast.LENGTH_SHORT).show();
}
};
#Override
public void onResume() {
super.onResume();
SampleActivity sampleActivity = (SampleActivity) getActivity();
sampleActivity.setSearchBoxTextChangedListener(onButtonClickedListener);
}
}
Hope can help someone.
Setting the onClick attribute for a button in your layout, even your fragment's layout, will call the appropriate method on your Activity.
Your app can then send this signal from your Activity to fragment B.