wake-up-neo.net

RecyclerView wird auf dem BenachrichtigungsdataSetChanged-Bildschirm im Chat nach oben verschoben

Ich versuche, eine Messaging-Art von Bildschirm mithilfe von recyclerView zu erstellen, die von unten beginnt und mehr Daten lädt, wenn der Benutzer das obere Ende des Chats erreicht hat. Aber ich stehe vor diesem seltsamen Thema. 

My recyclerView führt einen Bildlauf nach oben durch, wenn notifyDataSetChanged aufgerufen wird. Aufgrund dessen wird onLoadMore mehrfach aufgerufen.

Hier ist mein Code:

LinearLayoutManager llm = new LinearLayoutManager(context);
llm.setOrientation(LinearLayoutManager.VERTICAL);
llm.setStackFromEnd(true);
recyclerView.setLayoutManager(llm);

** Im Adapter

 @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (messages.size() > 8 && position == 0 && null != mLoadMoreCallbacks) {
        mLoadMoreCallbacks.onLoadMore();
    }

** In Aktivität

@Override
public void onLoadMore() {
    // Get data from database and add into arrayList
      chatMessagesAdapter.notifyDataSetChanged();
}

Es ist nur so, dass RecyclerView nach oben scrollen kann. Wenn Sie bis zum oberen Rand blättern, wird dieses Problem behoben. Bitte helfen Sie mir, die Ursache dieses Problems herauszufinden. Danke im Voraus.

11
user1288005

Sie sehen, es ist ganz natürlich, dass List beim Einfügen neuer Elemente zum obersten Element blättert. Nun, Sie gehen in die richtige Richtung, aber ich glaube, Sie haben das Hinzufügen vonsetReverseLayout(true)vergessen. 

Hier gibt setStackFromEnd(true) lediglich List an, Elemente vom unteren Rand der Ansicht aus zu stapeln. Wenn sie jedoch in Kombination mit setReverseLayout(true) verwendet wird, wird die Reihenfolge der Elemente und Ansichten umgekehrt, sodass das neueste Element immer unten in der Ansicht angezeigt wird.

Ihr endgültiger LayoutManager sieht in etwa so aus:

        mLayoutManager = new LinearLayoutManager(getActivity());
        mLayoutManager.setReverseLayout(true);
        mLayoutManager.setStackFromEnd(true);
        mRecyclerView.setLayoutManager(mLayoutManager);
2
Keivan Esbati

Ich denke, Sie sollten onBindViewHolder nicht auf diese Weise verwenden. Entfernen Sie den Code. Der Adapter sollte nur Modelldaten binden und nicht den Bildlauf überwachen.

Ich mache das "onLoadMore" normalerweise auf diese Weise:

In der Aktivität:

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;
}

Dies funktioniert perfekt für mich und das "totalLoaded" wird verwendet, wenn der Server keine weiteren Nachrichten zurückgibt, um keine Serveraufrufe mehr durchzuführen. Ich hoffe es hilft dir.

2
Borja

Auf diese Weise kann ich vermeiden, dass die Bildlaufansicht nach oben verschoben wird. Anstelle von notifyDataSetChanged () verwende ich notifyItemRangeChanged ().

List<Object> tempList = new ArrayList<>();
tempList.addAll(mList);
mList.clear();
mList.addAll(tempList);
notifyItemRangeChanged(0, mList.size());

Update: Aus einem anderen Grund ist Ihre andere Ansicht oben fokussiert, sodass sie beim Aufrufen von Benachrichtigungen nach oben springt. Entfernen Sie daher alle Fokusse, indem Sie Android hinzufügen: focusableInTouchMode = "true" in der Gruppenansicht.

1

Rufen Sie NICHT notifyDataSetChanged() für die RecyclerView auf. Verwenden Sie die neuen Methoden wie notifyItemChanged(), notifyItemRangeChanged(), notifyItemInserted() etc ... Und wenn Sie notifyItemRangeInserted()-- verwenden

rufen Sie danach keine setAdapter()-Methode auf ..!

0
Shobhit

Sie müssen den Artikel in einem bestimmten Bereich benachrichtigen 

   @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());

    }
0
Harsh Singhal

Sie müssen den Artikel in einem bestimmten Bereich wie folgt benachrichtigen:

       @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());

        }
0

Checkout Firebase Friendlychat Quellcode auf Github .

Es verhält sich wie Sie wollen, besonders bei:

    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);
            }
        }
    });
0
gustavogbc

Sie haben dieses Problem, weil jedes Mal, wenn Ihre Bedingung erfüllt ist, Sie die Variable loadMore aufrufen, auch wenn die Variable loadMore ausgeführt wurde. Um dieses Problem zu lösen, müssen Sie einen booleschen Wert in Ihren Code eingeben und diesen ebenfalls überprüfen. 

Überprüfen Sie meinen folgenden Code, um klarer zu werden.

1- deklarieren Sie einen booleschen Wert in Ihrer Adapterklasse

2- Setzen Sie es in Ihrem Zustand auf "true"

3- Setzen Sie den Wert auf "false", nachdem Sie Daten aus der Datenbank erhalten und Ihren Adapter benachrichtigt haben.

ihr Code muss also wie folgt aussehen:

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

}

in Aktivität:

@Override
public void onLoadMore() {
      // Get data from database and add into arrayList
      chatMessagesAdapter.notifyDataSetChanged();

      chatMessagesAdapter. setLoadingDataInProgress(false);
}

Dies muss Ihr Problem beheben, aber ich ziehe es vor, loadMore in der Activity- oder Presenter-Klasse mit dem Set addOnScrollListener auf RecyclerView zu behandeln und zu prüfen, ob findFirstVisibleItemPosition in LayoutManager den Wert 0 hat und dann Daten zu laden.

Ich habe eine -Bibliothek für die Paginierung geschrieben.

PS: Da andere Benutzer erwähnt wurden, sollte notifyDataSetChanged nicht verwendet werden, da alle Ansichten aktualisiert werden, einschließlich sichtbarer Ansichten, die nicht aktualisiert werden sollen. Verwenden Sie stattdessen notifyItemRangeInsert. In Ihrem Fall müssen Sie die Größe der geladenen Daten aus der Datenbank mit 0 angeben. Wenn Sie von oben laden, ändert notifyDataSetChanged die Bildlaufposition an die Spitze der neu geladenen Daten. Sie MÜSSEN notifyItemRangeInsert verwenden, um ein gutes Gefühl in Ihrer App zu erhalten

0

Ich verlasse mich bei solchen Dingen nicht auf onBindViewHolder. Es kann mehrmals für eine Position aufgerufen werden. Für die Listen, die mehr Optionen enthalten, sollten Sie nach dem Aufblähen Ihres Recyclingberichts so etwas verwenden.

    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();
                }
            }
        }
    });

Ich hoffe es hilft.

0
letitthebee

Ich empfehle Ihnen, die notifyItemRangeInserted-Methode von RecyclerView.Adapter für LoadMore-Vorgänge zu verwenden. Sie fügen Ihrer Liste einen Satz neuer Elemente hinzu, sodass Sie nicht das gesamte Dataset benachrichtigen müssen.

notifyItemRangeInserted(int positionStart, int itemCount)

Benachrichtigen Sie alle registrierten Beobachter darüber, dass itemCount Elemente ab PositionStart wurden neu eingefügt.

Weitere Informationen erhalten Sie unter: https://developer.Android.com/reference/Android/support/v7/widget/RecyclerView.Adapter.html

0
savepopulation