处理RecyclerView的触摸事件,并经常更改数据

问题描述 投票:0回答:1

场景:

  • [RecyclerViewRecyclerView.Adapter。因为会显示时间敏感信息,所以每10ms就会调用一次notifyDataSetChanged()方法,因此ViewHolders(类正在扩展RecyclerView.ViewHolder)会经常更新。
  • 基础数据来自本地C库,因此重写了Adapter方法以从本地库查询数据。
  • 源自this best practice video,在Adapter-class中实现了一个接口,以将onTouch-Events从适配器传递到Activity。因此,ViewHolder类实现View.OnTouchListener并将所有触摸事件和listItem-position(由getAdapterPosition()查询)通过接口传递给Activity。
  • 应该在活动中识别每个ListItem的各种onTouch事件(单击,LongClick,Swipe等)。

问题:

当调用notifyDataSetChanged()之后不久触摸ListItem时,接收到的值为:

[1 getAdapterPosition():-1

[2 motionEvent.getAction()ACTION_DOWN直接后跟ACTION_CANCEL

android-documentation说:

请注意,如果您调用了notifyDataSetChanged(),则直到下一个布局传递,此方法的返回值为NO_POSITION。

所以我猜想,在notifyDatasetChanges()刷新viewHolders时,每次触摸listItem都会发生错误:getAdapterPosition()根据文档返回-1。并且,可能是因为刷新了viewHolder中的元素,所以onTouchEvent抛出ACTION_CANCEL

我尝试过的事情:

  1. 我试图停止ACTION_DOWN上RecyclerView的刷新,但是由于ACTION_CANCEL事件,我没有收到任何ACTION_UP事件,并且无法重新开始刷新数据。
  2. 我在活动的recyclerView中添加了一个RecyclerView.OnItemTouchListener(),以便在将其传递给listItem及其onTouchListener并在其中停止刷新recyclerview之前,在onInterceptTouchEvent()中接收TouchEvent。但是,因为我仍然需要有关单击了哪个项目的信息,所以我仍然需要onTouchListener项,该项仍返回-1和ACTION_CANCEL

问题:

在经常更新其数据的RecyclerView中处理onTouch事件的最佳做法是什么?

活动类别

public class Activity extends AppCompatActivity implements DataStoreDataAdapter.OnListItemTouchListener {



    Handler dataUpdateHandler = new Handler();

    Runnable timerRunnable = new Runnable() {
        @Override
        public void run() {
            dataStoreDataAdapter.notifyDataSetChanged();

            dataUpdateHandler.postDelayed(this, 10);
        }
    };


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

        dataStoreDataAdapter = new DataStoreDataAdapter(getApplicationContext(),this);

        recyclerView = findViewById(R.id.list_view);
        layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(dataStoreDataAdapter);

        recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
            @Override
            public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
                Log.i(TAG, "onInterceptTouchEvent: " + " touched by type " + e);
                int action = e.getAction();
                if (action == MotionEvent.ACTION_DOWN) {
                    dataUpdateHandler.removeCallbacks(timerRunnable);
                } else if (action == MotionEvent.ACTION_UP) {
                    dataUpdateHandler.post(timerRunnable);
                }
                return false;
            }

            @Override
            public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
                Log.i(TAG, "onTouchEvent: " + " touched by type " + e);
            }


            @Override
            public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

            }
        });


        //set update Handler
        dataUpdateHandler.post(timerRunnable);
    }

    @Override
    public void onListItemTouch(int position, MotionEvent motionEvent) {
        Log.i(TAG, "onListItemTouch: ListItem position " + position + " motionEvent: " + motionEvent);
    }
}

适配器类

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

      private OnListItemTouchListener onListItemTouchListener;

    static class ViewHolder extends RecyclerView.ViewHolder implements View.OnTouchListener{
        View view;
        TextView Name;
       // ...  

        ViewHolder(@NonNull View itemView, OnListItemTouchListener onListItemTouchListener) {
            super(itemView);
            this.Name = itemView.findViewById(R.id.NameListItem);
            // ...

            this.onListItemTouchListener = onListItemTouchListener;
            itemView.setOnTouchListener(this);
        }

        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            onListItemTouchListener.onListItemTouch(getAdapterPosition(), motionEvent);
            return true;
        }
    }

    public interface OnListItemTouchListener{
        void onListItemTouch(int position, MotionEvent motionEvent);
    }

    public DataStoreDataAdapter(Context context, OnListItemTouchListener onListItemTouchListener) {
        super();
        this.onListItemTouchListener = onListItemTouchListener;
    }

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

        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view = inflater.inflate(R.layout.list_item,parent,false);

        return new ViewHolder(view, onListItemTouchListener);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        // get the stored data for this position
        // ...get stuff from native library

        // put data into view elements...

    }

    @Override
    public int getItemCount() {
        return // ... itemCount from native library;
    }

}

场景:带有RecyclerView.Adapter的RecyclerView。因为会显示时间敏感信息,所以每10毫秒调用一次notifyDataSetChanged()方法,因此ViewHolders(类正在扩展...

android android-recyclerview onclicklistener ontouchlistener custom-adapter
1个回答
0
投票
© www.soinside.com 2019 - 2024. All rights reserved.