簡體   English   中英

如何保持 FirebaseRecyclerAdapter 的滾動位置

[英]How to maintain scroll position of FirebaseRecyclerAdapter

當我從另一個活動返回到同一活動時,我試圖保持我的FirebaseRecyclerAdapter的滾動位置。

這是我設置FirebaseRecyclerAdapter的函數

public void setTheScreen(){
   FirebaseRecyclerAdapter<Post,PostViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Post,PostViewHolder>(
           Post.class,
           R.layout.post_display_blueprint,
           PostViewHolder.class,
           postsNode
   ) {
       @Override
       public void onDataChanged() {
           if(dialog != null && dialog.isShowing()){
               dialog.dismiss();
           }
       }

       @Override
       protected void populateViewHolder(final PostViewHolder viewHolder, Post model, int position) {
           final String key = getRef(position).getKey();
           mRefPosts = FirebaseDatabase.getInstance().getReference().child("posts").child(key);
           mLoveNode = mRef.child("loves");
           mRefLoves = mRef.child("loves").child(key);
           viewHolder.setTitle(model.getTitle());
           viewHolder.setLoves(mRefLoves);
           viewHolder.setLoveButton(Uid,key);
           viewHolder.setImage(getApplicationContext(),model.getImageUrl());


           mRefPosts.addValueEventListener(new ValueEventListener() {
               @Override
               public void onDataChange(DataSnapshot dataSnapshot) {

                   String isAnonymous = dataSnapshot.child("anonymous").getValue(String.class);
                   if (isAnonymous != null && isAnonymous.equals("true")) {
                       viewHolder.anonymousButton.setVisibility(View.VISIBLE);
                   }

               }
               @Override
               public void onCancelled(DatabaseError databaseError) {

               }
           });


            viewHolder.mView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    Intent intent = new Intent(MainActivity.this,PostDisplayPageActivity.class);
                    intent.putExtra("Key",key);
                    startActivity(intent);

                }
            });
       }
   };
   mRecyclerView.setAdapter(firebaseRecyclerAdapter);
    firebaseRecyclerAdapter.notifyDataSetChanged();

}

通過單擊適配器創建的任何視圖,我將從我的MainActivity轉到一個名為PostDisplayPageActivity的新活動,然后按回鍵我將完成PostDisplayPageActivity並返回到MainActivity

當我回到我的 MainActivity 時,列表從 0 位置開始

我在我的 onPause 和 onResume 方法中使用了以下代碼,但它不起作用。

 @Override
protected void onPause() {
    super.onPause();

    currentVisiblePosition = ((LinearLayoutManager)mRecyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
    Toast.makeText(MainActivity.this,String.valueOf(currentVisiblePosition),Toast.LENGTH_SHORT).show();

}

@Override
protected void onResume() {
    super.onResume();

    setTheScreen();
    mRecyclerView.getLayoutManager().scrollToPosition(currentVisiblePosition);
    Toast.makeText(MainActivity.this,String.valueOf(currentVisiblePosition),Toast.LENGTH_SHORT).show();
    currentVisiblePosition = 0;


}

從那 2 個Toasts中,我得到了正確的位置,但視圖總是從位置 0 開始。

對於我的RecyclerView ,我使用LinearLayoutManager作為mRecyclerView.setLayoutManager(mLinearLayoutManager);

有人請告訴我我做錯了什么或建議我用不同的方法來做到這一點。

我用一個更簡單的解決方案解決了我的問題。 我剛剛調用了 adapter.startListening(); 在 onViewCreated() 而不是 onStart 中調用 adapter.stopListening(); 在 onDestroyView() 而不是 onStop() 中,這阻止了整個列表在從下一個活動返回時重新生成,從而保留了以前的滾動位置。

面對同樣的問題,我發現了許多對我不起作用的建議。 因此,我想出了一個解決這個問題的方法,即恢復Firebase RecyclerView狀態/滾動位置。

在實現Firebase RecyclerView的 Activity/Fragment 中保留一個 RecyclerView instanceStateFirebaseRecycler實例狀態的字段:

private Parcelable instanceStateFirebaseRecycler;

首先,保存 Firebase RecyclerView 的實例狀態instanceStateFirebaseRecycler ,它保留滾動位置信息, onPause()

@Override
public void onPause() {
    saveScrollPosition();
    super.onPause();
}

其中saveScrollPosition()方法很簡單:

private void saveScrollPosition(){
    instanceStateFirebaseRecycler = firebaseRecyclerView.getLayoutManager().onSaveInstanceState();
}

接下來是棘手的部分,您向Firebase Adapter添加一個偵聽器,它會在適配器准備就緒時通知您,也就是說,當getItemCount()不為零時。 在偵聽器的回調中,您恢復回收器的狀態/滾動位置:

firebaseAdapter = new FirebaseAdapter(options, new FirebaseAdapter.OnRestoreRecyclerStateListener() {
        @Override
        public void onRestoreRecyclerState() {
            restoreScrollPosition();
        }
    });
    firebaseRecyclerView.setAdapter(firebaseAdapter);

自定義interface只是:

public interface OnRestoreRecyclerStateListener {
    void onRestoreRecyclerState();
}

並在Firebase Adapter onBindViewHolder中觸發callback (我沒有找到更好的位置)以確保適配器項已准備就緒:

@Override
protected void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull MyModel model) {
    ...
    onRestoreRecyclerStateListener.onRestoreRecyclerState();
}

,並且restoreScrollPosition()方法是:

private void restoreScrollPosition(){
    if (instanceStateFirebaseRecycler == null) return;
    firebaseRecyclerView.getRootView().setVisibility(View.GONE);
    final Handler handler = new Handler(Looper.getMainLooper());
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            if (instanceStateFirebaseRecycler == null) return;
            firebaseRecyclerView.getLayoutManager().onRestoreInstanceState(instanceStateFirebaseRecycler);
            instanceStateFirebaseRecycler = null;
            firebaseRecyclerView.getRootView().setVisibility(View.VISIBLE);
        }
    }, 100);
}

restoreScrollPosition()方法中,我檢查instanceStateFirebaseRecycler == null以避免不必要的運行。 另外,我通過Handler延遲了實例狀態恢復,因為items還沒有繪制,很快就會繪制。 如果沒有延遲地調用onRestoreInstanceState ,狀態將不會按預期恢復。 此外,我通過setVisibility()切換RecyclerView的可見性以隱藏丑陋的項目重新加載和快速滾動,這些可能被用戶解釋為故障。

順便說一下,@Sanju 建議的解決方案在流量和電池效率方面看起來有點危險,因為用戶可以將正在運行的應用程序長時間置於后台,而偵聽器一直處於活動狀態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM