使用Firebase&时如何更改方向后如何保留RecyclerView的位置ChildEventListener? [英] How to retain RecyclerView's position after Orientation change, while using Firebase & ChildEventListener?

查看:77
本文介绍了使用Firebase&时如何更改方向后如何保留RecyclerView的位置ChildEventListener?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个简单的APOD应用,该应用可实现:

I'm working on a simple APOD app that implements:

  • RecyclerView
  • CardView
  • Firebase
  • Picasso
  • RecyclerView
  • CardView
  • Firebase
  • Picasso

应用程序从FirebaseFirebase Storage抓取图像和文本,将它们显示在CardView中,并为每个View设置一个OnClickListener.当用户单击图像时,我通过Intent打开一个新的Activity.第二个Activity显示原始单击的图像以及有关此图像的更多信息.

The app grabs images and text from Firebase and Firebase Storage, displays them in a CardView, and sets an OnClickListener to each View. When the user clicks on an image, I open a new Activity through an Intent. The second Activity displays the original clicked image, and more info about it.

我已经使用GridLayoutManager来实现了所有功能,如果用户的电话为垂直",则为1列,如果用户的电话为水平",则为3列.

I've implemented this all using a GridLayoutManager, 1 column if the user's phone is VERTICAL, 3 columns if the user's phone is HORIZONTAL.

我遇到的问题是我似乎无法保存方向更改时的RecyclerView位置.我已经尝试了所有可以找到的单个选项,但是似乎都没有用.我唯一能得出的结论是,在旋转时,为了避免内存泄漏,我正在销毁FirebaseChildEventListener,并且一旦定向完成,由于出现了新问题,Firebase将重新查询数据库. ChildEventListener的实例.

The problem I'm having is I can't seem to save the RecyclerView's position on orientation change. I've tried every single option that I could find, but none seem to work. The only conclusion I could come up with, is that on rotation, I'm destroying Firebase's ChildEventListener to avoid a memory leak, and once orientation is complete, Firebase re-queries the database because of the new instance of ChildEventListener.

有什么方法可以保存我的RecyclerView位置更改方向吗?我不希望android:configChanges,因为它不会让我更改布局,并且我已经尝试将其另存为Parcelable,但未成功.我敢肯定,这很容易丢失,但是,嘿,我是新手.我的代码有任何帮助或建议,我们将不胜感激.谢谢!

Is there any way I can save my RecyclerView's position on orientation change? I do not want android:configChanges as it won't let me change my layout, and I've already tried saving as a Parcelable, which was unsuccessful. I'm sure it's something easy I'm missing, but hey, I'm new to developing. Any help or suggestions on my code is greatly appreciated. Thanks!

下面是我的课程,我仅将其缩短为必要的代码.

Below are my classes, which I have shortened only to the necessary code.

MainActivity

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

}

RecyclerAdapter

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

}

推荐答案

我终于能够使用多个因素来完成这项工作.如果其中任何一个被排除在外,那简直是行不通的.

I was finally able to make this work using multiple factors. If any one of these were left out, it simply would not work.

在我的onCreate中创建新的GridLayoutManager

Create new GridLayoutManager in my onCreate

gridLayoutManager = new GridLayoutManager(getApplicationContext(), columns);

将RecyclerView状态保存为onPause

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

Include configChanges in the AndroidManifest.xml

仅保存和恢复RecyclerView状态是不够的.我还不得不违反常规,将AndroidManifest.xml更改为'android:configChanges ="orientation | screenSize"'

Saving and restoring the RecyclerView state was not enough. I also had to go against the grain and change my AndroidManifest.xml to 'android:configChanges="orientation|screenSize"'

<activity
        android:name=".MainActivity"
        android:configChanges="orientation|screenSize"
        >

使用Handler

Restore the RecyclerView state in onConfigurationChanged using a Handler

处理程序是最重要的部分之一,如果不包括在内,它将无法正常工作,并且RecyclerView的位置将重置为0.我想这是几年前的缺陷,并且从来没有固定.然后,我根据方向更改了GridLayoutManagersetSpanCount.

The handler was one of the most important parts, if it's not included, it simply will not work and the position of the RecyclerView will reset to 0. I guess this has been a flaw going back a few years, and was never fixed. I then changed the GridLayoutManager's setSpanCount depending on the orientation.

    @Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    columns = getResources().getInteger(R.integer.gallery_columns);

    if (mBundleRecyclerViewState != null) {
        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                mListState = mBundleRecyclerViewState.getParcelable(KEY_RECYCLER_STATE);
                mRecyclerView.getLayoutManager().onRestoreInstanceState(mListState);

            }
        }, 50);
    }

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {

        gridLayoutManager.setSpanCount(columns);

    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {

        gridLayoutManager.setSpanCount(columns);

    }
    mRecyclerView.setLayoutManager(gridLayoutManager);
}

就像我说过的那样,所有这些更改都必须包括在内,至少对我而言.我不知道这是否是最有效的方法,但是花了几个小时后,它对我有用.

Like I said, all of these changes needed to be included, at least for me. I don't know if this is the most efficient way, but after spending many hours, it works for me.

这篇关于使用Firebase&amp;时如何更改方向后如何保留RecyclerView的位置ChildEventListener?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆