Android 如何保留RecyclerView';使用Firebase&;时,改变方向后的s位置;儿童事件监听器?
我正在开发一个简单的APOD应用程序,它实现: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列 我遇到的问题是,
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);
}
});
}