非常慢-来自片段的数据绑定更新UI

问题描述 投票:0回答:1

显然,在Android中,我显然没有得到一门科学来进行数据保全。我继续通过片段或视图模型来对抗更新视图,其中某些事情“可以正常工作”,而另一些似乎是无法正常工作的。

我想禁用登录按钮,更改其文本并在单击该按钮后设置Alpha,直到获得API响应,然后再将其更改。可以想象,我不希望用户重复提交身份验证请求。对该片段进行预数据绑定将处理onClick()侦听器,并且我将使用直刀来绑定元素,或者使用findViewById()手动进行绑定。无论哪种方式,当我更改视图时,它几乎都是即时的。现在有了数据绑定,它似乎是偶然的,在某些情况下非常慢,而在另一些情况下却似乎是即时的。我不包括将其更改回原先的代码,因为其一开始并未更改视图。

在写这篇文章时,我一遍又一遍地遇到了同样的问题,按钮从未改变。片段中的观察者被调用(在日志中,它按照我期望被调用的顺序显示),但UI只是不更新​​。我再次在模拟器上运行它,奇怪的是直到很久以后才出现观察者日志,然后按预期方式更新了视图。当我单击按钮时它没有更新,但是至少在API响应返回之前按钮已更改。这并不是很有用,因为单击和ui更改按钮之间的时间仍然可以快速单击。我停止了该应用程序,然后重新运行它,并立即返回到原始问题,它根本没有更新。测试之间未更改代码。

我使用未经Google架构示例修改的SingleLiveEventhttps://github.com/android/architecture-samples/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/SingleLiveEvent.java

activity_main_login

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

这是日志运行时的样子,您单击登录按钮...

D/MainViewModel: loginClicked()
D/MainFragment: showLoading changed
D/MainViewModel: login()
android android-databinding
1个回答
0
投票

不是我包括了可以进行/接收API调用的Retrofit2代码,但它与线程有关。我将调用同步改造资源的方法包装在

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

所以login()现在看起来更像这样

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

尽管API调用本身必须在其自己的线程上完成(并且以前)是由于thread.join()使整个事情最可能阻碍了UI线程。这导致数据绑定不更新。使用RxJava可能已经解决了这个问题,但是我还没有实现它,对于简单的任务,它不是必需的。

© www.soinside.com 2019 - 2024. All rights reserved.