Databinding bijwerken UI fragment middels binding

stemmen
0

Blijkbaar is er een wetenschap om databainding in android waarvan ik duidelijk dont get. Ik blijf belanden vechten uitzicht updaten via het fragment of viewmodel waar sommige dingen gewoon werk anderen zijn schijnbaar niet-functioneel.

Ik wil een login-knop uit te schakelen, wijzigt u de tekst en stel een alfa na zijn geklikt, totdat ik een API respons krijgen dan terug te veranderen ik het. Vrij ongecompliceerd. Im niet met inbegrip van de code die het weer zal veranderen, omdat de stoppen bij het veranderen van het de eerste keer.

Tijdens het schrijven van dit ik hadden hetzelfde probleem keer op keer, op de knop verandert nooit. De waarnemer in het fragment wordt aangeroepen (In het logboek toont in de volgorde waarin ik verwacht dat het zijn genoemd), maar de UI gewoon doesnt-update. Ik stelde het op een emulator weer en herhaaldelijk verschijnen de waarnemer log doesnt pas veel later en dan het uitzicht bijgewerkt zoals verwacht, sorta. Het didnt bijwerken wanneer ik op de knop geklikt, maar in ieder geval op de knop gewijzigd voordat de API respons kwam terug. Ik stopte de app en opnieuw liep het en im terug naar de oorspronkelijke emissie, zijn niet bijgewerkt.

Im met behulp van SingleLiveEvent ongemodificeerde uit Googles architectuur monsters https://github.com/android/architecture-samples/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/ blauwdrukken / todoapp / SingleLiveEvent.java

activity_main_login <- het is een fragment geen activiteit, maar ik havent gerefactored het nog niet. Dit wordt afgekapt, zodat het niet zou kunnen werken zonder een lay-out container.

<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 is wat de logs uitzien wanneer het wordt uitgevoerd en u op de login-knop ...

D/MainViewModel: loginClicked()
D/MainFragment: showLoading changed
D/MainViewModel: login()
De vraag is gesteld op 13/01/2020 om 23:52
bron van user
In andere talen...                            


1 antwoorden

stemmen
0

Niet dat ik onder meer de Retrofit2 code die gemaakt / ontvangen de API-oproep, maar het had te maken met de schroefdraad. Ik wikkelde de methode die de synchrone retrofit bron ingeroepen

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

Dus login () lijkt meer op deze nu

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

Hoewel de API oproep zelf moet worden gedaan op zijn eigen thread (en was) het hele ding gewoon het meest waarschijnlijk hield de UI thread te wijten aan de thread.join (). Dat veroorzaakte de DataBindings niet bij te werken. Dit kan zijn opgelost met behulp van RxJava maar ik heb nog niet zo en voor een eenvoudige taak zijn niet nodig geïmplementeerd.

antwoordde op 15/01/2020 om 01:25
bron van user

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