搜索适配器onbind方法中的IndexOutofBounexception? [英] IndexOutofBounexception in search adapter onbind method?

查看:85
本文介绍了搜索适配器onbind方法中的IndexOutofBounexception?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一开始搜索/过滤我的recyclerview列表结果,就一直从搜索适配器中的onBind方法获取IndexOutofBoundsException. 例外:

I keep getting IndexOutofBoundsException from my onBind method in search adapter as soon as I start to search /filter my recyclerview list results. Here's the exception :

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 0(offset:0).state:25 android.support.v7.widget.RecyclerView{3247b3d VFED..... ......ID 0,0-1440,5550 #7f090216 app:id/search_guests_recycler_view}, adapter:com.myapp.ui.registervisitor.searchGuests.SearchGuestListAdapter@2433f32, layout:android.support.v7.widget.LinearLayoutManager@68f5483, context:com.myapp.ui.registervisitor.searchGuests.SearchGuestActivity@843713
        at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5923)
        at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5858)
        at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5854)
        at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2230)
        at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1557)
        at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
        at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612)
        at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924)
        at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:3336)
        at android.view.View.measure(View.java:24545)
        at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:735)
        at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:481)
        at android.view.View.measure(View.java:24545)
        at android.widget.ScrollView.measureChildWithMargins(ScrollView.java:1414)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at android.widget.ScrollView.onMeasure(ScrollView.java:452)
        at android.view.View.measure(View.java:24545)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
        at android.view.View.measure(View.java:24545)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
        at android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:733)
        at android.support.design.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:805)
        at android.view.View.measure(View.java:24545)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
        at android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:733)
        at android.support.design.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:805)
        at android.view.View.measure(View.java:24545)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
        at android.view.View.measure(View.java:24545)
        at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:735)
        at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:481)
        at android.view.View.measure(View.java:24545)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143)
        at android.view.View.measure(View.java:24545)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
        at android.view.View.measure(View.java:24545)

我在网上尝试了几篇文章,但是没有运气.我尝试过的一些文章是: RecyclerView Adapter onBind方法

I tried a couple of articles online, but no luck. some of the articles that I tried are : RecyclerView Adapter onBind method and RecyclerView: Inconsistency detected. Invalid item position

我针对此问题的适配器代码位于: https://pastebin.com/VxsWWMiS

My adapter code for this issue is at : https://pastebin.com/VxsWWMiS

以及用于过滤的相应活动代码:

and corresponding activity code for filtering :

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                mSearchGuestListAdapter.getFilter().filter(query);

                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                mSearchGuestListAdapter.getFilter().filter(newText);
                mSearchGuestListAdapter.notifyDataSetChanged();
                mSearchGuestListAdapter.setFilter(newText);

                if(mSearchGuestListAdapter.getItemCount() == 0){


                    String sourceString = "No match found for <b>" + newText + "</b> ";
                    mNoMatchTextView.setText(Html.fromHtml(sourceString));
                } else {
                    mEmptyRelativeLayout.setVisibility(View.GONE);
                    mRecyclerView.setVisibility(View.VISIBLE);
                }
                return false;
            }
        });

如有需要,很乐意分享其他详细信息.有什么想法可以解决这个问题吗?

Happy to share any other details if needed. Any ideas how to resolve this?

这是我的整个活动代码: https://pastebin.com/5qDN4yh9

Here's my entire activity code: https://pastebin.com/5qDN4yh9

这是演示者类,在该类中调用了API: https://pastebin.com/YGiPGn8Z

This is the presenter class where the API is called : https://pastebin.com/YGiPGn8Z

这是模型类: https://pastebin.com/WCkPFnvU

这是一个json示例: https://pastebin.com/82R1zBHP

This is a json sample : https://pastebin.com/82R1zBHP

以下是调用recyclerview的xml代码: https://pastebin.com/Z3QxPkSL "search_guests_recycler_view"

Here's the xml code where recyclerview is called : https://pastebin.com/Z3QxPkSL "search_guests_recycler_view"

推荐答案

代码中有多个注意事项,可能会导致适配器不一致.

There are multiple considerations in your code that may cause that inconsistency in your adapter.

要了解Filter类的工作原理,您应该注意,根据官方文档:

To understand how Filter class works you should note that, according to official documentation:

通过调用filter(java.lang.CharSequence)或filter(java.lang.CharSequence,android.widget.Filter.FilterListener)执行的

过滤操作是异步执行的 .调用这些方法时,筛选请求将发布到请求队列中,并在以后进行处理.对这些方法之一的任何调用都会取消以前所有未执行的过滤请求.

Filtering operations performed by calling filter(java.lang.CharSequence) or filter(java.lang.CharSequence, android.widget.Filter.FilterListener) are performed asynchronously. When these methods are called, a filtering request is posted in a request queue and processed later. Any call to one of these methods will cancel any previous non-executed filtering request.


1.使用过滤器的单个实例

Filter类执行后台任务,在其中调用performFiltering()方法.为避免在键入时重叠过滤器,应避免使用多个Filter实例.在您的SearchGuestListAdapter类中:


1. Use a single instance of Filter

The Filter class performs a background task in which the performFiltering() method is called. To avoid overlapping filters while typing you should avoid using multiple instances of Filter. In your SearchGuestListAdapter class:

错误:

@Override
public Filter getFilter() {
    // WRONG: Return new instance of Filter every time getFilter() is called
    return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) {
            // Perform filtering...
            return anything;
        }

        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
            // Update and Notify adapter...
        }
    };
}

代替为:

private final Filter filter = new Filter() {
    @Override
    protected FilterResults performFiltering(CharSequence charSequence) {
        // Perform filtering...
        return anything;
    }

    @Override
    protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
        // Update and Notify adapter...
    }
};

@Override
public Filter getFilter() {
    // CORRECT: Always use the same Filter instance.
    return this.filter;
}


2.您不应该在performFiltering()中修改适配器变量

performFiltering()方法在后台线程中执行.在这里,您可以做很长的工作,可以从数据库中读取数据,甚至可以在需要时发出Web服务同步请求.


2. You should not modify adapter variables in performFiltering()

performFiltering() method is executed in a background thread. Here you can do a long job, read data from a database, even make a webservice synchronous request if you need it.

但是,如果您在此处更改适配器列表,则会导致屏幕上显示的RecyclerView与适配器列表的内容不一致.相反,您必须构建一个临时列表,然后使用FilterResults返回该列表.

But, if you alter the adapter list here you will cause inconsistency between RecyclerView is showing on the screen and the contents of the adapter list. Instead you must build a temporary list that you will return using FilterResults.

使用以下结构修复performFiltering():

@Override
protected FilterResults performFiltering(CharSequence charSequence) {
    // Here is Background Thread, never alter adapter list in this method
    String charString = charSequence.toString();
    List<RegisterGuestList.Guest> filteredList = new ArrayList<>();

    if (charString.isEmpty()) {
        filteredList.addAll(mSearchGuestListResponseList);
    } else {
        ... // fill filteredList as you did previously
    }

    FilterResults filterResults = new FilterResults();
    filterResults.values = filteredList;
    filterResults.count = filteredList.size(); // count is optional
    return filterResults;
}

@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
    // Here is Main Thread, safe to update list and notify adapter
    mSearchGuestListResponseListFiltered = (ArrayList<RegisterGuestList.Guest>) filterResults.values;
    searchText = charSequence.toString();
    notifyDataSetChanged();
}


3.使用FilterListener可以在过滤器完成时得到通知.

SearchGuestActivityonQueryTextChange()中,您要检查适配器列表大小以显示或隐藏空视图.由于过滤器在后台线程中工作,因此您必须使用 FilterListener 来执行过滤器调用检查空列表.


3. Use FilterListener to get notified when filter completed.

In your onQueryTextChange() of SearchGuestActivity, you want check adapter list size to show or hide a empty view. As Filter works in background thread you must perform filter call with a FilterListener to check empty list.

删除具有以下结构的SearchGuestListAdapter的setFilter()方法并修复SearchGuestActivity的onQueryTextChange():

Remove your setFilter() method of SearchGuestListAdapter and Fix onQueryTextChange() of SearchGuestActivity with the following structure:

@Override
public boolean onQueryTextChange(String newText) {
    mSearchGuestListAdapter.getFilter().filter(newText, new Filter.FilterListener() {
        @Override
        public void onFilterComplete(int count) {
            if (count == 0) {
                // Show empty view...
            } else {
                // Show recyclerView...
            }
        }
    });

    // Don't call notifyDataSetChanged() or setFilter() here!
    // Adaper will notified by publishResults() method
    // mSearchGuestListAdapter.setFilter(newText);
    // mSearchGuestListAdapter.notifyDataSetChanged();

    return false;
}

这篇关于搜索适配器onbind方法中的IndexOutofBounexception?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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