Detect changes to Data Model Android

1.1k Views Asked by At

I am trying to build an app with one MainActivity and multiple fragments.

In my MainActivity, I get the data and store it in the Data Model. For example, getting sunrise time, then display it in Fragment B. How can I detect the sunrise value changes and update the TextView in Fragment without restarting the app? Is there way can listen to value changed and update the textView?

here are my codes and fragment B layout.

JAVA data model CLASS

public class SunriseTimeClass {
    private static final SunriseTimeClass INSTANCE = new SunriseTimeClass();
    public String sunrise = "";

    private SunriseTimeClass(){ }

    public static SunriseTimeClass getInstance(){
        return INSTANCE;
    }
}

MAINACTIVITY

    override fun onCreate(savedInstanceState: Bundle?) {

      //this will clear the back stack and displays no animation on the     screen
      var sunRise = SunriseTimeClass.getInstance()

      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)
      setSupportActionBar(toolbar)
      supportActionBar!!.setDisplayShowHomeEnabled(true)

      getSunriseSunset()
    }

    fun getSunriseSunset(){
      val location =  com.luckycatlabs.sunrisesunset.dto.Location("40.9167654", "-74.171811")
      val calculator =  SunriseSunsetCalculator(location, "America/New_York")
      sunRise.sunrise = calculator.getOfficialSunriseForDate(Calendar.getInstance())
    }

FRAGMENT B layout

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text=""
        android:gravity="center"
        android:id="@+id/DisplaySunrise"/>
</FrameLayout>
5

There are 5 best solutions below

0
On

There are two possible ways to approach this.

FragmentB gets the sunRise data and updates its own TextView

Have FragmentB retrieve the sunRise values directly and update its TextView, rather than performing the retrieval in MainActivity.

OR

Communicate between Activity and Fragment via an interface

This answer is similar to another one in this thread, but is more explicit on how you would set the fragment's TextView. This solution makes several assumptions and may be an oversimplification due to the limited information in your question:

Assumption 1: This solution assumes that the getSunriseSunset method is synchronous, i.e. not dependent on any service or network call. If it is asynchronous, you would need a separate callback in your MainActivity (e.g. onSunriseRetrieved) to listen for when your data is returned, prior to updating your fragment.

Assumption 2: This solution also assumes that you want access to the fragment's views immediately after it has been added (hence, the executePendingTransactions call). That said, if you have FragmentB perform its own retrieval of the sunRise, then this assumption wouldn't be needed.

Define an interface in the Activity and :

    public class MainActivity extends AppCompatActivity
    {    
        public interface OnSunriseChangeListener
        {
            void onSunriseChange(String newText);
        }

        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            if (savedInstanceState == null)
            {
                getFragmentManager()
                    .beginTransaction()
                    .add(R.id.fragment_container, new FragmentB()))
                    .commit();

                //assuming you want access to the fragment's views immediately
                getFragmentManager().executePendingTransactions();
            }

            getSunriseAndUpdateFragment(fragment);

        } 

        /**
         * Assumes that getSunriseSunset is synchronous and assumes that FragmentB is created. 
         */
        private void getSunriseAndUpdateFragment()
        {
            String newSunRiseValue = getSunriseSunset();
            ((FragmentB)getFragmentManager().findFragmentById(R.id.fragment_b)).onSunriseChange(newSunRiseValue);
        }

        // other code not shown...
    }

Have FragmentB implement the interface:

    public class FragmentB extends Fragment implements OnSunriseChangeListener
    { 

        @Override
        public void onSunriseChange(String newSunriseData)
        { 
            TextView textView = getView.findViewById(R.id.DisplaySunrise);
            textView.setText(newSunriseText);
        }
1
On

(Java code)

Create a setter method in fragment which will be called by activity like:

In fragment:

public void setSunrise(String sunrise){
    this.sunrise = sunrise;
    //further operations..
}

And in Activity:

Fragment fragment = new Fragment(); //your fragment
String s= calculator.getOfficialSunriseForDate(Calendar.getInstance());
fragment.setSunrise(s);
2
On

If I understood you right, you need change/update the fragment when something happens in the Activity.

So I think you could implement an interface ( callback ) between the Activity and the Fragment.

1.You need create an interface in the Activity:

   public interface OnActivityAction {
            void updateFragment();}

2.You need declare the interface and the setter in the Activity and call it when you want

public OnActivityAction actionListener;

    public void setOnActionListener(OnActivityAction fragmentListener) {
        this.actionListener = fragmentListener;
    }

private void myActionToUpdate(){

      if (null != activityListener) {
            activityListener.doSomethingInFragment();
        }
}

3.Then in your Fragment need implement this interface and set the listener.

public class MyFragment extends Fragment implements OnActivityAction {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

         View rootView = inflater.inflate(R.layout.fragment_test_two, container, false);

        ((MainActivity) getActivity()).setOnActionListener(this);

         return rootView;
    }

    @Override
    public void updateFragment() {
        //Do whatever you want
    }
}

I hope this helps you.

0
On
  1. Add fragment from activity



    FragmentManager fragmentManager = getSupportFragmentManager();
        android.support.v4.app.FragmentTransaction fragmentTransaction = 
     fragmentManager.beginTransaction();
     //frame_layout put in activity xml
     fragmentTransaction.add(R.id.frame_layout, drawer, "").commit();

  1. Get Fragment instance and update your data


    FragmentManager fragmentManager = getSupportFragmentManager();
    Fragment fragment = fragmentManager.findFragmentById(R.id.frame_layout);
    ((FragmentB)fragment).updateFragment("Updated value");

  1. Make Public method in fragment for update textview



    public void updateFragment(String value) {
            //update textview here
           Textview.setText(value);
     }

0
On

Thanks for all the great answers. I have used SharePreference to do my job. working as expected.