Drawable Recyclerview背景变化缓慢,错误在主线程上做了太多工作

时间:2016-10-31 04:35:34

标签: android android-recyclerview xml-drawable setbackground

我正在尝试设置在recyclerview上选择的项目的状态。 UI通过将单个单元格框架的背景更改为另一个可绘制的xml来完成此操作。

在recyclerview onBindViewHolder中,我做了如下改动:

 @Override
    public void onBindViewHolder(final DeviceAlarmTonesHolder holder, final int position) {
        final DeviceAlarmTone alarmTone = alarmTones.get(position);
        // set click listener
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                holder.alarmTonesButtonBackground.setBackgroundResource(R.drawable.layout_bg_selected);
                itemClickListener.onItemClicked(holder, alarmTone, position, oldPostion);

                // Refresh the ui for the previous button
                if (oldPostion != -1){
                    notifyItemChanged(oldPostion);
                }
                oldPostion = position;
            }
        });


        String alarmToneString = alarmTones.get(position).getNotificationTitle();
        holder.alarmTonesNameTextView.setText(alarmToneString);

    }

基本上在onclick中我正在更改当前项目的背景,然后在旧项目上调用notifyitemchanged以将背景恢复为未选中。

正在更改的背景是xml drawables,如下所示:

未选择的背景:

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#212121"/>
    <corners android:radius="10dip"/>
    <padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" />
</shape>

选择背景:

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#0091EA"/>
    <corners android:radius="10dip"/>
    <padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" />
</shape>

提前感谢您的帮助。

这里更新是我的完整适配器:

public class DeviceAlarmToneAdapter extends RecyclerView.Adapter<DeviceAlarmTonesHolder>{

    Context context;
    ArrayList<DeviceAlarmTone> alarmTones;
    DeviceAlarmToneClickListener itemClickListener;

    int oldPostion = -1;

    public DeviceAlarmToneAdapter(Context context, ArrayList<DeviceAlarmTone> alarmTones, DeviceAlarmToneClickListener itemClickListener) {
        this.context = context;
        this.alarmTones = alarmTones;
        this.itemClickListener = itemClickListener;
    }

    @Override
    public DeviceAlarmTonesHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.singlecell_devicealarmtoneslist, parent, false);
        DeviceAlarmTonesHolder holder = new DeviceAlarmTonesHolder(v, context);
        return holder;
    }

    @Override
    public void onBindViewHolder(final DeviceAlarmTonesHolder holder, final int position) {
        final DeviceAlarmTone alarmTone = alarmTones.get(position);
        // set click listener
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                holder.alarmTonesButtonBackgroundUnselected.setVisibility(View.INVISIBLE);
                holder.alarmTonesButtonBackgroundSelected.setVisibility(View.VISIBLE);
                itemClickListener.onItemClicked(holder, alarmTone, position, oldPostion);

                // Refresh the ui for the previous button
                if (oldPostion != -1){
                    notifyItemChanged(oldPostion);
                }
                oldPostion = position;
            }
        });


        String alarmToneString = alarmTones.get(position).getNotificationTitle();
        holder.alarmTonesNameTextView.setText(alarmToneString);

    }

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

}

1 个答案:

答案 0 :(得分:0)

public class DeviceAlarmToneAdapter extends RecyclerView.Adapter<DeviceAlarmTonesHolder>{

Context context;
ArrayList<DeviceAlarmTone> alarmTones;
DeviceAlarmToneClickListener itemClickListener;

int oldPostion = -1;

public DeviceAlarmToneAdapter(Context context, ArrayList<DeviceAlarmTone> alarmTones, DeviceAlarmToneClickListener itemClickListener) {
    this.context = context;
    this.alarmTones = alarmTones;
    this.itemClickListener = itemClickListener;
}

@Override
public DeviceAlarmTonesHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.singlecell_devicealarmtoneslist, parent, false);
    DeviceAlarmTonesHolder holder = new DeviceAlarmTonesHolder(v, context);
    return holder;
}

@Override
public void onBindViewHolder(final DeviceAlarmTonesHolder holder, final int position) {
    final DeviceAlarmTone alarmTone = alarmTones.get(position);


    String alarmToneString = alarmTones.get(position).getNotificationTitle();
    holder.alarmTonesNameTextView.setText(alarmToneString);

}

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


public class DeviceAlarmTonesHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

    // view fields are here

    public DeviceAlarmTonesHolder(View itemView){
        super(itemView);

        // find view by ids by using itemview.findViewById(id)

        itemView.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        // you shouldnt use two views as background objects to show unselected or selected background. Use selector drawables xml instead... and call view.setSelected(true or false);
        // Since your modifyng view object itself you dont need to call notifyItemChanged...
        // with this tecnique you have only one View.OnClickListener object which belongs to your holder that have only one instance. This will lower your memory usage and fluid scrolls.

        if (itemClickListener != null){
            int position = getAdapterPosition();
            alarmTone = alarmTones.get(position);

            itemClickListener.onAlarmClicked(alarmTone);
        }
    }
}

}

我只是绕过更新以前的背景来检查是否出现问题。

您需要降低onBindHolder中的进程并避免在其中创建对象。因为每次滚动时都不想使用旧对象创建更多对象。

//您不应使用两个视图作为背景对象来显示未选择或选定的背景。使用selector drawables xml代替...并调用view.setSelected(true或false);还优化您的背景。减少它们的尺寸。有很多在线工具可以帮到你。另一方面,如果他们是像jpegs和pngs这样的图片,请将它们放入drawable-nodpi文件夹中以排除调整大小。

由于您的modifyng视图对象本身,您不需要调用notifyItemChanged ...

使用此tecnique,您只有一个View.OnClickListener对象属于您的持有者,该对象只有一个实例。

这会降低你的内存使用量和流畅的滚动。

如果出现问题,您可能需要使用Single Choice RecyclerView库或寻找其他解决方案。

祝你好运