Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading data in ViewModel that have been retrieved in SplashActvity

I'm new with the ViewModel and I understand that it's a powerful and easy way to communicate with fragments.

My problem is the following : How to load the data retrieved in the SplashActivity in the ViewModel of the mainActivity ?

My app achitecture is the following :

  1. SplashActivity : retrieve data with retrofit and store it into a List
  2. Main Activity : contains two fragments displaying the data in different ways

Here is a piece of code showing my implementation.

SplashActivity

public class SplashActivity extends AppCompatActivity {

    private final String TAG = "TAG.SplashActivity";
    public static List<Toilet> toiletList = new ArrayList<>(); // HERE IS THE DATA I WANT TO 
    RETRIEVE IN THE MAIN ACTIVITY

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /*Create handle for the RetrofitInstance interface*/
        GetDataService service = ...;
        // MY STUFF RETROFIT including
        Intent intent = new Intent(getApplicationContext(), MainActivity.class);
        intent.putExtra("toiletList", (Serializable) toiletList);
        startActivity(intent);
        finish();
    }
}

MainActivity

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {

    private final String TAG = getClass().getName();
    private List<Toilet> toiletList = new ArrayList<>();

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

        Intent intent= getIntent();
        Serializable s = intent.getSerializableExtra("toiletList");
        // Check type and cast
        if (s instanceof List<?>) {
            for (Object o : (List<?>) s) {
                if (o instanceof Toilet) {
                    toiletList.add((Toilet) o);
                }
            }
        }

        // SETTING UP FRAGMENTS
    }
}

FragmentExample

public class MainFragment extends Fragment {

    public static List<Toilet> toiletArrayList = new ArrayList<>();
    private final String TAG = this.getClass().getName();

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

        View view = inflater.inflate(R.layout.fragment_main, container, false);

       // SETTING UP UI
        return view;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        ToiletListViewModel model = ViewModelProviders.of(this).get(ToiletListViewModel.class);
        model.getToiletList().observe(this, new Observer<List<Toilet>>() {
            @Override
            public void onChanged(@Nullable List<Toilet> toilets) {
                //  update UI
            }
        });
    }
}

ToiletListViewModel

public class ToiletListViewModel extends ViewModel {

    private final String TAG = getClass().getName();
    private MutableLiveData<List<Toilet>> toiletList;

    public LiveData<List<Toilet>> getToiletList() {
        if (toiletList == null) {
            toiletList = new MutableLiveData<>();
            loadToilets();
        }
        return toiletList;
    }

    private void loadToilets() {
        // asynchronously fetch toilets
        // HERE IS MY PROBLEM : How to access the toiletList retrieved
        in the SplashActivity ?
        toiletList.setValue(SplashActivity.toiletList);
    }

    @Override
    protected void onCleared() {
        super.onCleared();
        Log.d(TAG, "onCleared() called");
    }
}

I hope that's clear. If you want any further info, fell free to ask !

Best

like image 490
Maxouille Avatar asked Oct 06 '18 11:10

Maxouille


People also ask

What happens when activity recreated with ViewModel?

Handle configuration changes: ViewModel objects are automatically retained whenever activity is recreated due to configuration changes.

What happens to ViewModel when activity is destroyed?

E.g. if it is an Activity, until it is finished. In other words, this means that a ViewModel will not be destroyed if its owner is destroyed for a configuration change (e.g. rotation). The new instance of the owner will just re-connected to the existing ViewModel.

Does ViewModel survive configuration changes?

The Android team introduced ViewModel and LiveData classes to help save state during configuration changes. A ViewModel stores and manages UI-related data in a lifecycle-conscious manner. Simply put, it allows data to survive configuration changes.

How do you pass data between fragments using ViewModel?

Passing Data between fragments in Android using ViewModel: This is because ViewModel is tied to the activity lifecycle. To actually pass the data between fragments, we need to create a ViewModel object with an activity scope of both the fragments, initialize the ViewModel , and set the value of the LiveData object.


1 Answers

You can share your ToiletListViewModel between the MainActivity and its Fragments.

So what you need is to provide your ViewModel with MainActivity scope (It means you bound the lifecycle of your ViewModel to your Activity) and call initToilets then child fragments can easily retrieve this ViewModel and observe on its LiveData.

ToiletListViewModel:

public class ToiletListViewModel extends ViewModel {

    private MutableLiveData<List<Toilet>> toiletList = new MutableLiveData();

    public LiveData<List<Toilet>> getToiletList() {
        return toiletList;
    }

    private void initToilets(List<Toilet> toilets) {
        toiletList.setValue(toilets);
    }


}

MainActivity:

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {

    private final String TAG = getClass().getName();
    private List<Toilet> toiletList = new ArrayList<>();

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

        Intent intent= getIntent();
        Serializable s = intent.getSerializableExtra("toiletList");
        // Check type and cast
        if (s instanceof List<?>) {
            for (Object o : (List<?>) s) {
                if (o instanceof Toilet) {
                    toiletList.add((Toilet) o);
                }
            }
        }
     ToiletListViewModel vm = ViewModelProviders.of(this).get(ToiletListViewModel.class);
     vm.initToilets(toiletList);
        // SETTING UP FRAGMENTS
    }
}

So, when setValue is called, Fragments that listen to the toiletList live data will be notified.

Note:

You can create a shared ViewModel without providing it on MainActivity, instead of calling

ViewModelProviders.of(this).get(ToiletListViewModel.class);

in your Fragment do

ViewModelProviders.of(getActivity()).get(ToiletListViewModel.class);
like image 69
Saeed Masoumi Avatar answered Sep 18 '22 23:09

Saeed Masoumi