首页 > 解决方案 > 如何并行连续递增多个 RecyclerView 值

问题描述

语境

使用RecyclerView每个都有标签和值的项目TextViews,以及一个开始Button

目标

问题

UI(值TextView、点击Button等)在 2 个或更多值开始递增后变慢。不确定如何处理线程(尝试过HandlerThread/ runOnUiThread,当前为每个MyValue对象使用单独的线程),请参见下面MyValue.start()代码

如何在RecyclerView不减慢 UI 的情况下在更新的同时并行不断地增加单个值?

到目前为止已经尝试过什么

代码

主要活动

public class MainActivity extends AppCompatActivity {

    ArrayList<MyValue> mValues;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = findViewById(R.id.recycler_view);
        recyclerView.setHasFixedSize(true);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(linearLayoutManager);

        mValues = new ArrayList<>();
        mValues.add(new MyValue("value 1"));
        mValues.add(new MyValue("value 2"));
        mValues.add(new MyValue("value 3"));
        ValuesAdapter valuesAdapter = new ValuesAdapter(mValues);
        recyclerView.setAdapter(valuesAdapter);
    }

}

值适配器

public class ValuesAdapter extends RecyclerView.Adapter<ValuesAdapter.ValueViewHolder> {
    private List<MyValue> mValues;
    private Context mContext;
    private ValueController mValueController;

    public ValuesAdapter(List<MyValue> values) {
        mValues = values;
        mValueController = new ValueController(mValues);
    }

    @Override
    public ValueViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mContext == null) {
            mContext = parent.getContext();
        }
        LayoutInflater layoutInflater = LayoutInflater.from(mContext);

        View valueView = layoutInflater.inflate(R.layout.value_item, parent, false);

        return new ValueViewHolder(valueView);
    }

    @Override
    public void onBindViewHolder(ValueViewHolder holder, int position) {
        MyValue value = mValues.get(position);
        String label = value.getLabel();
        int currentValue = value.getValue();
        holder.setupViewHolder(label, "" + currentValue);
        value.setListener(holder);
    }

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

    class ValueViewHolder extends RecyclerView.ViewHolder
            implements MyValue.ValueListener {

        TextView mLabel;
        TextView mValue;
        Button mStart;

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

            mLabel = itemView.findViewById(R.id.label);
            mValue = itemView.findViewById(R.id.value);
            mStart = itemView.findViewById(R.id.start);
        }

        public void setupViewHolder(String label, String currentValue) {
            mLabel.setText(label);
            mValue.setText(currentValue);
            int adapterPosition = getAdapterPosition();
            final MyValue value = mValues.get(adapterPosition);

            mStart.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    value.start();
                }
            });
        }

        @Override
        public void onTick(final int currentValue) {
            mValueController.incActiveStopwatches();

            ((Activity) mContext).runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mValue.setText("" + currentValue);
                }
            });
        }
    }

}

值控制器

public class ValueController {

    private List<MyValue> mValues;

    public ValueController(List<MyValue> values) {
        mValues = values;
    }

    public void incrementActiveValues() {
        for (int i = 0; i < mValues.size(); i++) {
            MyValue value = mValues.get(i);
            if (value.getShouldIncrement()) {
                value.increment();
            }
        }
    }

}

我的价值

public class MyValue {

    private String mLabel;
    private int mCurrentValue;
    private boolean mShouldIncrement;
    private Handler mHandler;
    private ValueListener mListener;

    public MyValue(String label) {
        mLabel = label;

        HandlerThread handlerThread = new HandlerThread("HandlerThread1");
        handlerThread.start();
        mHandler = new Handler(handlerThread.getLooper());
    }

    public String getLabel() {
        return mLabel;
    }

    public int getValue() {
        return mCurrentValue;
    }

    public void increment() {
        mCurrentValue++;
    }

    public void start() {
        mShouldIncrement = true;
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (mShouldIncrement) {
                    increment();
                    if (mListener != null) {
                        mListener.onTick(mCurrentValue);
                    }
                }
            }
        }).start();

//        mHandler.post(new Runnable() {
//            @Override
//            public void run() {
//                while (mShouldIncrement) {
//                    increment();
//                    if (mListener != null) {
//                        mListener.onTick(mCurrentValue);
//                    }
//                }
//            }
//        });
    }

    public void setListener(ValueListener listener) {
        mListener = listener;
    }

    public interface ValueListener {
        void onTick(int currentValue);
    }

    public boolean getShouldIncrement() {
        return mShouldIncrement;
    }

}

标签: javaandroidmultithreadingandroid-recyclerview

解决方案


问题

似乎RecyclerView TextView通过MyValue.ValueListener.onTick().

解决方案

当前的解决方案是延迟onTick到仅每 1 秒触发一次,即替换MyValue.start()为:

private Runnable mRepeatIncrementRunnable = new Runnable() {
    @Override
    public void run() {
        if (mShouldIncrement) {
            increment();
            if (mListener != null) {
                mListener.onTick(mCurrentValue);
            }
        } else {
            mHandler.removeCallbacks(this);
            return;
        }
        mHandler.postDelayed(this, mTickIntervalMs);
    }
};

public void start() {
    mShouldIncrement = true;
    mHandler.post(mRepeatIncrementRunnable);
}

推荐阅读