0

Hello :) I am trying to detect when the user press a long click on the button and when he releases the long click so I am using this answer: https://stackoverflow.com/a/10746549/3953319 I don't know why but the LongClickListener is called twice to me, here is my code:

button1.setOnLongClickListener(new View.OnLongClickListener() {
    public boolean onLongClick(View pView) {
        TimeCounter = 0;
        final Random rand = new Random();
        time = rand.nextInt(7) + 1;
        SecTime = time * 1000;
        CountDownTimer2 = new CountDownTimer(SecTime, 1000) {
            public void onTick(long millisUntilFinished) {
            }

            public void onFinish() {
                mPlayer = MediaPlayer.create(MainActivity.this,
                            R.raw.windows_8_notify);
                mPlayer.start();
                t = new Thread() {
                    @Override
                    public void run() {
                        try {
                            while (!isInterrupted()) {
                                Thread.sleep(1);
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        TimeCounter++;
                                        textview.setText("Your reaction time:"
                                                    + TimeCounter + "MS");
                                    }
                                });
                            }
                        } catch (InterruptedException e) {
                        }
                    }
                };
                t.start();
            }
        }.start();
        isSpeakButtonLongPressed = true;
        return true;
    }
});

button1.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View pView, MotionEvent pEvent) {
        pView.onTouchEvent(pEvent);
        if (pEvent.getAction() == MotionEvent.ACTION_UP) {
            if (isSpeakButtonLongPressed) {
                if (mPlayer == null) {
                    textview.setText("You have released the button before the sound");
                    CountDownTimer2.cancel();
                } else {
                    t.interrupt();
                    t = null;
                    OldScore = sharedpreferences.getInt("HighScore", 0);
                    if (TimeCounter < OldScore) {
                        Editor editor = sharedpreferences.edit();
                        editor.putInt("HighScore", TimeCounter);
                        editor.commit();
                        textview1.setText("Your new High Score:"
                                    + TimeCounter + "MS");
                    }
                    textview.setText("Your reaction time:"
                                + TimeCounter + "MS");
                    mPlayer.pause();
                    mPlayer.reset();
                    mPlayer = null;
                }
                isSpeakButtonLongPressed = false;
            }
        }
        return false;
    }
});

I ran the application and when I long click the button I hear the "windows_8_notify" twice, why is that? is there any better way to do it?

Community
  • 1
  • 1
David
  • 39
  • 4
  • Y do You have two .start() in your code ?? I think thats the reason its running twice . please check and let me know – sanath_p Aug 18 '14 at 20:24
  • @user3716835 have you looked at the code? one for the CountDownTimer and one for the Thread. – David Aug 18 '14 at 21:20
  • You mean if you hold it down the OnLongClick functionality happens twice? Where are you setting the listener? – zgc7009 Aug 18 '14 at 21:39
  • @zgc7009 yes it happens twice, I hear the voice twice, the thread runs twice (not at the same time) its like - sound, 2 seconds interval, sound again. – David Aug 18 '14 at 22:04

1 Answers1

3

I believe it is because in your onTouchListener's onTouch method, you call pView.onTouch(...), and then at the end, return false. The return false line indicates that your onTouchListener has not handled the onTouch event, so then it resorts to calling it's default onTouch function, which is identical to your pView.onTouch(...) call. However, the default function happens to also call your onLongClickListener's onLongClick method. Thus, it calls pView.onTouch(...) twice, each time calling your onLongClickListener's onLongClick method.

SO. I believe you can avoid this if you return true in the onTouch method in appropriate cases. In my mind, it would look something like this:

Abbreviated

button1.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View pView, MotionEvent pEvent) {
        boolean longClickOccurred = pView.onTouchEvent(pEvent);
        ...
        if (pEvent.getAction()...) {
            if (isSpeakButtonLongPressed) {
                ...
                longClickOccurred = true;
            }
        }
        return longClickOccurred;
    }
});

Full Rewrite

button1.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View pView, MotionEvent pEvent) {
        boolean longClickOccurred = pView.onTouchEvent(pEvent);
        if (pEvent.getAction() == MotionEvent.ACTION_UP) {
            if (isSpeakButtonLongPressed) {
                if (mPlayer == null) {
                    textview.setText("You have released the button before the sound");
                    CountDownTimer2.cancel();
                } else {
                    t.interrupt();
                    t = null;
                    OldScore = sharedpreferences.getInt("HighScore", 0);
                    if (TimeCounter < OldScore) {
                        Editor editor = sharedpreferences.edit();
                        editor.putInt("HighScore", TimeCounter);
                        editor.commit();
                        textview1.setText("Your new High Score:"
                                    + TimeCounter + "MS");
                    }
                    textview.setText("Your reaction time:"
                                + TimeCounter + "MS");
                    mPlayer.pause();
                    mPlayer.reset();
                    mPlayer = null;
                }
                isSpeakButtonLongPressed = false;
                longClickOccurred = true;
            }
        }
        return longClickOccurred;
    }
});

This will(should) stop your button from recalling the pView.onTouchEvent(pEvent), without interfering with other click functions.

(In fact, I don't think you need the boolean variable isSpeakButtonLongPressed, because its value is basically identical to longClickOccurred when you assert that pEvent.getAction() == MotionEvent.ACTION_UP. UNLESS 1) you use isSpeakButtonLongPressed outside of the onTouch function, or 2) you have some other onClickListener set or something like that, which will cause pView.onTouchEvent(pEvent) to return true when a long click has not occurred.)

Anyway, I hope the works/helps/was-not-a-convoluted-explanation. Good luck!

CrepeGoat
  • 2,315
  • 20
  • 24
  • Wow , thx for the explanation, just one thing - I want to try your code but - the qEvent.getAction() is not working (it says Type mismatch: cannot convert from int to boolean ) – David Aug 18 '14 at 22:35
  • Oh sorry about that. I didn't want to retype everything you had, so I put in `...`'s where you code does its own thing. You only need to copy/paste in three lines; each line with the `longClickOccurred` variable appears. – CrepeGoat Aug 18 '14 at 22:38
  • Ok so I have done it, you can take a look here: http://pastebin.com/QDtBQXeR unfurtunately, still the same :( you can test it if you want to :) here is the xml file: http://pastebin.com/8GaHMNwq – David Aug 18 '14 at 22:46
  • remove the first pView.onTouchEvent(...) call. I just wrote a full rewrite, if you want to compare to that (or copy/paste it). It "should" work :\ – CrepeGoat Aug 18 '14 at 22:48