1

I have some code that stores MotionEvents that occur to a particular View (call this the producer), and some different code in another thread that reads that data for display purposes (call this the consumer). I am in essence re-creating down-one-color-up-a-different-color button functionality where using standard Android buttons is not feasible. The MotionEvents are stored in a single ArrayList. The accesses to this are wrapped in a single permit semaphore to prevent the provider and consumer from I/Oing to the ArrayList at the same time and reading transitory data. All well and good.

The problem is when I'm tapping on this View at high speed. On the producer side, I add stuff to the ArrayList in response to a MotionEvent.ACTION_DOWN, and I remove it from the list in response to an MotionEvent.ACTION_UP (ACTION_MOVEs I ignore). If im flooding the phone with taps, when it comes time to add/remove, the semaphore not available, either because my consumer is reading the ArrayList, or because I'm not done handling a previous tap.

So what is best practice for this problem? If I miss a MOTION_DOWN, it seems like I can safely ignore it, but if I miss a MOTION_UP, won't my consumer be stuck displaying the button like the finger was still pressed down? I am seeing an occasional display bug (nothing to do with rapid taps) that could be caused by a missed MOTION_UP.

user1733212
  • 111
  • 8
  • What does 'the semaphore can is closed' mean? – user207421 Jun 16 '17 at 06:08
  • dumb typo, sorry. I mean, the semaphore is not available – user1733212 Jun 16 '17 at 08:43
  • so, I don't fully understood your problem, some code would be much better to help but let's try. Android supports fully java 7 right? So why don't you rely on java high level concurrent objects to control this https://docs.oracle.com/javase/tutorial/essential/concurrency/highlevel.html , it will, possibly, be more reliable. Another option it's possibly making your array list thread safe: `Collections.synchronizedList(new ArrayList<>())` – groo Jun 16 '17 at 08:51

1 Answers1

0

It is hard to tell what's exactly wrong with your scheme right now, but you do probably have some synchronization issue.

For producer-consumer patter, BlockingQueue is your best bet. In your case, just use simple unbounded implementation.

Execute mBlockingQueue.add(MotionEvent) in response to a button click, and consume events in an infinite loop on the background thread:

while(true) {
    processEvent(mBlockingQueue.take());
}

As a side note: I don't think that you really need background thread in order to change button's color on click. There are other simpler ways.

Vasiliy
  • 16,221
  • 11
  • 71
  • 127
  • @Vasilly I did some research on BlockingQueue after your suggestion. I wound up using a CopyOnWriteArrayList, so thanks for pointing me in that general direction. – user1733212 Jun 16 '17 at 20:33