我正在尝试使用recyclelerView创建消息类型的屏幕,它将从底部开始,并在用户到达聊天的最高点时加载更多数据。但我正面临着这个奇怪的问题。
我的recyclerView在调用notifyDataSetChanged时滚动到顶部。由于这个onLoadMore被多次调用。
这是我的代码:
LinearLayoutManager llm = new LinearLayoutManager(context);
llm.setOrientation(LinearLayoutManager.VERTICAL);
llm.setStackFromEnd(true);
recyclerView.setLayoutManager(llm);
**在适配器
中 @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (messages.size() > 8 && position == 0 && null != mLoadMoreCallbacks) {
mLoadMoreCallbacks.onLoadMore();
}
**活动
@Override
public void onLoadMore() {
// Get data from database and add into arrayList
chatMessagesAdapter.notifyDataSetChanged();
}
只是RecyclerView滚动到顶部。如果滚动到顶部停止,则此问题将得到解决。请帮我弄清楚这个问题的原因。提前谢谢。
答案 0 :(得分:2)
您可以看到,List
在插入新项目时滚动到最顶层的项目是很自然的。那么你朝着正确的方向前进,但我想你忘了添加 setReverseLayout(true)
。
此处setStackFromEnd(true)
只是告诉List
从视图底部开始堆叠项目,但与setReverseLayout(true)
结合使用时,它将颠倒项目和视图的顺序,以便最新项目始终显示在视图的底部。
你的最终layoutManager似乎是这样的:
mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
mRecyclerView.setLayoutManager(mLayoutManager);
答案 1 :(得分:2)
我认为你不应该以这种方式使用onBindViewHolder,删除该代码,适配器应该只绑定模型数据,而不是监听滚动。
我经常做" onLoadMore"这样:
在活动中:
private boolean isLoading, totallyLoaded; //
RecyclerView mMessages;
LinearLayoutManager manager;
ArrayList<Message> messagesArray;
MessagesAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
mMessages.setHasFixedSize(true);
manager = new LinearLayoutManager(this);
manager.setStackFromEnd(true);
mMessages.setLayoutManager(manager);
mMessages.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (manager.findFirstVisibleItemPosition() == 0 && !isLoading && !totallyLoaded) {
onLoadMore();
isLoading = true;
}
}
});
messagesArray = new ArrayList<>();
adapter = new MessagesAdapter(messagesArray, this);
mMessages.setAdapter(adapter);
}
@Override
public void onLoadMore() {
//get more messages...
messagesArray.addAll(0, moreMessagesArray);
adapter.notifyItemRangeInserted(0, (int) moreMessagesArray.size();
isLoading = false;
}
这对我而言是完美的,并且&#34;完全已加载&#34;如果服务器没有返回更多消息,则停止进行服务器调用。希望它可以帮到你。
答案 2 :(得分:1)
这是我避免滚动视图移至顶部的方法 而不是使用notifyDataSetChanged(),而是使用notifyItemRangeChanged();
List<Object> tempList = new ArrayList<>();
tempList.addAll(mList);
mList.clear();
mList.addAll(tempList);
notifyItemRangeChanged(0, mList.size());
更新: 出于另一个原因,您顶部的另一个视图正在聚焦,因此在您调用任何通知时它将跳至顶部,因此可以通过在GroupView中添加android:focusableInTouchMode =“ true”来删除所有聚焦。
答案 3 :(得分:0)
我不依赖onBindViewHolder来做这些事情。它可以被多次调用一个位置。对于有更多选项的列表,也许你应该在recyclelerview膨胀之后使用类似的东西。
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if ((((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition() == 0)) {
if (args.listModel.hasMore && null != mLoadMoreCallback && !loadMoreStarted) {
mLoadMoreCallbacks.onLoadMore();
}
}
}
});
希望它有所帮助。
答案 4 :(得分:0)
我建议您使用notifyItemRangeInserted
RecyclerView.Adapter
方法进行LoadMore
操作。您将一组新项目添加到列表中,因此您无需通知整个数据集。
notifyItemRangeInserted(int positionStart, int itemCount)
通知任何已注册的观察者当前反映的itemCount 已经新插入了从positionStart开始的项目。
了解更多信息: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html
答案 5 :(得分:0)
请勿致电notifyDataSetChanged()
上的RecyclerView
。使用notifyItemChanged()
,notifyItemRangeChanged()
,notifyItemInserted()
等新方法...
如果你使用notifyItemRangeInserted()
-
之后不要调用setAdapter()
方法..!
答案 6 :(得分:0)
你有这个问题,因为每次你的条件成立时你调用loadMore
方法即使loadMore
处于运行状态,为了解决这个问题,你必须在你的代码中加一个布尔值并检查一下。
检查我的以下代码,以便更清楚。
1-在适配器类中声明一个布尔值
2-在你的情况下将其设置为true
3-从数据库获取数据并通知适配器后将其设置为false。
因此您的代码必须如下代码所示:
public class YourAdapter extend RecylerView.Adapter<.....> {
private boolean loadingDataInProgress = false;
public void setLoadingDataInProgress(boolean loadingDataInProgress) {
this.loadingDataInProgress = loadingDataInProgress
}
....
// other code
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (messages.size() > 8 && position == 0 && null != mLoadMoreCallbacks && !loadingDataInProgress){
loadingDataInProgress = true;
mLoadMoreCallbacks.onLoadMore();
}
......
//// other adapter code
}
在活动中:
@Override
public void onLoadMore() {
// Get data from database and add into arrayList
chatMessagesAdapter.notifyDataSetChanged();
chatMessagesAdapter. setLoadingDataInProgress(false);
}
这必须解决您的问题,但我更喜欢在loadMore
上设置addOnScrollListener
的Activity或Presenter类中处理RecyclerView
,并检查findFirstVisibleItemPosition
中的LayoutManager
是否notifyDataSetChanged
为0然后加载数据。
我写了一个library for pagination,随意使用或自定义。
PS:正如其他提及的用户不使用notifyItemRangeInsert
,因为这会刷新所有视图,包括您不想刷新的视图,而是使用notifyDataSetChanged
,在您的情况下,您必须从0通知从数据库加载数据的大小。
在您从顶部加载的情况下,notifyItemRangeInsert
会将滚动位置更改为新加载数据的顶部,因此您必须使用.tab-item-active
才能在应用中获得良好感觉
答案 7 :(得分:0)
您需要保持特定范围内的项目,如下所示:
@Override
public void onLoadMore() {
// Get data from database and add into arrayList
List<Messages> messegaes=getFromDB();
chatMessagesAdapter.setMessageItemList(messages);
// Notify adapter with appropriate notify methods
int curSize = chatMessagesAdapter.getItemCount();
chatMessagesAdapter.notifyItemRangeInserted(curSize,messages.size());
}
答案 8 :(得分:0)
在Github上查看Firebase Friendlychat源代码。
它表现得像你想要的那样,特别是在:
mFirebaseAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
int friendlyMessageCount = mFirebaseAdapter.getItemCount();
int lastVisiblePosition = mLinearLayoutManager.findLastCompletelyVisibleItemPosition();
// If the recycler view is initially being loaded or the user is at the bottom of the list, scroll
// to the bottom of the list to show the newly added message.
if (lastVisiblePosition == -1 ||
(positionStart >= (friendlyMessageCount - 1) && lastVisiblePosition == (positionStart - 1))) {
mMessageRecyclerView.scrollToPosition(positionStart);
}
}
});
答案 9 :(得分:0)
您需要保持特定范围内的项目
@Override
public void onLoadMore() {
// Get data from database and add into arrayList
List<Messages> messegaes=getFromDB();
chatMessagesAdapter.setMessageItemList(messages);
// Notify adapter with appropriate notify methods
int curSize = chatMessagesAdapter.getItemCount();
chatMessagesAdapter.notifyItemRangeInserted(curSize,messages.size());
}