android - 如何从 2 个 View 模型更新 1 个回收器 View 适配器?

标签 android android-recyclerview android-livedata android-viewmodel

我有 2 个 View 模型观察房间中的 2 个表,每个表都发出实时数据,它们应该在值更改时更新我的​​回收器 View 。我的适配器可以处理多个模型和 View 持有者,但我不确定如何在不覆盖当前数据或复制任何数据的情况下使用新数据更新回收器 View 适配器有什么想法吗?

因此我的适配器采用了一个 Visitable 列表(可访问模式) 我有 2 个对象实现了这个接口(interface),接口(interface)有一个类型,所以我可以告诉它想要什么 View 持有者,我使用 diff utils 更新回收器 View ,它看起来像这样

public class CardAdapter extends RecyclerView.Adapter<BaseViewHolder> {

private final List<Visitable> elements;
private final TypeFactory typeFactory;
private final ItemTouchListener onItemTouchListener;
private final Context context;
private String cardType;
private final String layoutIdentifier;
private static final String TAG = "Adptr-Card";
private String CARD_CLICK_UPDATE = "card_click_update";
private final String[] imageFilePathNames;
private RequestManager glide;


public CardAdapter(List<Visitable> elements, TypeFactory typeFactory, ItemTouchListener onItemTouchListener,
                   Context context,
                   String cardType, String layoutIdentifier, RequestManager glide) {
    this.glide = glide;
    this.elements = elements;
    this.typeFactory = typeFactory;
    this.onItemTouchListener = onItemTouchListener;
    this.context = context;
    this.cardType = cardType;
    this.layoutIdentifier = layoutIdentifier;
    this.imageFilePathNames = context.getResources().getStringArray(R.array.image_set_names);
}

@NonNull
@Override
public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View contactView = LayoutInflater.from(context).inflate(viewType, parent, false);
    return typeFactory.createViewHolder(contactView, viewType, onItemTouchListener, glide, cardType);

}

@Override
public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {
    holder.bind(elements.get(position), position);
}

@Override
public int getItemViewType(int position) {
    return elements.get(position).type(typeFactory);
}

public void setCardType(String cardType) {
    this.cardType = cardType;
    notifyDataSetChanged();

}

@Override
public int getItemCount() {
    return elements.size();
}

public List<Visitable> getList() {
    return elements;
}

public List<Sentence> getSentencesList() {
    ArrayList<Sentence> sentences = new ArrayList<>();
    for (Visitable visitable : elements) {
        if (visitable.type(typeFactory) == CardViewHolder.LAYOUT) {
            sentences.add((Sentence) visitable);
        }
    }
    return sentences;
}

public Visitable getItem(int position) {
    if (position > 0 && position < elements.size()) {
        return elements.get(position);
    }
    return elements.get(0);
}


class CalculateDiffUtils extends AsyncTask<Void, Void, DiffResult> {

    private final List<Visitable> oldCardList;
    private final List<Visitable> newCardList;

    CalculateDiffUtils(List<Visitable> oldCardList, List<Visitable> newCardList) {
        this.oldCardList = oldCardList;
        this.newCardList = newCardList;
    }

    @Override
    protected DiffUtil.DiffResult doInBackground(Void... params) {
        return DiffUtil.calculateDiff(new VisitableDiffUtils(oldCardList, newCardList, typeFactory));
    }

    @Override
    protected void onPostExecute(DiffUtil.DiffResult diffResult) {
        super.onPostExecute(diffResult);
        dispatchUpdates(diffResult, newCardList);

    }
}

private void dispatchUpdates(DiffUtil.DiffResult diffResult, List<Visitable> newCardList) {
    this.elements.clear();
    this.elements.addAll(newCardList);
    diffResult.dispatchUpdatesTo(this);
}

public void refreshDiffUtilsList(List<Visitable> sentences) {
    new CalculateDiffUtils(elements, sentences).execute();
}



public void removeItem(int position) {
    elements.remove(position);
    notifyItemRemoved(position);
}


public void addCard(Sentence sentence) {
    elements.add(getItemCount(), sentence);
    notifyItemInserted(getItemCount());
}

public void addGroup(GroupsWithSentences sentence) {
    elements.add(getItemCount(), sentence);
    notifyItemInserted(getItemCount());
}


public void updateCardClick(int position) {
    notifyItemChanged(position, CARD_CLICK_UPDATE);
}


public void refreshList(List<Visitable> newElements) {
    ArrayList<Visitable> elementArrayList = new ArrayList<>(newElements);
    elements.clear();
    elements.addAll(elementArrayList);
    notifyDataSetChanged();
}

}

我的 2 个 View 模型位于一个 fragment 中,它们从我的 Room 数据库中观察一些数据并在发生变化时进行更新,但这意味着我将永远只有一个 View 模型的数据,我想我想要一种方法结合这些 View 模型可能使用某种中介实时数据,这是我的 2 个 View 模型(为简洁起见,我删除了一些东西,它们都是使用工厂启动的)

组 View 模型

public class GroupViewModel extends ViewModel {

private final GroupRepository groupRepository;
private final LiveData<List<GroupsWithSentences>> groups;

public GroupViewModel(@NonNull Application application, String[] cardArgs) {
    groupRepository = new GroupRepository(application);
    groups = groupRepository.getGroupsByWordDescriptionAndWordType(cardArgs[0],cardArgs[1]);
}

public LiveData<List<GroupsWithSentences>> getGroups() {
    return groups;
}
}

句 subview 模型

public class CardViewModel extends ViewModel {

private final SentenceRepository sentenceRepository;
private final LiveData<List<Sentence>> cards;
private static final String TAG = "view_model";

public CardViewModel(@NonNull Application application , int clicks){
    sentenceRepository = new SentenceRepository(application);
    search = new MutableLiveData<>();
    cardArgs = new MutableLiveData<>();
    cards = Transformations.switchMap(search, mySearch -> sentenceRepository.searchLiveCardListByWordTypeAndWordDescriptionAndSearchWord(getCardArgs()[0],getCardArgs()[1],mySearch));
}

public LiveData<List<Sentence>> getLiveCardList(){
    return cards;
}

}

在我的 fragment 中调用适配器

private void setUpCardViewModelObserver(String[] args) {


        cardViewModel.getLiveCardList().observe(getViewLifecycleOwner(), sentenceList -> {
            if (sentenceList != null) {
                ArrayList<Visitable> list = new ArrayList<>(sentenceList);
                cardAdapter.refreshDiffUtilsList(list);
                checkResults(list.size());
            }
        });


}

private void setUpGroupViewModelObserver() {
    groupViewModel.getGroups().observe(getViewLifecycleOwner(), groupsWithSentencesList -> {
        if (groupsWithSentencesList != null) {
            ArrayList<Visitable> list = new ArrayList<>(groupsWithSentencesList);
            cardAdapter.refreshDiffUtilsList(list);
            checkResults(groupsWithSentencesList.size());
        }
    });
}

欢迎任何帮助,非常感谢。

最佳答案

所以答案是使用 Mediator Live 数据,我设置新的中介者实时数据来响应对我现有的实时数据对象的更改,然后调解这些更改,所以我现在只有一个数据流,所以我现在的卡片 View 模型看起来像这样

public CardViewModel(@NonNull Application application , int clicks, String[] cardArgs){
    sentenceRepository = new SentenceRepository(application);
    search = new MutableLiveData<>();
    cards = Transformations.switchMap(search, mySearch -> sentenceRepository.searchLiveCardListByWordTypeAndWordDescriptionAndSearchWord(cardArgs[0],cardArgs[1],mySearch));
    groupRepository = new GroupRepository(application);
    groups = groupRepository.getGroupsByWordDescriptionAndWordType(cardArgs[0],cardArgs[1]);
    sentencesAndGroups = new MediatorLiveData<>();

    sentencesAndGroups.addSource(cards, sentences -> {
        sentencesAndGroups.setValue(combineLatest(sentences, groups.getValue()));
    });

    sentencesAndGroups.addSource(groups, groupsWithSentences -> {
        sentencesAndGroups.setValue(combineLatest(cards.getValue(), groupsWithSentences));
    });

}

我的新组合最新方法如​​下所示

private List<Visitable> combineLatest(List<Sentence> sentenceList, List<GroupsWithSentences> groupsWithSentences) {
    List<Visitable> visitableList = new ArrayList<>();
    if (sentenceList != null){
        visitableList.addAll(sentenceList);
    }
    if (groupsWithSentences != null){
        visitableList.addAll(groupsWithSentences);
    }
    return visitableList;
}

关于android - 如何从 2 个 View 模型更新 1 个回收器 View 适配器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58716381/

相关文章:

android - 如何读取存储在内存中的图像文件?

java - 如何让RecyclerView重复列表

android - 在 recyclerview 中填充 GridView

android - Retrofit LiveDataCallAdapter 不调用函数 adapt(call)

android - 为什么 LiveData 还要通知处于 onPause 状态的 Activity?

android - 用于数据绑定(bind)的 LiveData 与 ObservableField

android - 如何获得活跃下载?

java - Retrofit : NPE , 尝试在空对象引用上调用接口(interface)方法(仅限发行版)

Android - 使用过多的线性布局

android - RecyclerView 挂起主线程有很多元素