web-dev-qa-db-fra.com

MutableLiveData ne se met pas à jour dans l'interface utilisateur

PDATE: Si je passe à un autre fragment et reviens à celui-ci, TextView est mis à jour ...

Je ne parviens pas à obtenir le MutableLiveData dans l'interface utilisateur pour mettre à jour vers une nouvelle valeur en utilisant setValue () ou postValue (). Je peux faire en sorte que cela fonctionne en changeant MutableLiveData en ObservableData, mais le but est d'utiliser LiveData et non ObservableData.

J'ai des choses similaires qui fonctionnent dans d'autres vues sans problème. Je ne sais pas ce qui se passe ici ... La seule chose à laquelle je peux penser est que je saute entre une activité de caméra (via l'intention) et ce fragment. Sur le résultat de l'activité, je configure les données du fragment vers le ViewModel.

Je ne crois pas que je dois définir un observateur pour la valeur du fragment, car j'ai une liaison de données à 2 voies entre XML et ViewModel.

my_fragment.XML

<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    xmlns:tools="http://schemas.Android.com/tools">

    <data>
        <variable
            name="myViewModel"
            type="com.example.myapplication.MyViewModel" />
    </data>

    <LinearLayout
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:orientation="vertical">

            <TextView
            Android:id="@+id/textView"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:text="@={myViewModel.photosCount}"
            tools:text="1" />

           <Button
               Android:id="@+id/btnTakePhoto"
               Android:layout_width="wrap_content"
               Android:layout_height="wrap_content"
               Android:text="Take Picture"
               Android:onClick="@{myViewModel::navClicked}"/>

    </LinearLayout>

</layout>

MyViewModel.Java

private MutableLiveData<String> photosCount = new MutableLiveData<>();
private MutableLiveData<Boolean> takePhoto = new MutableLiveData<>();

public MyViewModel() {
    photosCount.setValue("0"); // This correctly sets the value to "0" in UI
    takePhoto.setValue(true);
}

public MutableLiveData<String> getPhotosCount() {
    return photosCount;
}

public MutableLiveData<Boolean> getTakePhoto() {
    return takePhoto;
}

public void storeImage() {
    ....
    Log.d(TAG, "Updating UI count to: " + String.valueOf(count)); // this shows the correct value that should be updated in the UI
    photosCount.setValue(String.valueOf(count));
    Log.d(TAG, "Updated value: " + photosCount.getValue()); // this shows the correct updated value
    ...
}

public void navClicked(@NonNull View view) {
    if (view.getId() == R.id.btnTakePhoto) {
        takePhoto.setValue(true);
    }
}

Maintenant, puisque LiveData ne garantit pas la mise à jour de l'interface utilisateur au moment de modifier la valeur, je pensais que cela pourrait être un problème de répartition contraignant. Cela n'a pas résolu le problème non plus ...

MyFragment.Java

private MyViewModel myViewModel;
MyFragmentBinding binding;

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

    myViewModel = new ViewModelProvider(this).get(MyViewModel.class);

    binding = DataBindingUtil.inflate(inflater, R.layout.my_fragment, container, false);
    binding.setMyViewModel(myViewModel);

    return binding.getRoot();
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    viewModel.getTakePhoto().observe(getViewLifecycleOwner(), takePhoto -> {
        if (takePhoto) {
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

            if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
                File photo = viewModel.createImageFile();
                if (photo != null) {
                    Uri photoURI = FileProvider.getUriForFile(getActivity(),"com.example.fileprovider", photo);
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                    this.startActivityForResult(intent, Constants.RequestCodes.MY_REQUEST_IMAGE_CAPTURE);
                }
            }
        }
    });
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == Constants.RequestCodes.MY_REQUEST_IMAGE_CAPTURE) {
            viewModel.storeImage();
        }
    }
}

Encore une fois, si vous passez de photosCount de MutableLiveData à ObservableData, le problème est résolu, mais ce n'est pas LiveData.

4
DevinM

D'après les documents officiels:

/**
 * Sets the {@link LifecycleOwner} that should be used for observing changes of
 * LiveData in this binding. If a {@link LiveData} is in one of the binding expressions
 * and no LifecycleOwner is set, the LiveData will not be observed and updates to it
 * will not be propagated to the UI.
 *
 * @param lifecycleOwner The LifecycleOwner that should be used for observing changes of
 *                       LiveData in this binding.
 */z

Étapes requises:

  1. Assurez-vous de définir activityOrFragmentBinding.lifecycleOwner = this après avoir intégré la liaison de la vue. activityOrFragmentBinding remplacez-le par le nom de votre variable de liaison.
  2. Définissez toujours ViewModel sur la liaison de données.
0
Muhammad Maqsood