由于onBindViewHolder(),RecyclerView适配器是滞后的

时间:2016-09-07 06:39:04

标签: android android-recyclerview android-adapter

我有一个带有RecyclerView和自定义Adapter的应用,它可以从解析后端获取。

我的适配器包含一些TextView,一个Button,一个小ImageView。我的TextView中的某些Adapter需要在onBindViewHolder()的{​​{1}}中使用函数(计算upvote计数和类似内容)来获取数据。

我注意到由于onBindViewHolder()中调用的函数,我的滚动速度非常慢且滞后。

我应该在哪里设置数据并调用我的函数才能顺利滚动?

编辑1:

这是我的适配器代码:

public class PostAdapter extends RecyclerView.Adapter<PostAdapter.ViewHolder> {
public static class ViewHolder extends RecyclerView.ViewHolder {
    public TextView     postName;
    public ImageView    postCatIcon;

    public TextView     postDays;
    public TextView     postDaysLabel;
    public TextView     postHours;
    public TextView     postHoursLabel;
    public TextView     postMinutes;
    public TextView     postMinutesLabel;
    public TextView     postDistance;

    public TextView     postLikes;
    public TextView     postAuthor;
    public LikeButton   likepost;

    private Post post;


    public ViewHolder(View itemView) {
        super(itemView);
        postName    = (TextView) itemView.findViewById(R.id.post_name);
        postCatIcon = (ImageView) itemView.findViewById(R.id.post_cat_icon);

        postDays            = (TextView) itemView.findViewById(R.id.post_days);
        postDaysLabel       = (TextView) itemView.findViewById(R.id.post_days_label);
        postHours           = (TextView) itemView.findViewById(R.id.post_hours);
        postHoursLabel      = (TextView) itemView.findViewById(R.id.post_hours_label);
        postMinutes         = (TextView) itemView.findViewById(R.id.post_minutes);
        postMinutesLabel    = (TextView) itemView.findViewById(R.id.post_minutes_label);
        postDistance        = (TextView) itemView.findViewById(R.id.post_distance);

        likePost    = (LikeButton) itemView.findViewById(R.id.like_the_post);
        postAuthor  = (TextView) itemView.findViewById(R.id.post_author);
        postLikes   = (TextView) itemView.findViewById(R.id.post_likes);
    }

    public void setData(Post post){
        this.post = post;
        updateTimeRemaining(System.currentTimeMillis());
    }

    public void updateTimeRemaining(long currentTime) {
        long diff = post.getDate().getTime() - currentTime;

        int minutes = (int) ((diff / (1000*60)) % 60);
        int hours   = (int) ((diff / (1000*60*60)) % 24);
        int days = (int) (diff / (1000*60*60*24));


        String strgMinutes = "00";
        String strgHours = "00";
        String strgDays = "00";

        if(minutes < 10)
            strgMinutes = "0" + String.valueOf(minutes);
        else
            strgMinutes = String.valueOf(minutes);

        if(hours < 10)
            strgHours = "0" + String.valueOf(hours);
        else
            strgHours = String.valueOf(hours);

        if(days < 10){
            strgDays = "0" + String.valueOf(days);
        }else
            strgDays = String.valueOf(days);

        postDays.setText(strgDays);
        postHours.setText(strgHours);
        postMinutes.setText(strgMinutes);
    }
}

public static class ProgressViewHolder extends PostAdapter.ViewHolder {
    public ProgressBar progressBar;

    public ProgressViewHolder(View v) {
        super(v);
        progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
    }
}

private List<Post> mPosts;
private Context mContext;
private ListFragment mFragment;

private final int VIEW_ITEM = 1;
private final int VIEW_PROG = 0;

ArrayList<PostAdapter.ViewHolder> viewHoldersList;
private Handler handler = new Handler();
private Runnable updateRemainingTimeRunnable = new Runnable() {
    @Override
    public void run() {
        long currentTime = System.currentTimeMillis();
        synchronized (viewHoldersList) {
            for (PostAdapter.ViewHolder holder : viewHoldersList) {
                holder.updateTimeRemaining(currentTime);
            }
        }
        handler.postDelayed(this, 60000);
    }
};

// The minimum amount of items to have below your current scroll position before loading more.
private int visibleThreshold = 2;
private int lastVisibleItem, totalItemCount;
private boolean loading;
private OnLoadMoreListener onLoadMoreListener;

public PostAdapter(List<Post> posts, Context context, ListFragment fragment, RecyclerView recyclerView) {
    mContext = context;
    mPosts = posts;
    mFragment = fragment;

    if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {

        final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                totalItemCount = linearLayoutManager.getItemCount();
                lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
                if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                    // End has been reached
                    // Do something
                    if (onLoadMoreListener != null) {
                        onLoadMoreListener.onLoadMore();
                    }
                    loading = true;
                }
            }
        });
    }

    viewHoldersList = new ArrayList<>();
    startUpdateTimer();
}

public PostAdapter(List<Post> posts, Context context, RecyclerView recyclerView) {
    mContext = context;
    mPosts = posts;

    if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {

        final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                totalItemCount = linearLayoutManager.getItemCount();
                lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
                if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                    // End has been reached
                    // Do something
                    if (onLoadMoreListener != null) {
                        onLoadMoreListener.onLoadMore();
                    }
                    loading = true;
                }
            }
        });
    }
    viewHoldersList = new ArrayList<>();
    startUpdateTimer();
}

private void startUpdateTimer() {
    handler.postDelayed(updateRemainingTimeRunnable,60000);
}

public PostAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    Context context         = parent.getContext();
    LayoutInflater inflater = LayoutInflater.from(context);
    View postView;
    ViewHolder viewHolder;

    if (viewType == VIEW_ITEM) {
        postView = inflater.inflate(R.layout.list_item, parent, false);

         viewHolder = new ViewHolder(postView);
    } else {
        postView = inflater.inflate(R.layout.loading_item, parent, false);

        viewHolder = new ProgressViewHolder(postView);
    }

    return viewHolder;
}

public void onBindViewHolder(final PostAdapter.ViewHolder viewHolder, final int position) {
    if (viewHolder instanceof ViewHolder) {
        final Post post = mPosts.get(position);
        if(post != null){
            synchronized (viewHoldersList) {
                viewHolder.setData(post);
                viewHoldersList.add(viewHolder);
            }

            Category cat                    = post.getCategory();
            TextView nameTextView           = viewHolder.postName;
            TextView authorTextView         = viewHolder.postAuthor;
            final TextView likesTextView    = viewHolder.postLikes;
            ImageView CatIconView           = viewHolder.postCatIcon;
            final LikeButton likeButtonView = viewHolder.likePost;
            TextView postDistance           = viewHolder.postDistance;
            ParseUser postAuthor = null;

            if(mFragment != null) {
                if (mFragment.getIfFilteredByDistance()) {
                    postDistance.setVisibility(View.VISIBLE);
                    Location postLocation = new Location("Post location");
                    if(post.getLocation() != null){
                        postLocation.setLongitude(post.getLocation().getLongitude());
                        postLocation.setLatitude(post.getLocation().getLatitude());

                        GPSTracker gpsTracker = new GPSTracker(mContext);
                        if (gpsTracker.canGetLocation()) {
                            Location myLocation = new Location("My location");
                            myLocation.setLatitude(gpsTracker.getLatitude());
                            myLocation.setLongitude(gpsTracker.getLongitude());

                            postDistance.setText((Math.round(myLocation.distanceTo(postLocation)) / 1000) + " km");
                        } else
                            gpsTracker.showSettingsAlert();
                    }
                } else
                    postDistance.setVisibility(View.INVISIBLE);
            }


            try{
                postAuthor = post.getAuthor().fetchIfNeeded();
            }catch (ParseException e){
                Log.e("Parse:", e.getMessage());
            }

            saveActivitiesToLocalDatastore(post);

            final int likeCount = ((PostApplication)mContext).getPostLikeCount(post);
            likesTextView.setText(String.valueOf(likeCount));

            likeButtonView.setLiked(((PostApplication)mContext).getIfLiked(post));

            viewHolder.itemView.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(mContext, DetailActivity.class);
                    intent.putExtra("PostID",post.getObjectId());
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    mContext.startActivity(intent);
                }
            });

            likeButtonView.setOnLikeListener(new OnLikeListener() {
                @Override
                public void liked(LikeButton likeButton) {
                    if(((PostApplication)mContext).likePost(post))
                        likesTextView.setText(String.valueOf(Integer.parseInt(likesTextView.getText().toString()) + 1));
                }

                @Override
                public void unLiked(LikeButton likeButton) {
                    if(((PostApplication)mContext).unlikePost(post))
                        likesTextView.setText(String.valueOf(Integer.parseInt(likesTextView.getText().toString()) -1));

                }
            });


            nameTextView.setText(post.getTitle());
            authorTextView.setText(post.getAuthor().getUsername());


            CatIconView.setImageDrawable(ContextCompat.getDrawable(mContext,mContext.getResources().getIdentifier(cat.getIconName()+"_18dp","drawable",mContext.getPackageName())));

        }
    } else {
        ((ProgressViewHolder) viewHolder).progressBar.setIndeterminate(true);
    }
}



public int getItemCount() {
    return mPosts.size();
}

private void saveActivitiesToLocalDatastore(final Post post){
    // Saves Likes to Parse local datastore
}

@Override
public int getItemViewType(int position) {
    return mposts.get(position) != null ? VIEW_ITEM : VIEW_PROG;
}


public void setLoaded() {
    loading = false;
}

public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
    this.onLoadMoreListener = onLoadMoreListener;
}

public interface OnLoadMoreListener {
    void onLoadMore();
}

编辑2:

我按照这个来修复我倒计时的闪烁:

Recyclerview with multiple countdown timers causes flickering

编辑3:

我尝试运行应用程序而没有像saveActivitiesInBackgroud这样的附加方法,而且听众也很顺利

2 个答案:

答案 0 :(得分:2)

如果你想使用RecyclerView你需要使用onBindViewHolder。它与OnBindViewHolder没有问题。问题是你的意大利面条代码,你也没有存储信息,所以这导致你的recyclerview滞后

答案 1 :(得分:1)

  • 尽量不要在ViewHolder之外更改onBindViewHolder()州。 ViewHolder表示屏幕上的视图,但不代表数据本身。 RecyclerView会在屏幕上显示不可见时重复使用视图,因此会重复使用附加到该视图的ViewHolder视图。

  • 永远不要存储ViewHolder - RecyclerView负责管理它们。

  • 如果您仅在60 secnotifyDataSetChanges更新计时器,而不是直接更新ViewHolder。并在适当的时间更新onBindViewHolder中的视图状态。