Я использую MVVM и DataBindg в своем приложении. У меня проблема в том, что когда данные будут получены с сервера, мой адаптер recyclerView будет добавлять новые элементы без остановки.
Например, если я получил 15 предметов, recyclerview добавит 15, затем 30, затем 60, ...
Это мой фрагмент ViewModel:
public class ArticlesViewModel extends BaseObservable {
// These observable fields will update Views automatically
public final ObservableList<Article> items = new ObservableArrayList<>();
public final ObservableBoolean dataLoading = new ObservableBoolean(false);
private final AppRepository mTasksRepository;
private final ObservableBoolean mIsDataLoadingError = new ObservableBoolean(false);
private Context mContext; // To avoid leaks, this must be an Application Context.
private static final String TAG = "ArticlesViewModel";
public ArticlesViewModel(
AppRepository repository,
Context context) {
mContext = context.getApplicationContext(); // Force use of Application Context.
mTasksRepository = repository;
}
public void start() {
loadTasks(false);
}
@Bindable
public boolean isEmpty() {
return items.isEmpty();
}
public void loadTasks(boolean forceUpdate) {
loadTasks(forceUpdate, true);
}
public String getSnackbarText() {
return snackbarText.get();
}
private void loadTasks(boolean forceUpdate, final boolean showLoadingUI) {
if (showLoadingUI) {
dataLoading.set(true);
}
mTasksRepository.getArticleList(0, new AppDataSource.LoadDefaultListCallback() {
@Override
public void onTasksLoaded(List list) {
Log.d(TAG, "onTasksLoaded: ");
if (showLoadingUI) {
dataLoading.set(false);
}
mIsDataLoadingError.set(false);
items.clear();
items.addAll(list);
notifyPropertyChanged(BR.empty); // It's a @Bindable so update manually
}
@Override
public void onDataNotAvailable() {
mIsDataLoadingError.set(true);
}
});
}
}
Я проверил эту часть своего кода, и она будет выполнена один раз. А это XML этого фрагмента:
<?xml version = "1.0" encoding = "utf-8"?>
<layout xmlns:android = "http://schemas.android.com/apk/res/android"
xmlns:app = "http://schemas.android.com/apk/res-auto">
<data>
<import type = "android.view.View"/>
<variable
name = "view"
type = "project.article.ArticleFragment"/>
<variable
name = "viewmodel"
type = "project.article.ArticlesViewModel"/>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:orientation = "vertical">
<android.support.v7.widget.RecyclerView
android:id = "@+id/article_recycler_article"
android:layout_width = "match_parent"
android:layout_height = "0dp"
android:layout_weight = "1"
app:items = "@{viewmodel.items}"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintLeft_toLeftOf = "parent"
app:layout_constraintRight_toRightOf = "parent"
app:layout_constraintTop_toBottomOf = "@+id/article_recycler_cat"/>
</android.support.constraint.ConstraintLayout>
</layout>
Я также использую BindingAdapter для установки полученных данных в свой recyclerView.
Это мой класс BindingAdapter:
public class TasksListBindings {
private static final String TAG = "TasksListBindings";
@SuppressWarnings("unchecked")
@BindingAdapter("app:items")
public static void setItems(RecyclerView recyclerView, List<Article> items) {
RecyclerArticleAdapter adapter = (RecyclerArticleAdapter) recyclerView.getAdapter();
Log.d(TAG, "setItems: " + items.size());
adapter.swapData(items); //this part of code will call more than 20 times that makes application to crash.
}
}
И, наконец, это мой адаптер recyclerView для установки в него полученных данных:
public class RecyclerArticleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Article> mainList;
private static final String TAG = "RecyclerArticleAdapter";
public RecyclerArticleAdapter(List<Article> mainList) {
this.mainList = mainList;
Log.d(TAG, "RecyclerArticleAdapter: " + mainList.size());
}
public void swapData(List<Article> dataList) {
if (mainList.size() == 0) {
mainList = dataList;
} else {
mainList.addAll(dataList);
}
notifyDataSetChanged();
}
public List<Article> getList() {
return mainList;
}
public class ItemViewHolder extends RecyclerView.ViewHolder {
private Context context;
private ArticleItemBinding articleItemBinding;
public ItemViewHolder(
ArticleItemBinding binding) {
super(binding.getRoot());
context = itemView.getContext();
articleItemBinding = binding;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ArticleItemBinding binding = DataBindingUtil.inflate(
LayoutInflater.from(parent.getContext()),
R.layout.article_item, parent, false);
ItemViewHolder holder = new ItemViewHolder(binding);
return holder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder rawHolder, final int position) {
final ItemViewHolder holder = (ItemViewHolder) rawHolder;
Article article = mainList.get(position);
holder.articleItemBinding.setArticle(article);
}
@Override
public int getItemCount() {
return mainList.size();
}
}
Я не могу понять, в чем проблема. Я очень ценю твои ответы.
Спасибо.
Кажется, что к recyclerview не прикреплен менеджер по расположению. Вы должны установить менеджер компоновки recyclerview.
андроид: ориентация = "вертикальный" app: layoutManager = "android.support.v7.widget.LinearLayoutManager"
Нет, в
recyclerViewесть LayoutManager. Я установил это в своем фрагменте так:private void setupListAdapter() { RecyclerView recyclerArticle = mArticleFragBinding.articleRecyclerArticle; recyclerArticle.setLayoutManager(new LinearLayoutManager(getActivity())); mListAdapter = new RecyclerArticleAdapter(new ArrayList<Article>(0)); recyclerArticle.setAdapter(mListAdapter); }