選択可能なRecyclerViewのパフォーマンスの問題

woodii

私は現在、毎週の時間枠を編集するアプリを実現しようとしています。ソケット用の機械式タイマーのようですが、私の場合は平日です。

ここに画像の説明を入力してください

粒度はそもそも二次的なものです(15分または30分になると思います)。

私のアプローチだったRecyclerViewGridLayoutManagerし、ArrayAdapterすべてのセルのためのアイテムを。

さらにセルを選択するには、セルを長押しして他のセルの上にドラッグします。これを実現するために、次のライブラリDragSelectRecyclerViewのリスナーを使用しました

それはかなりうまく機能し、あなたは非常に良いアイテムを選ぶことができますが、特にエミュレーターや古い電話では非常に遅くて遅いです。デバッグログキャットでは、ビューのレンダリング時および複数のセルの選択時に、コレオグラファーが多くのフレームをスキップする必要があることもわかります。

ここに画像の説明を入力してください

そのような振る舞いを達成するためのより良いアプローチはありますか?それとも、コードに非常に遅くてくだらない大きな間違いがありますか?

編集:

その方法に変更notifyItemChanged(pos);した後、notifyItemRangeChanged(pos, pos);ラグは少なくなりましたが、それでも期待どおりに機能していません。

また、コードを単純化するために、自動スクロール(上記のライブラリの機能)の原因となっているものをすべて削除しました。

ここに私のソース Fragment

    public class TestFragment extends Fragment
    {
        @BindView(R.id.gridView_hours) GridView gridView_hours;
        @BindView(R.id.weekdays_container) LinearLayout weekdays_container;

        private String[] hours = new String[]{"00:00", "01:00", "02:00", "03:00", "04:00", "05:00", "06:00", "07:00", "08:00", "09:00", "10:00", "11:00", "12:00", "13:00", "14:00", "15:00", "16:00", "17:00", "18:00", "19:00", "20:00", "21:00", "22:00", "23:00"};
        private String[] hoursShort = new String[]{"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"};

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
        }

        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
        {
            View view = inflater.inflate(R.layout.fragment_test, container, false);
            ButterKnife.bind(this, view);

            for (int i = 1; i <= 7; i++)
            {
                RecyclerView recyclerView = new RecyclerView(getActivity());
                initAdapter(recyclerView);

                GridLayoutManager glm = new GridLayoutManager(getActivity(), 48, GridLayoutManager.VERTICAL, false);
                recyclerView.setLayoutManager(glm);

                weekdays_container.addView(recyclerView);

            }
            gridView_hours.setAdapter(new ArrayAdapter<String>(getActivity(), R.layout.hour_view, hoursShort));

    //        GridLayoutManager glm = new GridLayoutManager(getActivity(), 48, GridLayoutManager.VERTICAL, false);
    //        recyclerView.setLayoutManager(glm);

            return view;
        }

        private void initAdapter(RecyclerView recyclerView)
        {
            TestAutoDataAdapter adapter = new TestAutoDataAdapter(getActivity(), 48);
            recyclerView.setAdapter(adapter);

            DragSelectionProcessor dragSelectionProcessor = new DragSelectionProcessor(new DragSelectionProcessor.ISelectionHandler() {
                @Override
                public HashSet<Integer> getSelection() {
                    return adapter.getSelection();
                }

                @Override
                public boolean isSelected(int index) {
                    return adapter.getSelection().contains(index);
                }

                @Override
                public void updateSelection(int start, int end, boolean isSelected, boolean calledFromOnStart) {
                    adapter.selectRange(start, end, isSelected);
                }
            });

            DragSelectTouchListener dragSelectTouchListener = new DragSelectTouchListener()
                    .withSelectListener(dragSelectionProcessor);
            recyclerView.addOnItemTouchListener(dragSelectTouchListener);

            adapter.setClickListener(new TestAutoDataAdapter.ItemClickListener()
            {
                @Override
                public void onItemClick(View view, int position)
                {
                    adapter.toggleSelection(position);
                }

                @Override
                public boolean onItemLongClick(View view, int position)
                {
                    dragSelectTouchListener.startDragSelection(position);
                    return true;
                }
            });
        }
    }

そしてその RecyclerView.Adapter

    public class TestAutoDataAdapter extends RecyclerView.Adapter<TestAutoDataAdapter.ViewHolder>
    {

        private int dataSize;
        private Context context;
        private ItemClickListener clickListener;

        private HashSet<Integer> selected;

        public TestAutoDataAdapter(Context context, int size)
        {
            this.context = context;
            dataSize = size;
            selected = new HashSet<>();
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
        {
            View view = LayoutInflater.from(context).inflate(R.layout.test_cell, parent, false);
            ViewHolder viewHolder = new ViewHolder(view);
            return viewHolder;
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, int position)
        {
            holder.tvText.setText("");
            if (selected.contains(position))
                holder.tvText.setBackgroundColor(Color.RED);
            else
                holder.tvText.setBackgroundColor(Color.WHITE);
        }

        @Override
        public int getItemCount()
        {
            return dataSize;
        }

        // ----------------------
        // Selection
        // ----------------------

        public void toggleSelection(int pos)
        {
            if (selected.contains(pos))
                selected.remove(pos);
            else
                selected.add(pos);
            notifyItemChanged(pos);
        }

        public void select(int pos, boolean selected)
        {
            if (selected)
                this.selected.add(pos);
            else
                this.selected.remove(pos);
            notifyItemRangeChanged(pos, pos);
        }

        public void selectRange(int start, int end, boolean selected)
        {
            for (int i = start; i <= end; i++)
            {
                if (selected)
                    this.selected.add(i);
                else
                    this.selected.remove(i);
            }
            notifyItemRangeChanged(start, end - start + 1);
        }

        public void deselectAll()
        {
            // this is not beautiful...
            selected.clear();
            notifyDataSetChanged();
        }

        public void selectAll()
        {
            for (int i = 0; i < dataSize; i++)
                selected.add(i);
            notifyDataSetChanged();
        }

        public int getCountSelected()
        {
            return selected.size();
        }

        public HashSet<Integer> getSelection()
        {
            return selected;
        }

        // ----------------------
        // Click Listener
        // ----------------------

        public void setClickListener(ItemClickListener itemClickListener)
        {
            clickListener = itemClickListener;
        }

        public interface ItemClickListener
        {
            void onItemClick(View view, int position);
            boolean onItemLongClick(View view, int position);
        }

        // ----------------------
        // ViewHolder
        // ----------------------

        public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener
        {
            public TextView tvText;

            public ViewHolder(View itemView)
            {
                super(itemView);
                tvText = itemView.findViewById(R.id.tvText);
                itemView.setOnClickListener(this);
                itemView.setOnLongClickListener(this);
            }

            @Override
            public void onClick(View view)
            {
                if (clickListener != null)
                    clickListener.onItemClick(view, getAdapterPosition());
            }

            @Override
            public boolean onLongClick(View view)
            {
                if (clickListener != null)
                    return clickListener.onItemLongClick(view, getAdapterPosition());
                return false;
            }
        }
    }

SelectTouchListener

    public class DragSelectTouchListener implements RecyclerView.OnItemTouchListener
    {
        private static final String TAG = "DSTL";

        private boolean mIsActive;
        private int mStart, mEnd;
        private int mLastStart, mLastEnd;

        private OnDragSelectListener mSelectListener;

        public DragSelectTouchListener()
        {
            reset();
        }

        /**
         * sets the listener
         * <p>
         *
         * @param selectListener the listener that will be notified when items are (un)selected
         */
        public DragSelectTouchListener withSelectListener(OnDragSelectListener selectListener)
        {
            this.mSelectListener = selectListener;
            return this;
        }

        // -----------------------
        // Main functions
        // -----------------------

        /**
         * start the drag selection
         * <p>
         *
         * @param position the index of the first selected item
         */
        public void startDragSelection(int position)
        {
            setIsActive(true);
            mStart = position;
            mEnd = position;
            mLastStart = position;
            mLastEnd = position;
            if (mSelectListener != null && mSelectListener instanceof OnAdvancedDragSelectListener)
                ((OnAdvancedDragSelectListener)mSelectListener).onSelectionStarted(position);
        }

        // -----------------------
        // Functions
        // -----------------------

        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
        {
            if (!mIsActive || rv.getAdapter().getItemCount() == 0)
                return false;

            int action = e.getAction();
            switch (action)
            {
                case MotionEvent.ACTION_POINTER_DOWN:
                case MotionEvent.ACTION_DOWN:
                    reset();
                    break;
            }

            return true;
        }

        @Override
        public void onTouchEvent(RecyclerView rv, MotionEvent e)
        {
            if (!mIsActive)
                return;

            int action = e.getAction();
            switch (action)
            {
                case MotionEvent.ACTION_MOVE:
                    updateSelectedRange(rv, e);
                    break;
                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_POINTER_UP:
                    reset();
                    break;
            }
        }

        private void updateSelectedRange(RecyclerView rv, MotionEvent e)
        {
            updateSelectedRange(rv, e.getX(), e.getY());
        }

        private void updateSelectedRange(RecyclerView rv, float x, float y)
        {
            View child = rv.findChildViewUnder(x, y);
            if (child != null)
            {
                int position = rv.getChildAdapterPosition(child);
                if (position != RecyclerView.NO_POSITION && mEnd != position)
                {
                    mEnd = position;
                    notifySelectRangeChange();
                }
            }
        }

        private void notifySelectRangeChange()
        {
            if (mSelectListener == null)
                return;
            if (mStart == RecyclerView.NO_POSITION || mEnd == RecyclerView.NO_POSITION)
                return;

            int newStart, newEnd;
            newStart = Math.min(mStart, mEnd);
            newEnd = Math.max(mStart, mEnd);
            if (mLastStart == RecyclerView.NO_POSITION || mLastEnd == RecyclerView.NO_POSITION)
            {
                if (newEnd - newStart == 1)
                    mSelectListener.onSelectChange(newStart, newStart, true);
                else
                    mSelectListener.onSelectChange(newStart, newEnd, true);
            }
            else
            {
                if (newStart > mLastStart)
                    mSelectListener.onSelectChange(mLastStart, newStart - 1, false);
                else if (newStart < mLastStart)
                    mSelectListener.onSelectChange(newStart, mLastStart - 1, true);

                if (newEnd > mLastEnd)
                    mSelectListener.onSelectChange(mLastEnd + 1, newEnd, true);
                else if (newEnd < mLastEnd)
                    mSelectListener.onSelectChange(newEnd + 1, mLastEnd, false);
            }

            mLastStart = newStart;
            mLastEnd = newEnd;
        }

        private void reset()
        {
            setIsActive(false);
            if (mSelectListener != null && mSelectListener instanceof OnAdvancedDragSelectListener)
                ((OnAdvancedDragSelectListener)mSelectListener).onSelectionFinished(mEnd);
            mStart = RecyclerView.NO_POSITION;
            mEnd = RecyclerView.NO_POSITION;
            mLastStart = RecyclerView.NO_POSITION;
            mLastEnd = RecyclerView.NO_POSITION;
        }

        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept)
        {
            // ignore
        }

        public void setIsActive(boolean isActive)
        {
            this.mIsActive = isActive;
        }

        // -----------------------
        // Interfaces and simple default implementations
        // -----------------------

        public interface OnAdvancedDragSelectListener extends OnDragSelectListener
        {
            /**
             * @param start      the item on which the drag selection was started at
             */
            void onSelectionStarted(int start);

            /**
             * @param end      the item on which the drag selection was finished at
             */
            void onSelectionFinished(int end);
        }

        public interface OnDragSelectListener
        {
            /**
             * @param start      the newly (un)selected range start
             * @param end        the newly (un)selected range end
             * @param isSelected true, it range got selected, false if not
             */
            void onSelectChange(int start, int end, boolean isSelected);
        }
    }

および必要なインターフェースの実装

    public class DragSelectionProcessor implements DragSelectTouchListener.OnAdvancedDragSelectListener {

        private ISelectionHandler mSelectionHandler;
        private HashSet<Integer> mOriginalSelection;
        private boolean mFirstWasSelected;
        private boolean mCheckSelectionState = false;

        public DragSelectionProcessor(ISelectionHandler selectionHandler)
        {
            mSelectionHandler = selectionHandler;
        }

        @Override
        public void onSelectionStarted(int start)
        {
            mOriginalSelection = new HashSet<>();
            Set<Integer> selected = mSelectionHandler.getSelection();
            if (selected != null)
                mOriginalSelection.addAll(selected);
            mFirstWasSelected = mOriginalSelection.contains(start);

            mSelectionHandler.updateSelection(start, start, !mFirstWasSelected, true);

        }

        @Override
        public void onSelectionFinished(int end)
        {
            mOriginalSelection = null;
        }

        @Override
        public void onSelectChange(int start, int end, boolean isSelected)
        {
            for (int i = start; i <= end; i++)
                checkedUpdateSelection(i, i, isSelected ? !mFirstWasSelected :  mOriginalSelection.contains(i));
        }

        private void checkedUpdateSelection(int start, int end, boolean newSelectionState)
        {
            if (mCheckSelectionState)
            {
                for (int i = start; i <= end; i++)
                {
                    if (mSelectionHandler.isSelected(i) != newSelectionState)
                        mSelectionHandler.updateSelection(i, i, newSelectionState, false);
                }
            }
            else
                mSelectionHandler.updateSelection(start, end, newSelectionState, false);
        }

        public interface ISelectionHandler
        {
            Set<Integer> getSelection();

            boolean isSelected(int index);

            void updateSelection(int start, int end, boolean isSelected, boolean calledFromOnStart);
        }
    }
ジル

それぞれの選択プロセスでnotifyItemRangeChanged(pos, pos);notifyDataSetChanged()などは使用しません

なぜあなたはこれが好きではないのですか。

1.次のようにアダプタでrecyclerview参照を取得します。

 private RecyclerView mRecyclerView;
 public TestAutoDataAdapter(Context context, int size, RecyclerView pRecyclerView){
        this.mRecyclerView = pRecyclerView;
        ..

2.選択したビューホルダーの背景色を次のように設定します。

       public void select(int pos, boolean selected){
          // Get selected view holder from recyclerview
          ViewHolder holder = recyclerview..findViewHolderForAdapterPosition(pos);

            if (selected)
                this.selected.add(pos);
            else
                this.selected.remove(pos);
            //notifyItemRangeChanged(pos, pos);
            holder.tvText.setBackgroundColor(selected ? Color.RED : Color.WHITE);

        }

このように選択プロセス全体を変更して、結果をお知らせください。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

MySQLはJDBCでパフォーマンスの問題を選択します

分類Dev

副選択でn個の最新の行を選択する際のパフォーマンスの問題

分類Dev

Coldfusion10で再現可能なCFQUERYPARAMのパフォーマンスの問題

分類Dev

リンクリストの選択ソートの実装パフォーマンスの問題?

分類Dev

各プレイヤーの最新レコードの選択と注文(パフォーマンスの問題)

分類Dev

パフォーマンスの問題

分類Dev

単純な更新/選択でのMysqlテーブルのパフォーマンスの問題(大きなテーブル、多くの接続)

分類Dev

Angular 2 * ng選択/オプションのパフォーマンスの問題

分類Dev

yaml-cppの主なパフォーマンスの問題

分類Dev

DataReaderのパフォーマンスの問題、奇妙な動作

分類Dev

奇妙なKinecticjsのパフォーマンスの問題

分類Dev

UICollectionビューのスクロール可能な年ビュー:パフォーマンスの問題

分類Dev

IE8は人口パフォーマンスの問題を選択します-解決策が必要です

分類Dev

予期しないパフォーマンスの問題

分類Dev

SQLパフォーマンスの問題:明確な200人の顧客が見つかるまでN行を選択します

分類Dev

パンダのパフォーマンス:列の選択

分類Dev

グループごとの最大行を選択します-パンダのパフォーマンスの問題

分類Dev

Rのループのパフォーマンスの問題

分類Dev

DjangoAdminの重大なパフォーマンスの問題-外部キーラベル

分類Dev

RecyclerViewの画像をダウンロードする際のパフォーマンスの問題

分類Dev

Pythonnumpyのパフォーマンス-非常に大きな配列での選択

分類Dev

表形式のレポート用のPostgreSQLの内部選択に関するSQLパフォーマンスの問題

分類Dev

Springの@Autowiredは大きなパフォーマンスの問題ですか?

分類Dev

奇妙なJavaScript / Node.jsのパフォーマンスの問題

分類Dev

SQLServerクエリの断続的なパフォーマンスの問題

分類Dev

単純なクエリでのパフォーマンスの問題

分類Dev

春の起動時のパフォーマンスの問題

分類Dev

matplotlibの凡例のパフォーマンスの問題

分類Dev

PageStorageKeyでのFlutterListViewのパフォーマンスの問題

Related 関連記事

  1. 1

    MySQLはJDBCでパフォーマンスの問題を選択します

  2. 2

    副選択でn個の最新の行を選択する際のパフォーマンスの問題

  3. 3

    Coldfusion10で再現可能なCFQUERYPARAMのパフォーマンスの問題

  4. 4

    リンクリストの選択ソートの実装パフォーマンスの問題?

  5. 5

    各プレイヤーの最新レコードの選択と注文(パフォーマンスの問題)

  6. 6

    パフォーマンスの問題

  7. 7

    単純な更新/選択でのMysqlテーブルのパフォーマンスの問題(大きなテーブル、多くの接続)

  8. 8

    Angular 2 * ng選択/オプションのパフォーマンスの問題

  9. 9

    yaml-cppの主なパフォーマンスの問題

  10. 10

    DataReaderのパフォーマンスの問題、奇妙な動作

  11. 11

    奇妙なKinecticjsのパフォーマンスの問題

  12. 12

    UICollectionビューのスクロール可能な年ビュー:パフォーマンスの問題

  13. 13

    IE8は人口パフォーマンスの問題を選択します-解決策が必要です

  14. 14

    予期しないパフォーマンスの問題

  15. 15

    SQLパフォーマンスの問題:明確な200人の顧客が見つかるまでN行を選択します

  16. 16

    パンダのパフォーマンス:列の選択

  17. 17

    グループごとの最大行を選択します-パンダのパフォーマンスの問題

  18. 18

    Rのループのパフォーマンスの問題

  19. 19

    DjangoAdminの重大なパフォーマンスの問題-外部キーラベル

  20. 20

    RecyclerViewの画像をダウンロードする際のパフォーマンスの問題

  21. 21

    Pythonnumpyのパフォーマンス-非常に大きな配列での選択

  22. 22

    表形式のレポート用のPostgreSQLの内部選択に関するSQLパフォーマンスの問題

  23. 23

    Springの@Autowiredは大きなパフォーマンスの問題ですか?

  24. 24

    奇妙なJavaScript / Node.jsのパフォーマンスの問題

  25. 25

    SQLServerクエリの断続的なパフォーマンスの問題

  26. 26

    単純なクエリでのパフォーマンスの問題

  27. 27

    春の起動時のパフォーマンスの問題

  28. 28

    matplotlibの凡例のパフォーマンスの問題

  29. 29

    PageStorageKeyでのFlutterListViewのパフォーマンスの問題

ホットタグ

アーカイブ