带有Asynctask的无尽RecyclerView

时间:2016-06-25 23:33:31

标签: android android-asynctask android-recyclerview recycler-adapter notifydatasetchanged

我有一个具有无尽的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一点点。是的,它足够小,只有当你滚动得太快才能看到,但无论如何它很烦人。我如何优化此代码以消除冻结?

1 个答案:

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

所以使用这个代码一切都很完美,没有任何纳米冻结。