gpt4 book ai didi

android - 使用 Firebase 和 ChildEventListener 时如何在方向更改后保留 RecyclerView 的位置?

转载 作者:IT老高 更新时间:2023-10-28 22:22:49 25 4
gpt4 key购买 nike

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

  • RecyclerView
  • 卡片 View
  • Firebase
  • 毕加索

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

我已经使用 GridLayoutManager 实现了这一切,如果用户的手机是 VERTICAL,则为 1 列,如果用户的手机为 HORIZONTAL,则为 3 列。

我遇到的问题是我似乎无法保存 RecyclerView 在方向更改时的位置。我已经尝试了我能找到的每一个选项,但似乎没有一个有效。我能得出的唯一结论是,在轮换时,我正在销毁 FirebaseChildEventListener 以避免内存泄漏,一旦定向完成,Firebase 由于 ChildEventListener 的新实例而重新查询数据库。

有什么方法可以保存我的 RecyclerView 在方向更改时的位置?我不想要 android:configChanges,因为它不会让我更改布局,而且我已经尝试保存为 Parcelable,但没有成功。我敢肯定我错过了一些简单的事情,但是嘿,我是开发新手。非常感谢对我的代码的任何帮助或建议。谢谢!

以下是我的类(class),我已将其缩短为必要的代码。

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

}

最佳答案

编辑:

我终于能够使用多种因素完成这项工作。如果其中任何一个被遗漏,它根本就行不通。

在我的 onCreate 中创建新的 GridLayoutManager

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

在 onPause 中保存 RecyclerView 状态

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"'

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

使用 Handler

恢复 onConfigurationChanged 中的 RecyclerView 状态

处理程序是最重要的部分之一,如果不包括在内,它将根本无法工作,并且 RecyclerView 的位置将重置为 0。我想这是一个可以追溯的缺陷几年了,一直没修好。然后我根据方向更改了 GridLayoutManagersetSpanCount

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

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

关于android - 使用 Firebase 和 ChildEventListener 时如何在方向更改后保留 RecyclerView 的位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42514011/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com