java - 如何并行连续递增多个 RecyclerView 值

标签 java android multithreading android-recyclerview

上下文

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

目标

  • 在按下开始按钮时开始并继续递增一个值
  • 必须能够通过其按钮单独启动每个项目的值
  • 一旦启动,多个值必须能够并行连续递增

问题

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

如何在不减慢 UI 的情况下,在更新 RecyclerView 的同时连续并行增加各个值?

到目前为止尝试了什么

  • 使用 HandlerThreadrunOnUiThread
  • 为每个 MyValue 对象使用单独的 Thread
  • 考虑过 AsyncTask,但将来“增加多个值”行为可能需要独立于 Activity 在后台运行(即,仅更新 GUI当 Activity 处于前台时),因此行为可能会转移到 BoundService
  • 可以使用 LiveDataRecyclerView 项目根据 MyValue 中的值进行观察和更新,但是,不确定 LiveData 如何可以与 MyValueValuesAdapter
  • 一起使用

代码

主要 Activity

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

}

值 Controller

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();
            }
        }
    }

}

我的值(value)

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;
    }

}

最佳答案

问题

似乎是通过 MyValue.ValueListener.onTick 完成了高频率的工作(即,在增加值和更新 RecyclerView TextView 值时跳过大约 2000 帧) ()

解决方案

当前的解决方案是延迟 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);
}

关于java - 如何并行连续递增多个 RecyclerView 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52138669/

相关文章:

java - 为什么这个gcd方法不起作用?

java - 在 JTextField 中使用自定义 Caret 以实现可访问性

java - java.awt.Color 对象的大小

java - Android 中的实时音频处理

javascript - 仅允许在 Android 应用程序上访问文件并使用 .htaccess 或 javascript 禁用浏览器访问..?

c++ - 同时多次运行一个进程

android - 如何在 android 数据绑定(bind)中使用逻辑操作?

android - list 文件的 "modern"外观

java - 实时服务器 CPU 使用率高时的线程转储分析

multithreading - 线程::队列什么都不返回