Datenbindung von Fragment Update UI Bindungs

stimmen
0

Anscheinend gibt es eine Wissenschaft zu databainding in Android, von denen ich eindeutig dont get. Ich halte endet Aktualisierung Ansichten über das Fragment oder Ansichtsmodell kämpfen, wo einige Dinge „einfach funktionieren“ andere scheinbar nicht funktionsfähig sind.

Ich möchte ein Login-Button deaktivieren, seinen Text ändern und einen Alpha-Set nach seiner geklickt wurde, bis ich eine API-Antwort erhalten dann ich es wieder ändern. Ziemlich einfach. Im darunter nicht den Code, der es wieder ändern wird, da seine Anhalte es zum ersten Mal zu ändern.

Beim Schreiben dieses ich das gleiche Problem immer und immer hatte, ändert sich die Taste nicht. Der Beobachter im Fragmente aufgerufen wird (im Protokoll zeigt es in der Reihenfolge ich es erwarten genannt worden), aber die UI gerade tut Update. Ich lief es auf einem Emulator wieder und immer wieder der Beobachter Protokoll doesnt erscheint erst viel später und dann der Ansicht aktualisiert, wie erwartet, sorta. Es hat nicht aktualisieren, wenn ich auf die Schaltfläche geklickt, aber zumindest die Taste vor der API-Antwort geändert kam zurück. Ich hörte auf die App und wieder lief es und im wieder auf die ursprüngliche Frage, es ist nicht zu aktualisieren.

Im mit SingleLiveEvent unverändert von Googles Architektur Proben https://github.com/android/architecture-samples/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/ Baupläne / todoapp / SingleLiveEvent.java

activity_main_login <- es ist ein Fragment nicht Aktivität, aber ich havent Refactoring es noch nicht. Dies wird abgeschnitten, so dass es nicht ohne das Layout Container funktionieren könnte.

<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();
}

Hier ist, was die Protokolle aussehen, wenn es läuft und Sie die Login-Button klicken ...

D/MainViewModel: loginClicked()
D/MainFragment: showLoading changed
D/MainViewModel: login()
Veröffentlicht am 13/01/2020 um 23:52
quelle vom benutzer
In anderen Sprachen...                            


1 antworten

stimmen
0

Nicht, dass ich den Retrofit2-Code enthalten, dass gemacht / erhielt den API-Aufruf, aber es hatte mit dem Gewinde zu tun. Ich wickelte die Methode, die die synchrone Retrofit Ressource genannt in

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

So login () sieht wie folgt aus mehr jetzt

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
        ...
    });
}

Auch wenn der API-Aufruf selbst auf einem eigenen Thread getan werden muss (und war) die ganze Sache nur den UI-Thread höchstwahrscheinlich aufgrund der Thread.Join gehalten (). Das verursachte die Datenbindungen nicht zu aktualisieren. Diese wurden unter Verwendung von RxJava gelöst, aber ich habe nicht realisiert, dass noch und für eine einfache Aufgabe es ist nicht notwendig.

Beantwortet am 15/01/2020 um 01:25
quelle vom benutzer

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