Android 安卓:我的应用程序出现奇怪问题,设备旋转后出现1个碎片
我的应用程序由1个片段组成。此片段包含一个包含大量条目的recyclerview 症状是设备旋转后,似乎无法将recyclerview滚动到保存位置。无论我做了什么,结果都没有滚动。因此,UI中发生了奇怪的事情 编辑(揭示根本原因) 在我的活动中,我有以下代码Android 安卓:我的应用程序出现奇怪问题,设备旋转后出现1个碎片,android,android-recyclerview,Android,Android Recyclerview,我的应用程序由1个片段组成。此片段包含一个包含大量条目的recyclerview 症状是设备旋转后,似乎无法将recyclerview滚动到保存位置。无论我做了什么,结果都没有滚动。因此,UI中发生了奇怪的事情 编辑(揭示根本原因) 在我的活动中,我有以下代码 if (findViewById(R.id.fragment_container) != null) { FragmentCategoryChecklist f2 = new FragmentCategoryChecklist()
if (findViewById(R.id.fragment_container) != null) {
FragmentCategoryChecklist f2 = new FragmentCategoryChecklist();
Bundle b = new Bundle();
b.putString("contents", "Category Fragment");
f2.setArguments(b);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, f2).commit();
}
这是错误的!请参阅下面的代码
当使用此代码旋转设备时,每次都会创建一个新的片段。这是错误的,因为Android已经重新创建了(保存的)片段
其结果是代码使用实例数据创建了一个片段,然后立即销毁,然后在没有任何实例数据的情况下重新创建。没有保存的实例数据意味着没有滚动到以前保存的位置
正确的代码如下所示。对不起,我的问题只是一个症状,没有显示根本原因
Fragment f = getSupportFragmentManager().findFragmentById( R.id.fragment_container);
if( f == null) {
if (findViewById(R.id.fragment_container) != null) {
FragmentCategoryChecklist f2 = new FragmentCategoryChecklist();
Bundle b = new Bundle();
b.putString("contents", "Category Fragment");
f2.setArguments(b);
getSupportFragmentManager().
beginTransaction().
replace(R.id.fragment_container, f2).
commit();
}
}
这是一种黑客的方式,但是你可以设置一个线程来定期检查你的
RecyclerView
final LinearLayoutManager manager = (LinearLayoutManager) recyclerview.getLayoutManager();
new Thread(){
@Override
public void run(){
try {
while(true){
Thread.sleep(543);
if(manager.findLastCompletelyVisibleItemPosition() != -1){
//Return to the UI thread and continue your work
//Try runOnUiThread(Runnable)
break;
}
}
} catch (Exception ex) {
//Handle thread interruption, etc
}
}
}.start();
当然有更好的方法来实现这一点,而不涉及线程。设置有限的试用次数可能会有所帮助,这样您就不会有永远运行的游离线程。我相信您可以从第一个和最后一个VisibleItem位置回调布局渲染完成。这是最好的解释。希望这有帮助
private boolean canScroll = false;
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
@Override
public void onLayoutChildren(final Recycler recycler, final State state) {
super.onLayoutChildren(recycler, state);
final int firstVisibleItemPosition = findFirstVisibleItemPosition();
if (firstVisibleItemPosition != 0) {
// this avoids trying to handle un-needed calls
if (firstVisibleItemPosition == -1)
//not initialized, or no items shown.Can't
canScroll = false;
return;
}
final int lastVisibleItemPosition = findLastVisibleItemPosition();
canScroll = (lastVisibleItemPosition - firstVisibleItemPosition) > 0
}
};
然后可以使用
canScroll
变量决定是否滚动。问题的根本原因显示在问题的编辑部分之后
设备旋转后正确启动碎片的解决方案是:
Fragment f = getSupportFragmentManager().findFragmentById( R.id.fragment_container);
if( f == null) {
if (findViewById(R.id.fragment_container) != null) {
FragmentCategoryChecklist f2 = new FragmentCategoryChecklist();
Bundle b = new Bundle();
b.putString("contents", "Category Fragment");
f2.setArguments(b); getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, f2).commit();
}
}
仅当设备旋转后不存在新片段时,才会创建新片段
最初的问题是什么
很简单,只需添加一个
((LinearLayoutManager) recyclerview.getLayoutManager()).scrollToPositionWithOffset( jumpToCurrentSelection, 20);
在片段上添加以下内容:
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(SAVED_LAYOUT_MANAGER, recyclerView.getLayoutManager().onSaveInstanceState());
return bundle;
}
及
并通过以下方式恢复您的回收器视图数据:
public void setItems(List objects) {
adapter.setItems(objects);
restoreLayoutManagerPosition();
}
private void restoreLayoutManagerPosition() {
if (layoutManagerSavedState != null) {
recyclerView.getLayoutManager().onRestoreInstanceState(layoutManagerSavedState);
}
}
我认为您可以尝试使用UI处理程序来实现这一点。将
Runnable
发布到UI消息队列,并尝试在那里findLastCompletelyVisibleItemPosition
。这将保证在生命周期回调后执行此Runnable。如果这不起作用,请在此处发布一些代码,因为很难找到问题。你能详细说明你的答案吗?我没有将此作为答案发布,因为我不能100%确定它是否有效,所以我请你尝试。@bpr10的解决方案行得通吗?如果你不明白我的意思,就这样试试:uiHandler.post(new Runnable(){@Override public void run(){((LinearLayoutManager)recyclerview.getLayoutManager()).findlastpletelyvisibleitemposition();//这不应该返回-1})
。其中,uiHandler
是附加到UI线程的Handler
对象。我已将代码添加到问题中。您将看到选项1。。。在findLastCompletelyVisibleItemPosition()上返回-1。我也添加了选项2,再次返回-1。唉,这不起作用。它只是提到(Toast消息)lastVisibleItemPosition类似于9。我仍然无法滚动到某个位置。因此,在canScroll==true时,以下滚动无效。((LinearLayoutManager)recyclerview.getLayoutManager()).scrollToPositionWithOffset(jumpToCurrentSelection,20);你的答案加1。你的答案加1。
public void setItems(List objects) {
adapter.setItems(objects);
restoreLayoutManagerPosition();
}
private void restoreLayoutManagerPosition() {
if (layoutManagerSavedState != null) {
recyclerView.getLayoutManager().onRestoreInstanceState(layoutManagerSavedState);
}
}