javaandroidandroid-handlerpostdelayed

Android Handler.postDelayed only working once


I'm writing a WearOS app that tries to tell the time by vibrating. (e.g. if the time is 4:12 it will vibrate 4 times, then 1 time, then 2 times) I doubt this has much practical use, but I'm doing it as a way to learn about android app development.

I'm trying to use handler.postDelayed for the delay between the vibrations, but this only works once. After it successfully triggers the handler once, I need to restart the activity for it to work again. Why?

My relevant code is here:

    int[] pulses = new int[4]; //length 4, one for each possible digit of the time

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //some init code goes here
        Calendar cal = Calendar.getInstance();
        int hour = cal.get(Calendar.HOUR);
        int minute = cal.get(Calendar.MINUTE);

        pulses[0] = hour/10;
        pulses[1] = hour%10;
        pulses[2] = minute/10;
        pulses[3] = minute%10;

        RelativeLayout parent_layout = findViewById(R.id.parent_layout);
        parent_layout.setOnTouchListener(new TotalGestureDetector(this){
            @Override
            public void onDoubleTap(MotionEvent e) {
                Toast.makeText(getApplicationContext(), "Double-Tap", Toast.LENGTH_SHORT).show();
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        int time = vibratePattern();
                        if (time < 0){
                            return; //no need to re-call the function
                        }
                        new Handler().postDelayed(this, time);
                        return;
                    }
                }, 500);

            }
        });

    private int vibratePattern(){
        int pulse_len = 130;
        int pause_len = 100;
        int delay_between_digits = 1250;
        for(int i = 0; i < pulses.length; i++){
            if (pulses[i] > 0){
                pulses[i]--;
                buzz(pulse_len);
                return pulse_len + pause_len;
            } else if( pulses[i] == 0){
                //don't vibrate, insert delay between digits
                pulses[i]--; //set this to -1 so we know it is acted upon
                return delay_between_digits;
            } else {
                //Do nothing, let the loop continue to the next digit in the time.
            }
        }
        //if it ever gets here, array is empty
        //return -1 to show that no more calls are needed
        return -1;
    }

Sorry if that's a lot of code.

buzz is just a function I have that vibrates the device for the amount of ms it is given

TotalGestureDetector is a class which I just yoinked from here: https://gist.github.com/nesquena/b2f023bb04190b2653c7 and renamed.

parent_layout is literally just the default layout in an empty activity -- screen is blank I want this app to be vibration-only.


Solution

  • You should revert value of pulses again when it already vibrate all. Try this

    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            int time = vibratePattern();
            if (time < 0){
                pulses[0] = hour/10;
                pulses[1] = hour%10;
                pulses[2] = minute/10;
                pulses[3] = minute%10;
                return; //no need to re-call the function
            }
            new Handler().postDelayed(this, time);
            return;
        }
    }, 500);