[英]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.