简体   繁体   中英

Application architecture: ViewPager2, Fragments and MutableLiveData

Good evening,

I am new at Android App development. I have a project where I receive data from multiple sensors which are connected an instrument.

At this time, I can select any sensor and stream its data using AudioTrack. The streaming is from a service and this service is bound to the MainActivity instance. A single sensor data is streamed at the time. This is working as expected.

Now, I want to plot (using MPAndroidChart) the data for each sensor in its own chart. In the activity_main layout, I added a ViewPager2 element, and Fragments are instantiated by the PagerAdapter::CreateFragment(int position) method.

My class model is as follow (based on a ViewPager2 example ):

public class MainActivity extends AppCompatActivity
public class PagerAdapter extends FragmentStateAdapter
public class ChannelFragment extends Fragment
public class SensorViewModel extends ViewModel

I tested the visualisation of the plots in the Fragments using mock data (and a different colour background). The mock data was generated in ChannelFragment::onCreateView() method. This also works, though the mock data is the same for all fragments/charts, but different background colour for each fragment.

In a live test, I also proved to myself that I process changing the visible fragment correctly. I associate each fragment to a specific sensor and the streaming data changes as the visible fragment changes. This is done from MainActivity using ViewPager2.OnPageChangeCallback onPageSelected(position)

I am able to set the sensor data to the SensorViewModel and trigger a notification when calling postValue() from SensorViewModel.

The SensorViewModel contains the following declaration

private MutableLiveData<float[][]> sensorLiveData = new MutableLiveData<>();

and is created in MainActivity::onCreate(Bundle savedInstanceState)

            // Create a ViewModel to hold the audio (sensor) data. This view model is used to communicate
            // with the UI, graphically display the audio data for example
            sensorViewModel = new ViewModelProvider(this).get(SensorViewModel.class);

The code for the observer is defined as a ChannelFragment method and listed as

    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState)
    {
        super.onViewCreated(view, savedInstanceState);

        sensorViewModel = new ViewModelProvider(requireActivity()).get(SensorViewModel.class);
        sensorViewModel.getSampleData().observe(requireActivity(), new Observer<float[][]>() {
            @Override
            public void onChanged(@Nullable float[][] sampleData)
            {
                // Update the sample data graphical representation
                Log.d(TAG, String.format("ChannelFragment; onChanged() sampleData length : %d, size: %d",
                        sampleData.length, sampleData[0].length));
                addEntry(sampleData);
            }
        });

And the log statement reports

ChannelFragment: ChannelFragment; onChanged() sampleData length : 8, size: 170

I am stuck as to update the correct chart (correct ChannelFragment) with its corresponding sensor data.

How to a plot sampleData[0][] in Fragment at position 0, sampleData 1 in Fragment at position 1, and so forth? Calls to ChannelFragment.getId() always returns 0, though I am able to access other attributes such as title when different fragments become visible.

I also modified the SensorVIewModel as suggested by Tiago Redaelli . The new declaration:

private HashMap<Integer, MutableLiveData<ArrayList<Float>>> sensorLiveData = new HashMap<>();

where the key identifies the sensor/fragment the MutableLiveData belongs to. However, the example does not explain how to set (inject?) the ViewModel (and MutableLiveData value) to the ChannelFragment. In the example, the method setViewModel() is implemented but call is not shown.

Using this new ViewModel definition, how do I associate each HashMap values with their corresponding Fragment (who is calling setViewModel() ? What I am missing?

Thanks in advance Daniel

Just a quick update. I was trying to create a complicated solution to my issue, including looking at ViewModel factory for example. In my solution, I simply call setViewModel() (mentioned above) using the position/index value passed as argument when creating an instance of ChannelFragment.

This appears to be working.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM