Сценарий:
RecyclerView
с RecyclerView.Adapter
. notifyDataSetChanged()
-метод вызывается каждые 10 мс, потому что отображается чувствительная ко времени информация, поэтому ViewHolders (класс расширяется RecyclerView.ViewHolder
) часто обновляется. - Базовые данные поступают из собственной C-библиотеки, поэтомуметоды адаптера переопределяются для запроса данных из собственной библиотеки.
- , полученный из этого наилучшего видео интерфейс был реализован в классе адаптера для передачи onTouch-Events изАдаптер для деятельности. Поэтому класс ViewHolder реализует
View.OnTouchListener
и передает все события касания и позицию listItem (запрашивается getAdapterPosition()
) через интерфейс в Activity. - различные события onTouch (Click, LongClick, Swipe и т. Д. .) для каждого ListItem должен быть распознан в действии.
Проблема:
При касании ListItem вскоре после вызова notifyDataSetChanged()
,получены следующие значения:
1 getAdapterPosition()
: -1
2 motionEvent.getAction()
: ACTION_DOWN
, за которыми следует ACTION_CANCEL
android-документация гласит:
Обратите внимание, что если вы вызывали notifyDataSetChanged (), до следующего прохода макета возвращаемое значение этого метода будетбыть NO_POSITION.
Так что я предполагаю, что ошибка возникает каждый раз, когда происходит касание listItem, в то время как notifyDatasetChanges()
обновляет viewHolders: getAdapterPosition()
возвращает -1 в соответствии с документацией. И, возможно, из-за того, что элементы в viewHolder обновляются, onTouchEvent выдает ACTION_CANCEL
.
, что я пытался:
- Я пытался остановитьобновление RecyclerView на
ACTION_DOWN
, но из-за события ACTION_CANCEL
я не получаю никакого события ACTION_UP
и не могу перезапустить обновление данных. - Я добавил
RecyclerView.OnItemTouchListener()
кпросмотрщик в действии для получения TouchEvent в onInterceptTouchEvent()
перед его передачей в listItem и его onTouchListener и прекращением обновления там просмотра. Но, поскольку мне по-прежнему нужна информация о том, по какому элементу щелкнули, мне все еще нужны элементы на TouchListener, который по-прежнему возвращает -1 и ACTION_CANCEL
.
Вопрос:
Как лучше всего обрабатывать события onTouch в RecyclerView, который часто обновляет свои данные?
Класс активности
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;
}
}