Liaison de données de mise à jour de l'interface utilisateur en utilisant le fragment de liaison

voix
0

Apparemment, il y a une science à databainding dans Android dont je get clairement Do not. Je continue à mettre fin à des vues de mise à jour via le fragment combattre ou viewmodel où certaines choses d'autres « juste travail » sont apparemment non fonctionnel.

Je veux désactiver un bouton de connexion, modifier le texte et définir une alpha après son été cliquée jusqu'à ce que je reçois une réponse de l'API je change en arrière. Assez simple. Je ne suis pas compris le code qui va changer en arrière depuis son arrêt à changer la première fois.

Tout en écrivant cela, j'eu le même problème à plusieurs reprises, le bouton ne change jamais. L'observateur dans le fragment est appelé (Dans le journal, il montre dans l'ordre, je pense qu'il a été appelé), mais l'interface utilisateur mise à jour juste ne marche pas. Je l'ai couru sur un émulateur de nouveau et à plusieurs reprises l'observateur ne marche pas de journal est que beaucoup plus tard, puis la vue mise à jour comme prévu, sorta. Il na pas à jour quand je clique sur le bouton, mais au moins le bouton changé avant que la réponse de l'API est revenu. Je me suis arrêté l'application et re-couru et le dos im à la question d'origine, sa mise à jour pas.

Im en utilisant SingleLiveEvent non modifiée à partir d' échantillons d'architecture googles https://github.com/android/architecture-samples/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/ plans / todoapp / SingleLiveEvent.java

activity_main_login <- est un fragment, mais pas l'activité Je nai refactorisés encore. Ceci est tronqué de sorte qu'il ne fonctionne pas sans un conteneur de mise en page.

<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=mainViewModel
            type=com.example.viewmodel.MainViewModel />
    </data>
    ...
    <Button
        android:id=@+id/btnLogin
        android:layout_width=135dp
        android:layout_height=47dp
        android:layout_marginLeft=8dp
        android:layout_marginRight=8dp
        android:layout_marginTop=16dp
        android:onClick=@{() -> mainViewModel.loginClicked()}
        android:text=@string/login
        android:textColor=#ffffff
        android:textStyle=bold
        android:background=#e05206
        app:layout_constraintLeft_toLeftOf=parent
        app:layout_constraintRight_toRightOf=parent
        app:layout_constraintTop_toBottomOf=@+id/fingerprintSwitch
        tools:layout_editor_absoluteX=101dp />
    ....
</layout>

MainFragment

ActivityMainLoginBinding binding;

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

    mainViewModel = new ViewModelProvider(this).get(MainViewModel.class);

    getLifecycle().addObserver(mainViewModel);

    binding = DataBindingUtil.inflate(inflater, R.layout.activity_main_login, container, false);
    mView = binding.getRoot();
    binding.setMainViewModel(mainViewModel);
    binding.setLifecycleOwner(this); // Yeah this is what I forgot last time...

    return mView;
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    AppLog.d(TAG, -> onViewCreated() );
    super.onViewCreated(view, savedInstanceState);

    mainViewModel.getShowLoading().observe(getViewLifecycleOwner(), showLoading -> {
        AppLog.d(TAG, showLoading changed);
        this.loading = true;

        binding.btnLogin.setText(R.string.loggingIn);
        binding.btnLogin.setEnabled(false);
        binding.btnLogin.setAlpha(.5f);
    });
}

MainViewModel

private SingleLiveEvent<Boolean> showLoading = new SingleLiveEvent<>();

public void loginClicked() {
    Log.d(TAG, loginClicked());
    showLoading.setValue(true);
    login();
}

Voici ce que les journaux ressemblent quand il fonctionne et vous cliquez sur le bouton de connexion ...

D/MainViewModel: loginClicked()
D/MainFragment: showLoading changed
D/MainViewModel: login()
Créé 13/01/2020 à 21:52
source utilisateur
Dans d'autres langues...                            


1 réponses

voix
0

Non pas que j'inclus le code Retrofit2 qui a fait / reçu l'appel de l'API, mais il a dû faire avec le filetage. J'Enveloppez la méthode qui a appelé la ressource de rattrapage synchrone

new Handler().post(() -> { });

Le login () ressemble plus à ce moment

private void login() {
    new Handler().post(() -> {
        // original retrofit call
        Thread t = new Thread(() -> authResponse = restApi.doAuthSync());
        t.start();

        // Joining thread so we wait for the response
        // I believe this to be the actual culprit of the problem
        try {
            t.join();
        } catch (InterruptedException e) {
            Log.e(TAG, e.getMessage());
        }

        // handle authResponse
        ...
    });
}

Même si l'appel API lui-même doit se faire sur son propre fil (et était) la chose entière vient de se tenir le fil de l'interface utilisateur la plus probable en raison de la Thread.join (). Cela a causé les DataBindings pas mise à jour. Cela peut avoir été résolu en utilisant RxJava mais je n'ai pas mis en œuvre que encore et pour une tâche simple son pas nécessaire.

Créé 14/01/2020 à 23:25
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more