Java 替换RecyclerView项时获取IndexOutOfBoundsException

Java 替换RecyclerView项时获取IndexOutOfBoundsException,java,android,android-recyclerview,Java,Android,Android Recyclerview,当有人搜索某个单词时,我试图替换我的RecyclerView中的项目。一个GIF列表被发送到我的回调方法,我正在循环这些对象,并希望替换RecyclerView中的每个对象。但是,当我尝试执行此操作时,如果在适配器中调用ArrayList.set(),则会出现IndexOutOfBoundsException 我明白为什么会这样……适配器中的ArrayList中没有任何项。我的问题是为什么?我做错了什么 我的活动代码: package hidden.package; // Imports hi

当有人搜索某个单词时,我试图替换我的RecyclerView中的项目。一个GIF列表被发送到我的回调方法,我正在循环这些对象,并希望替换RecyclerView中的每个对象。但是,当我尝试执行此操作时,如果在适配器中调用
ArrayList.set()
,则会出现IndexOutOfBoundsException

我明白为什么会这样……适配器中的ArrayList中没有任何项。我的问题是为什么?我做错了什么

我的活动代码:

package hidden.package;

// Imports hidden

public class GifSearchActivity extends AppCompatActivity {

    @BindView(R.id.gifSearchBar)
    FloatingSearchView searchGifs;

    @BindView(R.id.gifSearchResults)
    RecyclerView searchResults;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gifsearch);
        ButterKnife.bind(this);

        final GIFResultsAdapter adapter = new GIFResultsAdapter();

        final SharedPreferences prefs = PreferenceManager
                .getDefaultSharedPreferences(GifSearchActivity.this);

        final GIFInterface i = new GIFInterface();
        i.setSearchListener(new GIFInterface.GIFSearchListener() {
            @Override
            public void onSearchResultsRetrieved(final GIFSearchResults gifSearchResults) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.d("GAB", "Results Retrieved...");
                        int count = 0;
                        for (GIF gif : gifSearchResults.getGIFs()) {
                            adapter.replaceItem(gif, count);
                            count++;
                        }
                    }
                });
            }
        });

        searchResults.setLayoutManager(new GridLayoutManager(getBaseContext(), 1, GridLayoutManager.VERTICAL, false));
        searchResults.setItemAnimator(new DefaultItemAnimator());
        searchResults.setAdapter(adapter);

        searchGifs.setOnQueryChangeListener(new FloatingSearchView.OnQueryChangeListener() {
            @Override
            public void onSearchTextChanged(String oldQuery, String newQuery) {
                i.searchForGif(prefs.getString("token", ""), newQuery);
            }
        });
    }
}
我的适配器代码:

package hidden.package;

// Imports hidden

@SuppressWarnings("deprecation")
public class GifResultsAdapter extends RecyclerView.Adapter<GifResultsAdapter.GifsViewHolder> {

    private ArrayList<GIF> gifs = new ArrayList<>();
    private Context con;

    public class GifsViewHolder extends RecyclerView.ViewHolder {

        ImageView gif;
        ProgressBar gifProgressBar;

        public GifsViewHolder(View itemView) {
            super(itemView);
            gif = (ImageView) itemView.findViewById(R.id.gif);
            gifProgressBar = (ProgressBar) itemView.findViewById(R.id.gifProgressBar);
        }
    }

    public void replaceItem(GIF gif, int position) {
        gifs.set(position, gif);
        notifyItemChanged(position);
    }

    @Override
    public GifsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Log.d("GAB", "ViewHolder Created");
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.util_gif_row, parent, false);
        this.con = parent.getContext();
        return new GifsViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(final GifsViewHolder holder, int position) {
        Log.d("GAB", "ViewHolder bound");
        final GIF gif = gifs.get(position);
        Glide.with(con)
                .load(gif.getUrl())
                .override(700, 700)
                .fitCenter()
                .placeholder(new ColorDrawable(AndroidHelper.darkenColor(con.getResources().getColor(R.color.colorAccent), 0.95f)))
                .into(holder.gif);
    }

    @Override
    public int getItemCount() {
        return gifs.size();
    }
}

如果您有一双新鲜的眼睛,我们将不胜感激

您正在调用的方法是
replaceItem
它将一个元素替换为另一个元素,如果您在列表为空时调用它,您应该首先创建一个方法来在适配器中添加GIF

public void addItem(GIF gif) {
    gifs.add(gif);
    notifyItemChanged(position);
}
第一次收到Gif时,不要调用
replaceItem
,而应该调用
addItem


之后,当您需要替换特定元素时,您可以使用
replaceItem

我会做一些稍微不同的事情。我会在每次按键时等待一小段时间,大约50/100毫秒,以及请求新内容加载的afetr(可能使用加载程序)

通过这种方式,您可以防止触发大量可能是exprensive和无用的搜索,然后使用新的结果集合替换适配器的所有内容

在下面的示例中,我将使用AsyncTask来加快速度

在GifSearchActivity中,为下面定义的AsyncTask添加一个名为gifSearchTask的变量,并用此变量替换yout query change listener

通过这种方式,您将为每个查询更改触发一个事件,取消前一个if正在运行或挂起。用新查询开始新查询,最后用新查询替换回收器视图的整个数据集

searchGifs.setOnQueryChangeListener(new FloatingSearchView.OnQueryChangeListener() {
        @Override
        public void onSearchTextChanged(String oldQuery, String newQuery) {
            if (gifSearchTask != null && AsyncTask.Status.FINISHED != gifSearchTask.getStatus()) {
                gifSearchTask.cancel(true);
            }
            gifSearchTask = new GifSearchAsyncTask();
            gifSearchTask.execute(newQuery);
        }
    });


class GifSearchAsyncTask extends AsyncTask<String, Void, List<Gif>> {

    @Override
    protected List<Gif> doInBackground(String... params) {
        List<Gif> results = null;
        android.os.SystemClock.sleep(100);
        // if not cancelled
        if (!isCancelled()) {
            results = performSearch(params);
        }
        return results;
    }

    @Override
    protected void onCancelled() {
        // do nothing
    }

    @Override
    protected void onCancelled(Result result) {
        // do nothing
    }

    @Override
    protected void onPostExecute(List<Gif> results) {
        adapter.setData(results);
        gifSearchTask = null;
    }

    private List<Gif> performSearch(String ... params) {
        // perform search and retur the results
    }
}
searchGifs.setOnQueryChangeListener(新的FloatingSearchView.OnQueryChangeListener(){
@凌驾
已更改SearchTextChanged上的公共void(字符串oldQuery、字符串newQuery){
if(gifSearchTask!=null&&AsyncTask.Status.FINISHED!=gifSearchTask.getStatus()){
giveSearchTask.cancel(true);
}
gifSearchTask=新的GifSearchAsyncTask();
gifSearchTask.execute(newQuery);
}
});
类GifSearchAsyncTask扩展了AsyncTask{
@凌驾
受保护列表doInBackground(字符串…参数){
列表结果=空;
android.os.SystemClock.sleep(100);
//如果没有取消
如果(!isCancelled()){
结果=性能搜索(参数);
}
返回结果;
}
@凌驾
受保护的void onCancelled(){
//无所事事
}
@凌驾
取消时受保护的无效(结果){
//无所事事
}
@凌驾
受保护的void onPostExecute(列出结果){
adapter.setData(结果);
gifSearchTask=null;
}
私有列表性能搜索(字符串…参数){
//执行搜索并返回结果
}
}

我想出了一个更好的解决方案:创建一个
clear()
方法,并在搜索查询更改时调用它


特别感谢你。现在,每次更改搜索查询时,都会删除当前项目并添加新项目。

我应该提到,起初,我尝试将GIF添加到RV…但最终用户每次查询都会添加GIF。因此,如果我键入
angry
,它将为查询
a
an
ang
,等等加载GIF。这就是我要替换结果的原因。您将创建GIF对象的空列表(
gifs
)。您需要在构造函数中传递列表(例如)
searchGifs.setOnQueryChangeListener(new FloatingSearchView.OnQueryChangeListener() {
        @Override
        public void onSearchTextChanged(String oldQuery, String newQuery) {
            if (gifSearchTask != null && AsyncTask.Status.FINISHED != gifSearchTask.getStatus()) {
                gifSearchTask.cancel(true);
            }
            gifSearchTask = new GifSearchAsyncTask();
            gifSearchTask.execute(newQuery);
        }
    });


class GifSearchAsyncTask extends AsyncTask<String, Void, List<Gif>> {

    @Override
    protected List<Gif> doInBackground(String... params) {
        List<Gif> results = null;
        android.os.SystemClock.sleep(100);
        // if not cancelled
        if (!isCancelled()) {
            results = performSearch(params);
        }
        return results;
    }

    @Override
    protected void onCancelled() {
        // do nothing
    }

    @Override
    protected void onCancelled(Result result) {
        // do nothing
    }

    @Override
    protected void onPostExecute(List<Gif> results) {
        adapter.setData(results);
        gifSearchTask = null;
    }

    private List<Gif> performSearch(String ... params) {
        // perform search and retur the results
    }
}