如何使用 RxJava 或 Retrofit2 在使用 ApiRest 的 AutoCompleteTextView Adapter 中返回 FilterResults? [英] How to return FilterResults in AutoCompleteTextView Adapter consuming ApiRest with RxJava or Retrofit2?

查看:117
本文介绍了如何使用 RxJava 或 Retrofit2 在使用 ApiRest 的 AutoCompleteTextView Adapter 中返回 FilterResults?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个由 ApiRest 填充的 autocompleteTextView 适配器.我正在使用 rxJava 和 Retrofit 2. 但无法获得过滤结果,因为我不知道如何在异步函数中返回值.这是我的代码

I am coding an autocompleteTextView adapter which is filled by an ApiRest. I'm using rxJava and Retrofit 2. but cannot get the filtered result because i dont know how to return the value in asynchronous function. here is my code

public class DiagnosticoAutoCompleteAdapter extends BaseAdapter implements Filterable {
...
@Override
public Filter getFilter() {
    Filter filter = new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) {

            final FilterResults filterResults= new FilterResults();
            if(charSequence!=null) {
                ApiUtils.getAPIServiceDos()
                        .getDiagnosticos(charSequence.toString())
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Observer<List<Diagnostico>>() {
                            @Override
                            public void onSubscribe(Disposable d) {

                            }

                            @Override
                            public void onNext(List<Diagnostico> value) {
// HERE IT SHOWS ME THE SIZE E.G. 45 so The values are received correctly
                                System.out.println("tamaño diagnostico::"+value.size());
// HERE IT SHOWS ME THE OBJECT NAME IN POSITION 0 AND ITS OK                                   
 System.out.println("contenido diagg...."+value.get(0).getNombre());
                                filterResults.values=value;
                                filterResults.count=value.size();
                            }

                            @Override
                            public void onError(Throwable e) {

                            }

                            @Override
                            public void onComplete() {

                            }
                        });
            }


//here i lost the information. the count is 0
            System.out.println("tamaño de filtered results::"+filterResults.count);
            return filterResults;
        }

RxJava 请求工作正常,但无法返回值.

The RxJava request works OK but cannot return the values.

我的问题是如何返回过滤后的结果??

My question is how to return the filtered results??

推荐答案

问题是您正在执行异步操作,而 API 预期是同步操作,这意味着您正在启动异步操作,同时立即返回空 FilterResults,异步操作并没有坐等结果,然后将其返回到 performFiltering 方法中,因此异步操作的结果(在 Observer 中).onNext) 在您已经返回空的 FilterResults 之后发生变化.

The problem is that you're performing asynchronous operation where the API expected synchronous one, meaning you're launching a the async operation, while returning immediately the empty FilterResults, the async operation didn't sits and wait to the result before returning it back inside the performFiltering method, thus the result from the async operation (inside the Observer.onNext) is changed after you've already return empty FilterResults.

Filter 对象是抽象类,它已经完成了在后台线程上进行实际工作的繁重工作,performFiltering 在工作线程中调用的方法,你应该在UI线程中处理结果在 publishResults 方法.

Filter object is abstract class that already do the heavy lifting of doing the actual work on background thread, performFiltering method invoked in a worker thread, and you should handle the results in the UI thread at publishResults method.

此 API 并不完全适合 RxJava 反应式模型,您可以直接在 performFiltering 处调用服务器调用,并返回在工作线程中调用的结果.
如果你想要 RxJava,你可以通过将流转换为阻塞流并返回结果来实现:

This API is not exactly fits to RxJava reactive model, you can invoke the server call directly at performFiltering and return the result as it's invoked in a worker thread.
If you want RxJava, you can do it by converting the stream to a blocking one and returns the result:

 @Override
 protected FilterResults performFiltering(CharSequence charSequence) {

     final FilterResults filterResults = new FilterResults();
     if (charSequence != null) {
         List<Diagnostico> value = ApiUtils.getAPIServiceDos()
                 .getDiagnosticos(charSequence.toString())
                 .toBlocking()
                 .first();
         System.out.println("tamaño diagnostico::" + value.size());
         System.out.println("contenido diagg...." + value.get(0).getNombre());
         filterResults.values = value;
         filterResults.count = value.size();
     }
     return filterResults;
 }

为什么不应该在 publishResults 触发异步请求:

Why you should not fire the async request at publishResults:

publishResults 执行请求将起作用,因为它是为您设计的,在您获得结果后更新 UI(可能通知适配器),因此在 bg 中执行请求后,您将返回主线程并更新适配器.

performing the request at publishResults will work as it's designed for you to update the UI after you have the results (probably notify the adapter), so after you perform the request in bg you return to main thread and update the adapter.

但是,它会引入一些错误,因为您没有绑定到正确的过滤生命周期,这意味着进度指示将立即消失,并且不会在您在后台实际获取结果时显示,此外,更严重的问题,当多个请求被触发时会导致错误,因为较早的请求可能会在较晚的请求之后到达并使用旧数据更新适配器.这就是为什么您需要遵守过滤器 API 并在 performFiltering 处以阻塞方式执行请求.

BUT, it will introduce some bugs, as you're not bound to the correct lifecycle of filtering, that means that the progress indication will disappear immediately, and will not shown while you actually fetch the result in the background, additionally, more sever problem, it will cause bugs when multiple requests are fired, as earlier request might arrive after later one and update the adapter with old data. that's why you need to obey the filter API and perform the request in blocking fashion at the performFiltering.

这篇关于如何使用 RxJava 或 Retrofit2 在使用 ApiRest 的 AutoCompleteTextView Adapter 中返回 FilterResults?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆