Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/183.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 安卓:我的应用程序出现奇怪问题,设备旋转后出现1个碎片_Android_Android Recyclerview - Fatal编程技术网

Android 安卓:我的应用程序出现奇怪问题,设备旋转后出现1个碎片

Android 安卓:我的应用程序出现奇怪问题,设备旋转后出现1个碎片,android,android-recyclerview,Android,Android Recyclerview,我的应用程序由1个片段组成。此片段包含一个包含大量条目的recyclerview 症状是设备旋转后,似乎无法将recyclerview滚动到保存位置。无论我做了什么,结果都没有滚动。因此,UI中发生了奇怪的事情 编辑(揭示根本原因) 在我的活动中,我有以下代码 if (findViewById(R.id.fragment_container) != null) { FragmentCategoryChecklist f2 = new FragmentCategoryChecklist()

我的应用程序由1个片段组成。此片段包含一个包含大量条目的recyclerview

症状是设备旋转后,似乎无法将recyclerview滚动到保存位置。无论我做了什么,结果都没有滚动。因此,UI中发生了奇怪的事情

编辑(揭示根本原因)

在我的活动中,我有以下代码

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