Android 如何保留RecyclerView';使用Firebase&;时,改变方向后的s位置;儿童事件监听器?

Android 如何保留RecyclerView';使用Firebase&;时,改变方向后的s位置;儿童事件监听器?,android,firebase,firebase-realtime-database,Android,Firebase,Firebase Realtime Database,我正在开发一个简单的APOD应用程序,它实现: RecyclerView cardwiew Firebase 毕加索 该应用程序从Firebase和Firebase存储中获取图像和文本,在CardView中显示它们,并为每个视图设置OnClickListener。当用户单击图像时,我通过意图打开一个新的活动。第二个活动显示原始单击的图像以及有关该图像的更多信息 我使用了一个GridLayoutManager,如果用户的电话是垂直的,则为1列,如果用户的电话是水平的,则为3列 我遇到的问题是,

我正在开发一个简单的APOD应用程序,它实现:

  • RecyclerView
  • cardwiew
  • Firebase
  • 毕加索
该应用程序从
Firebase
Firebase存储中获取图像和文本,在
CardView
中显示它们,并为每个
视图设置
OnClickListener
。当用户单击图像时,我通过
意图打开一个新的
活动
。第二个
活动
显示原始单击的图像以及有关该图像的更多信息

我使用了一个
GridLayoutManager
,如果用户的电话是垂直的,则为1列,如果用户的电话是水平的,则为3列

我遇到的问题是,我似乎无法保存
RecyclerView
对方向更改的立场。我已经尝试了我能找到的每一个选项,但似乎都不起作用。我能得出的唯一结论是,在轮换时,我正在销毁
Firebase
ChildEventListener
以避免内存泄漏,一旦定向完成,
Firebase
会因为
ChildEventListener
的新实例而重新查询数据库

有什么方法可以保存我的
RecyclerView
在方向更改时的位置吗?我不想要
android:configChanges
,因为它不允许我更改布局,而且我已经尝试将其保存为
包裹,但未成功。我肯定我错过了一些简单的东西,但是,嘿,我对开发还不熟悉。非常感谢对我的代码的任何帮助或建议。谢谢

下面是我的类,我只是将其缩短为必要的代码

main活动

public class MainActivity extends AppCompatActivity {

private RecyclerAdapter mRecyclerAdapter;
private DatabaseReference mDatabaseReference;
private RecyclerView mRecyclerView;
private Query query;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
    setContentView(R.layout.activity_main);
    getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    final int columns = getResources().getInteger(R.integer.gallery_columns);

    mDatabaseReference = FirebaseDatabase.getInstance().getReference();
    query = mDatabaseReference.child("apod").orderByChild("date");

    mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    mRecyclerView.setHasFixedSize(true);
    mRecyclerView.setLayoutManager(new GridLayoutManager(this, columns));


    mRecyclerAdapter = new RecyclerAdapter(this, query);
    mRecyclerView.setAdapter(mRecyclerAdapter);


  }

@Override
public void onDestroy() {
    mRecyclerAdapter.cleanupListener();
  }

}
回收适配器

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ApodViewHolder> {

private final Context mContext;
private final ChildEventListener mChildEventListener;
private final Query mDatabaseReference;
private final List<String> apodListIds = new ArrayList<>();
private final List<Apod> apodList = new ArrayList<>();

public RecyclerAdapter(final Context context, Query ref) {
    mContext = context;
    mDatabaseReference = ref;


    ChildEventListener childEventListener = new ChildEventListener() {


        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            int oldListSize = getItemCount();
            Apod apod = dataSnapshot.getValue(Apod.class);

            //Add data and IDs to the list
            apodListIds.add(dataSnapshot.getKey());
            apodList.add(apod);

            //Update the RecyclerView
            notifyItemInserted(oldListSize - getItemCount() - 1);
        }

        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) {

        }

        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) {
            String apodKey = dataSnapshot.getKey();
            int apodIndex = apodListIds.indexOf(apodKey);

            if (apodIndex > -1) {

                // Remove data and IDs from the list
                apodListIds.remove(apodIndex);
                apodList.remove(apodIndex);

                // Update the RecyclerView
                notifyDataSetChanged();
            }
        }

        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String s) {

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }

    };
    ref.addChildEventListener(childEventListener);
    mChildEventListener = childEventListener;

 }

   @Override
    public int getItemCount() {
    return apodList.size();
}
    public void cleanupListener() {
    if (mChildEventListener != null) {
        mDatabaseReference.removeEventListener(mChildEventListener);
    }
  }

}
公共类RecyclerAdapter扩展了RecyclerView.Adapter{ 私有最终上下文mContext; private final ChildEventListener mChildEventListener; 私有最终查询mDatabaseReference; private final List apodListIds=new ArrayList(); private final List apodList=new ArrayList(); 公共RecyclerAdapter(最终上下文,查询引用){ mContext=上下文; mDatabaseReference=ref; ChildEventListener ChildEventListener=新的ChildEventListener(){ @凌驾 公共void onChildAdded(DataSnapshot DataSnapshot,字符串s){ int oldListSize=getItemCount(); Apod Apod=dataSnapshot.getValue(Apod.class); //将数据和ID添加到列表中 add(dataSnapshot.getKey()); apodList.add(apod); //更新RecyclerView notifyItemInserted(oldListSize-getItemCount()-1); } @凌驾 公共void onChildChanged(DataSnapshot DataSnapshot,字符串s){ } @凌驾 ChildRemoved上的公共void(DataSnapshot DataSnapshot){ 字符串apodKey=dataSnapshot.getKey(); int apodIndex=apodListIds.indexOf(apodKey); 如果(apodIndex>-1){ //从列表中删除数据和ID apodListIds.remove(apodIndex); apodList.remove(apodIndex); //更新RecyclerView notifyDataSetChanged(); } } @凌驾 已移动ChildMoved上的公共void(DataSnapshot DataSnapshot,字符串s){ } @凌驾 已取消的公共void(DatabaseError DatabaseError){ } }; ref.addChildEventListener(childEventListener); mChildEventListener=childEventListener; } @凌驾 public int getItemCount(){ 返回apodList.size(); } public void cleanupliner(){ if(mChildEventListener!=null){ mDatabaseReference.removeEventListener(mChildEventListener); } } }
编辑:

我终于能够利用多种因素完成这项工作。如果其中任何一个被忽略,它根本就不起作用

在我的onCreate中新建
GridLayoutManager

gridLayoutManager = new GridLayoutManager(getApplicationContext(), columns);
private final String KEY_RECYCLER_STATE = "recycler_state"; 
private static Bundle mBundleRecyclerViewState;
private Parcelable mListState = null;`


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

    mBundleRecyclerViewState = new Bundle();
    mListState = mRecyclerView.getLayoutManager().onSaveInstanceState();
    mBundleRecyclerViewState.putParcelable(KEY_RECYCLER_STATE, mListState);


}
在onPause中保存RecyclerView状态

gridLayoutManager = new GridLayoutManager(getApplicationContext(), columns);
private final String KEY_RECYCLER_STATE = "recycler_state"; 
private static Bundle mBundleRecyclerViewState;
private Parcelable mListState = null;`


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

    mBundleRecyclerViewState = new Bundle();
    mListState = mRecyclerView.getLayoutManager().onSaveInstanceState();
    mBundleRecyclerViewState.putParcelable(KEY_RECYCLER_STATE, mListState);


}
AndroidManifest.xml
中包含
configChanges

仅保存和恢复
RecyclerView
状态是不够的。我还不得不违背规则,将我的
AndroidManifest.xml
更改为“android:configChanges=“orientation | screenSize”


正如我所说,所有这些变化都需要包括在内,至少对我来说是这样。我不知道这是否是最有效的方法,但在花了很多时间后,它对我来说是有效的。

每次方向改变时,都会重新创建活动。因此,您必须在bundle中保存位置,然后在第二次调用onCreate()时重新使用它

@Override
public void onCreate(Bundle savedInstanceState) {

   super.onCreate(savedInstanceState);

   int recyclerViewPosition;
   if(savedInstanceState != null){
     recyclerViewPosition = savedInstanceState.getInt(RECYCLER_VIEW_POSITION);
   }

   mRecyclerView.scrollToPosition(recyclerViewPosition);

}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    //save the current recyclerview position 
    outState.putInt(RECYCLER_VIEW_POSITION, mRecyclerView.getAdapterPosition());
}

您可能需要查看RecyclerView.State(),了解有关如何恢复回收器视图状态的更多选项。

当旋转活动再次被销毁和重新创建时,这意味着所有对象都被销毁和重新创建,布局也被重新绘制

如果您想停止重新创建活动,您可以使用android:configChanges
,但这是一种不好的做法,也不是正确的方法

现在唯一剩下的就是在旋转前保存recyclerview的位置,并在活动重新创建后获取它

//保存recyclerview位置的步骤

 @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
      // Save UI state changes to the savedInstanceState.
      // This bundle will be passed to onCreate if the process is
      // killed and restarted.
      savedInstanceState.putInt("position", mRecyclerView.getAdapterPosition()); // get current recycle view position here.
      super.onSaveInstanceState(savedInstanceState);
    }
//恢复价值

    @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
    setContentView(R.layout.activity_main);
    getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    final int columns = getResources().getInteger(R.integer.gallery_columns);

    mDatabaseReference = FirebaseDatabase.getInstance().getReference();
    query = mDatabaseReference.child("apod").orderByChild("date");

    mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    mRecyclerView.setHasFixedSize(true);
    mRecyclerView.setLayoutManager(new GridLayoutManager(this, columns));


    mRecyclerAdapter = new RecyclerAdapter(this, query);
    mRecyclerView.setAdapter(mRecyclerAdapter);
   if(savedInstanceState != null){
     // scroll to existing position which exist before rotation.
     mRecyclerView.scrollToPosition(savedInstanceState.getInt("position"));
   }  

  }

希望这些对您有所帮助。

实际上,当活动重新创建时,有更好的方法来恢复回收器视图位置,这是通过使用“回收器视图布局管理器”选项来存储和恢复最后一个位置(最后一个回收器视图布局状态)。看看这个

只需几句话,您就需要在
private static String STATE = "STATE";
    
    // the recycler view manager
    private GridLayoutManager layoutManager;
    
    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        // save recycler view layout
        if(layoutManager != null) {
            outState.putParcelable(STATE, layoutManager.onSaveInstanceState());
        }
    }
    
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
                             
        ...
        

        loadDataAsync(savedInstanceState);
        
    
        return view;
    }
    
    private void loadDataAsync(Bundle savedInstanceState){
    
        repository.getAll(new IMyListener()){
                @Override
                public void getAll(List<String> listResult) {
                        reyclerViewFilterableAdapter.setItems(listResult);
                        reyclerViewFilterableAdapter.notifyDataSetChanged();
                        new Handler().postDelayed(new Runnable() {

                            @Override
                            public void run() {
                                if (layoutManager != null) {
                                    layoutManager.onRestoreInstanceState(savedInstanceState.getParcelable(STATE));
                                }
                            }
                        }, 100);
                }
            });
    
    }