RxJava Room with Flowable: возвращаются только новые строки - PullRequest
0 голосов
/ 29 июня 2018

Мы решили использовать Flowable из RxJava с библиотекой персистентности Room. У нас есть таблицы, в которых контент добавляется сервисами через неопределенные промежутки времени (каждые 2-3 секунды выполняется 2-3 обновления), и строки этой таблицы подписываются в BaseAdapter для внесения изменений в представление в режиме реального времени.

Проблема в том, что, когда происходит какая-либо операция обновления / вставки, мы снова получаем весь список, заставляя базовый адаптер восстановить представление. Также могут быть операции удаления, что делает длину строк бесполезной для нас.

Я хочу спросить, существует ли какой-либо другой оператор, который поддерживает оперативные данные, и вызывает onNext для новых данных и предоставляет полный список операций удаления.

Ответы [ 2 ]

0 голосов
/ 29 июня 2018

подписаны в BaseAdapter

Используйте RecyclerView с детализированными * уведомлениями, такими как notifyItemInserted вместо ListView

Проблема в том, что, когда происходит какая-либо операция обновления / вставки, мы снова получаем весь список

Это вполне ожидаемое поведение как с LiveData<List<T>>, так и с Flowable<List<T>>.

заставляет базовый адаптер восстанавливать вид.

Это потому, что вы не используете DiffUtil или не используете новое дополнение RecyclerView, ListAdapter (которое обрабатывает различие внутри и автоматически)

предоставить полный список операций удаления.

На самом деле он уже предоставляет весь список (конечно, без удаленных элементов).


Решение со стороны AAC заключается в использовании DataSource.Factory<Integer, T> вместо Flowable<List<T>>/LiveData<List<T>>, чтобы вы могли создать LiveData<PagedList<T>> через LivePagedListBuilder, который вы можете установить на PagedListAdapter. Таким образом, он выбирает только заданный размер страницы, а не весь список, и обрабатывает различия.

EDIT:

@Entity(tableName = Task.TABLE_NAME)
public class Task {
    public static DiffUtil.ItemCallback<Task> DIFF_CALLBACK = new DiffUtil.ItemCallback<Task>() {
        @Override
        public boolean areItemsTheSame(@NonNull Task oldItem, @NonNull Task newItem) {
            return oldItem.id == newItem.id;
        }

        @Override
        public boolean areContentsTheSame(@NonNull Task oldItem, @NonNull Task newItem) {
            return oldItem.equals(newItem);
        }
    };

    public static final String TABLE_NAME = "TASK";
    public static final String COLUMN_ID = "task_id";
    public static final String COLUMN_TEXT = "task_text";
    public static final String COLUMN_DATE = "task_date";

и

@Dao
public interface TaskDao {
    @Query("SELECT * FROM " + Task.TABLE_NAME + " ORDER BY " + Task.COLUMN_DATE + " ASC ")
    DataSource.Factory<Integer, Task> tasksSortedByDate();

    // ...
}

и

public class TaskViewModel
        extends ViewModel {
    private final TaskDao taskDao;

    private LiveData<PagedList<Task>> liveResults;

    public TaskViewModel(TaskDao taskDao) {
        this.taskDao = taskDao;
        liveResults = new LivePagedListBuilder<>(taskDao.tasksSortedByDate(),
                                                 new PagedList.Config.Builder() //
                                                         .setPageSize(20) //
                                                         .setPrefetchDistance(20) //
                                                         .setEnablePlaceholders(true) //
                                                         .build())
                .setInitialLoadKey(0)
                .build();
    }

    public LiveData<PagedList<Task>> getTasks() {
        return liveResults;
    }
}

и

public class TaskFragment
        extends Fragment {
    RecyclerView recyclerView;

    // ...

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        recyclerView = view.findViewById(R.id.recycler_view);
        TaskViewModel viewModel = ViewModelProviders.of(this).get(TaskViewModel.class);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
        final TaskAdapter taskAdapter = new TaskAdapter();
        recyclerView.setAdapter(taskAdapter);
        viewModel.getTasks().observe(this, pagedList -> {
            //noinspection Convert2MethodRef
            taskAdapter.submitList(pagedList);
        });
    }

    @Override
    protected void onDestroyView() {
        super.onDestroyView();
        viewModel.getTasks().removeObservers(this);
    }
}

и

public class TaskAdapter
        extends PagedListAdapter<Task, TaskAdapter.ViewHolder> {
    public TaskAdapter() {
        super(Task.DIFF_CALLBACK);
    }
0 голосов
/ 29 июня 2018

Нет, с комнатой нет. Если вы используете Rx с комнатой, вы можете использовать Diff util или вы можете использовать Список Адаптер Также есть вариант под названием SortedListAdapter

Предоставление примера реализации от разработчика Android

@Dao
 interface UserDao {
     @Query("SELECT * FROM user ORDER BY lastName ASC")
     public abstract LiveData<List<User>> usersByLastName();
 }

 class MyViewModel extends ViewModel {
     public final LiveData<List<User>> usersList;
     public MyViewModel(UserDao userDao) {
         usersList = userDao.usersByLastName();
     }
 }

 class MyActivity extends AppCompatActivity {
     @Override
     public void onCreate(Bundle savedState) {
         super.onCreate(savedState);
         MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
         RecyclerView recyclerView = findViewById(R.id.user_list);
         UserAdapter<User> adapter = new UserAdapter();
         viewModel.usersList.observe(this, list -> adapter.submitList(list));
         recyclerView.setAdapter(adapter);
     }
 }

 class UserAdapter extends ListAdapter<User, UserViewHolder> {
     public UserAdapter() {
         super(User.DIFF_CALLBACK);
     }
     @Override
     public void onBindViewHolder(UserViewHolder holder, int position) {
         holder.bindTo(getItem(position));
     }
     public static final DiffUtil.ItemCallback<User> DIFF_CALLBACK =
             new DiffUtil.ItemCallback<User>() {
         @Override
         public boolean areItemsTheSame(
                 @NonNull User oldUser, @NonNull User newUser) {
             // User properties may have changed if reloaded from the DB, but ID is fixed
             return oldUser.getId() == newUser.getId();
         }
         @Override
         public boolean areContentsTheSame(
                 @NonNull User oldUser, @NonNull User newUser) {
             // NOTE: if you use equals, your object must properly override Object#equals()
             // Incorrectly returning false here will result in too many animations.
             return oldUser.equals(newUser);
         }
     }
 }

Или вы можете создать реализацию RXBus, а при вставке данных в базу данных публиковать событие с добавленными / удаленными данными. Подпишитесь на нее, и вы сможете получить то, что хотите.

...