我有一个具有无尽的recyclerView的应用程序(当到达列表末尾的某个偏移时,我从recyclerView适配器调用接口方法)。
RecyclerView适配器
public SearchResultAdapter(ArrayList<String> suggestions) {
this.suggestions = suggestions;
}
public SearchResultAdapter(ArrayList<Word> results, RecyclerView recyclerView) {
words = results;
this.recyclerView = recyclerView;
final LinearLayoutManager mLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0) //check for scroll down
{
visibleItemCount = mLayoutManager.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if ((visibleItemCount + pastVisiblesItems + 14) >= totalItemCount) {
if (mOnLoadMoreListener != null)
mOnLoadMoreListener.onLoadMore();
loading = false;
}
}
}
}
});
}
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
}
public void setOnSearchResultClickListener(OnSearchResultClickListener mClickListener) {
this.mClickListener = mClickListener;
}
public void setLoading() {
loading = true;
}
@Override
public int getItemViewType(int position) {
if(words !=null)
return words.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
else
return VIEW_TYPE_SUGGESTION;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
if (suggestions != null) {
View view = inflater.inflate(R.layout.activity_suggestion_item, parent, false);
return new SuggestionsViewHolder(view);
}
if (words != null) {
// Inflate the custom layout
if (viewType == VIEW_TYPE_ITEM) {
View view = inflater.inflate(R.layout.activity_main_search_result_item, parent, false);
return new WordViewHolder(view);
}
//inflate loading
else if (viewType == VIEW_TYPE_LOADING) {
View view = inflater.inflate(R.layout.activity_main_search_result_loading, parent, false);
return new LoadingViewHolder(view);
}
}
return null;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
Word word=null;
if(words !=null)
word = words.get(position);
if (viewHolder instanceof LoadingViewHolder) {
LoadingViewHolder holder = (LoadingViewHolder) viewHolder;
holder.progressBar.setIndeterminate(true);
} else if (viewHolder instanceof WordViewHolder) {
WordViewHolder holder = (WordViewHolder) viewHolder;
holder.wordTextView.setText(word.getTitle());
holder.sourceTextView.setText(word.getSource().getTitle());
} else if (viewHolder instanceof SuggestionsViewHolder){
SuggestionsViewHolder holder = (SuggestionsViewHolder) viewHolder;
holder.wordTextView.setText(suggestions.get(position));
}
//wordTextView.loadDataWithBaseURL(null,result.toString(), "text/html", "utf-8", null);
}
@Override
public int getItemCount() {
return words == null ? (suggestions ==null?0:suggestions.size()) : words.size();
}
public static class LoadingViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public LoadingViewHolder(View itemView) {
super(itemView);
progressBar = (ProgressBar) itemView.findViewById(R.id.search_item_progressbar);
}
}
public class WordViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
// public TextView titleTextView;
private CustomTextView wordTextView;
private CustomTextView sourceTextView;
private CardView searchResultItem;
public WordViewHolder(View itemView) {
super(itemView);
searchResultItem = (CardView) itemView.findViewById(R.id.search_result_item_cardview);
wordTextView = (CustomTextView) itemView.findViewById(R.id.search_result_item_body);
sourceTextView = (CustomTextView) itemView.findViewById(R.id.search_result_source);
searchResultItem.setOnClickListener(this);
}
@Override
public void onClick(View view) {
mClickListener.onSearchResultClick(getAdapterPosition());
}
}
public class SuggestionsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
// public TextView titleTextView;
private CustomTextView wordTextView;
private CardView suggestionItem;
public SuggestionsViewHolder(View itemView) {
super(itemView);
suggestionItem = (CardView) itemView.findViewById(R.id.suggestion_item_cardview);
wordTextView = (CustomTextView) itemView.findViewById(R.id.activity_suggestion_title);
wordTextView.setTypeface(MainActivity.custom_font);
suggestionItem.setOnClickListener(this);
}
@Override
public void onClick(View view) {
mClickListener.onSuggestionClick(suggestions.get(getAdapterPosition()));
}
}
@Override
public int getItemViewType(int position) {
if(words !=null)
return words.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
else
return VIEW_TYPE_SUGGESTION;
}
OnLoadMore
@Override
public void onLoadMore() {
if (request.getPage() < totalPageAmount) {
request.nextPage();
LoadMoreTask task = new LoadMoreTask(request, words, adapter);
task.execute();
}
}
LoadMoreTask
public LoadMoreTask(Request request, ArrayList<Word> words, SearchResultAdapter adapter){
this.request=request;
this.words=words;
this.adapter=adapter;
this.connection = new Connection(request.getUrl());
}
@Override
protected void onPreExecute() {
super.onPreExecute();
if(words.get(words.size()-1)!=null){
words.add(null);
index = words.size() - 1;
adapter.notifyItemInserted(index);
}
}
@Override
protected Void doInBackground(Void... params) {
connection.connect();
String result = connection.getStringFromServer();
Respond respond = new Respond(result);
if(!request.isDetailed())
words.addAll(respond.handleSimple());
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
connection.disconnect();
if(index!=0 && words.get(index)==null){
words.remove(index);
adapter.notifyItemRemoved(index+1);
}
adapter.notifyDataSetChanged();
adapter.setLoading();
}
可以看出,当onLoadMore
触发时,我连接到网络服务器获取更多数据并将其附加到之前的arraylist
。在preExecute
中添加空对象是为了更改viewHolder
类型(我在列表末尾加载progressBar
,并在asynctask
完成后删除)。
这段代码非常有效,只是notifyDataSetChanged
冻结了UI一点点。是的,它足够小,只有当你滚动得太快才能看到,但无论如何它很烦人。我如何优化此代码以消除冻结?
答案 0 :(得分:2)
我使用notifyItemRangeInserted
函数解决了问题,似乎此函数需要的资源少于notifyDatasetChanged
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
connection.disconnect();
adapter.resetLoading();
if(index!=0 && words.get(index)==null){
words.remove(index);
adapter.notifyItemRemoved(index);
}
adapter.notifyItemRangeInserted(index,30);
}
所以使用这个代码一切都很完美,没有任何纳米冻结。