java - 使用 Retrofit/Rxjava 进行数据绑定(bind)/实时数据处理配置更改

标签 java android retrofit rx-java2 mutablelivedata

请看一下这段代码:

主要 Activity :

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        MutableLiveData<User> mutableUser = new MutableLiveData<>();
        mutableUser.setValue(new User("John","Gordon","Homeless"));

        activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        activityMainBinding.setHandler(new MainActivityHandler());

        activityMainBinding.setLifecycleOwner(this);
        activityMainBinding.setUser(mutableUser);

        setSupportActionBar(activityMainBinding.toolbar);
    }

MutableLiveData在xml布局中定义:

<variable name="user" type="android.arch.lifecycle.MutableLiveData&lt;test.databindingtemplate.ViewModels.User&gt;"/ >

用户的每个字段都通过数据绑定(bind)绑定(bind)到控件:

<EditText
                android:id="@+id/editTextName"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginBottom="8dp"
                android:layout_marginEnd="8dp"
                android:layout_marginStart="8dp"
                android:layout_marginTop="8dp"
                android:ems="10"
                android:inputType="textPersonName"
                android:text="@={user.firstName}"
                app:layout_constraintBottom_toTopOf="@+id/textViewSecondName"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/textViewSecondName"
                app:layout_constraintTop_toTopOf="parent"/>

这工作正常,配置更改被跟踪并填充到 GUI(例如,当我在“名称”字段中输入某些内容时,屏幕旋转时值仍然存在)。

接下来,我想从其余 Web 服务 - Retrofit/RxJava 实现刷新用户详细信息,并且我想在数据加载过程中显示繁忙指示器,例如 onCreate方法:

showBusyIndicator(); 
testService.getUserDetails(headers)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(user ->
                {
                  hideBusyIndicator();
                  activityMainBinding.getUser().setValue(user);
                }, throwable -> 
                {
                    Log.d(TAG, "ERROR loading user");
                    hideBusyIndicator();
                });

现在我不确定如何正确处理配置更改 - 当显示忙碌指示器时,应该在屏幕旋转更改后重新创建它。如MutableLiveData很好地处理配置更改,我无法找到任何解决方案(除了“经典”方式)来解决这种情况下加载指示器和处理结果的问题。

你能给我指出正确的方向吗?

[编辑] getUserDetails 声明:

@NonNull
@GET("/user")
Observable<User> getUserDetails(@HeaderMap Map<String, String> headers);

@user8035311

我修改了您的 github 示例,以在单击按钮时触发模拟数据加载,这样(按钮已添加到布局中):

@Override
    protected void onCreate(@Nullable Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        this.progressDialog = new ProgressDialog(this);
        this.progressDialog.setMessage("Loading...");

        final ActivityMainBinding mainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        mainBinding.setLifecycleOwner(this);

        mainBinding.button2.setOnClickListener(view ->
        {
            RxViewModel.RxViewModelFactory factory = new RxViewModel.RxViewModelFactory();
            final RxViewModel model = ViewModelProviders.of(MainActivity.this, factory).get(RxViewModel.class);
            LiveData<User> liveData = model.getLiveData();
            progressDialog.show();
            liveData.observe(MainActivity.this, s ->
            {
                progressDialog.dismiss();
                mainBinding.setUser(s);
            });

        });
    }

但这不起作用。任务在屏幕旋转时中断,但有异常(exception):

06-27 09:05:18.737 11829-11829/app.rxrotation.com.architecturecomponentsrxrotation E/WindowManager: android.view.WindowLeaked: Activity app.rxrotation.com.architecturecomponentsrxrotation.MainActivity has leaked window DecorView@5b16e38[] that was originally added here at android.view.ViewRootImpl.(ViewRootImpl.java:485) at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:346) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93) at android.app.Dialog.show(Dialog.java:330) at app.rxrotation.com.architecturecomponentsrxrotation.MainActivity.lambda$onCreate$1$MainActivity(MainActivity.java:35) at app.rxrotation.com.architecturecomponentsrxrotation.MainActivity$$Lambda$0.onClick(Unknown Source:4) at android.view.View.performClick(View.java:6294) at android.view.View$PerformClick.run(View.java:24770) at android.os.Handler.handleCallback(Handler.java:790) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6494) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

我第二次点击按钮后,数据加载甚至没有执行。

最佳答案

您可以将 ViewModelLiveData 一起使用,以在配置更改后保留异步任务。因此,您的 LiveData 可能如下所示:

public class UserLiveData extends LiveData<User> {
    public UserLiveData() {
        setValue(new User());
    }

    public UserLiveData(Headers headers) {
        Observable<User> observable = Observable.defer(new Callable<ObservableSource<? extends User>>() {
            @Override
            public ObservableSource<? extends User> call() throws Exception {
                User user = testService.getUserDetails(headers);
                return Observable.just(user);
            }
        });

        observable.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeWith(new DefaultObserver<String>() {
                @Override
                public void onNext(User value) {
                    setValue(value);
                }

                @Override
                public void onError(Throwable e) {
                    throw new RuntimeException(e);
                }

                @Override
                public void onComplete() {

                }
        });
    }
}

然后,您的 UserDetailsViewModel 如下:

public class UserDetailsViewModel extends ViewModel {
    private LiveData<User> userLiveData;

    public UserDetailsViewModel() {
        userLiveData = new UserLiveData();    
    }

    public void observeLiveDate(LifecycleOwner owner,
                              Observer<User> observer) {
        userLiveData.observe(owner, observer);
    }

    public void loadLiveData(Headers headers) {
        userLiveData = new UserLiveData(someArgs);
    }
}

然后您的 MainActivity 可能如下所示:

public class MainActivity extends AppCompatActivity {
    private ProgressDialog progressDialog;
    private UserViewModel viewModel;
    private ActivityMainBinding mainBinding;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.progressDialog = new ProgressDialog(this);
        this.progressDialog.setMessage("Loading...");

        mainBinding = DataBindingUtil.setContentView(this,
            R.layout.activity_main);
        mainBinding.setLifecycleOwner(this);

        viewModel = ViewModelProviders.of(this).get(UserViewModel.class);

        observeLiveData();
        mainBinding.button2.setOnClickListener(v -> {
            viewModel.initLiveData(<your headers>);
            observeLiveData();
        });
    }

    private void observeLiveData() {
        progressDialog.show();
        progressDialog.setCanceledOnTouchOutside(false);
        viewModel.observeRxLiveDate(this, user -> {
            progressDialog.dismiss();
            mainBinding.setUser(user);
        });
    }
}

我创建了一个非常简单的示例here

关于java - 使用 Retrofit/Rxjava 进行数据绑定(bind)/实时数据处理配置更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50831532/

相关文章:

java - JAVA中多个选中复选框的总和

java - 获取java sql时间并将其插入到表中

java - 请求相机权限会导致 String.equals 中出现 NullPointerException

android - OKHttp 监听连接状态

java - 下载带有 json 数据的图像(retrofit2 android)

kotlin - 如何通过改造阻塞客户端和协程实现有限调用

java.lang.IllegalStateException : No Hibernate Session bound to thread

java - IntelliJ-java : Cannot find JDK '1.8'

java - 如何修复 ProGuard 错误

android - 如何使recyclerview显示所有项目并且无法滚动