Search code examples
javaandroidmultithreadinghandlerrunnable

Android - How do I continuously run a thread, one after another


So i have the following code below which basically takes the initial battery level, waits a certain amount of time, and takes the ending battery level inside of calculateHelper which then finds the difference and prints it.

    // Get the initial battery level
    IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
    Intent batteryStatus = this.registerReceiver(null, ifilter);
    int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
    System.out.println("Initial battery level is: " + level);
    int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
    final float batteryPctTemp0 = level / (float) scale;
    final float batteryPct0 = batteryPctTemp0 * 100;

    int waitTime = 60000 * interval; // 1 minute is 60000 miliseconds
    System.out.println("Wait time is " + waitTime);
    Runnable r = new Runnable() {
        @Override
        public void run(){
            calculateHelper(batteryPct0,startButton);
        }
    };
    Handler h = new Handler();
    h.postDelayed(r, waitTime);

I want to infinitely loop (until program exit) this entire process so that after each successive thread finishes, the next one begins, taking a new initial battery level each time and passing it into the calculateHelper function for calculation of a new difference. I do NOT want threads to stack up. I want one thread at a time. In other words, the loop needs to wait for the thread to finish before starting another one.

I can't for the life of me figure out how to do this! If i put the entire thing into a while, it will just repeatedly open up threads crashing the phone.

If anyone can point me in the right direction on the matter I would be greatly appreciative. Also, if any more code is needed to solve the problem, simply comment and I will reply as soon as I have added it to my question.

Thank you.


Thanks to Whooper, I've added in this method of regulating execution order in a loop. However, for some reason my postExecute() method is never being executed and nothing is happening.

    private class BatteryLifeTask extends AsyncTask<Void, Void, Void> {

    // Member variables
    Context appContext;
    float batteryPct0;
    Button startButton;

    public BatteryLifeTask(Context context, Button start) {
        super();
        appContext = context;
        startButton = start;
    }

    protected Void doInBackground(Void... params) {
        // Get the initial battery level
        IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent batteryStatus = appContext.registerReceiver(null, ifilter);
        int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
        System.out.println("Initial battery level is: " + level);
        int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
        final float batteryPctTemp0 = level / (float) scale;
        batteryPct0 = batteryPctTemp0 * 100;
        return null;
    }

    protected void onPostExecute() {
        int waitTime = 60000 * interval; // 1 minute is 60000 miliseconds
        System.out.println("In postExecute. waitTime is" + waitTime);
        Runnable r = new Runnable() {
            @Override
            public void run(){
                System.out.println("An interval has passed.");
                calculateHelper(batteryPct0,startButton);
                new BatteryLifeTask(appContext,startButton).execute();
            }
        };
        Handler h = new Handler();
        h.postDelayed(r, waitTime);
    }
}

and my call to the execute method:

    // Start the task loop
    new BatteryLifeTask(getApplicationContext(), startButton).execute();

I've found the problem:

I forgot to set the @Override annotation, and this answer : https://stackoverflow.com/a/11127996/2247192 states:

"If your params of onPostExecute(Param param) don't match the one you defined with extends AsyncTask<...,...,Param> and you didn't use the @Override annotation, it will never be executed and you don't get a warning from Eclipse."

So I've corrected my postExecute method to:

        @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        int waitTime = 60000 * interval; // 1 minute is 60000 miliseconds
        System.out.println("In postExecute. waitTime is " + waitTime);
        Runnable r = new Runnable() {
            @Override
            public void run(){
                System.out.println("An interval has passed.");
                calculateHelper(batteryPct0,startButton);
                new BatteryLifeTask(appContext,startButton).execute();
            }
        };
        Handler h = new Handler();
        h.postDelayed(r, waitTime);
    }

All issues are now resolved.


Solution

  • Try using an AsyncTask. http://developer.android.com/reference/android/os/AsyncTask.html

    This way you can execute the task again when onPostExecute() is called.

    Something like this:

    private class BatteryLifeTask extends AsyncTask<Void, Void, Void> {
             protected void doInBackground(Void... params) {
                 // Get the initial battery level
                IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
                Intent batteryStatus = this.registerReceiver(null, ifilter);
                int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
                System.out.println("Initial battery level is: " + level);
                int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
                final float batteryPctTemp0 = level / (float) scale;
                final float batteryPct0 = batteryPctTemp0 * 100;
             }
    
             protected void onPostExecute() {
                int waitTime = 60000 * interval; // 1 minute is 60000 miliseconds
                Runnable r = new Runnable() {
                    @Override
                    public void run(){
                       new BatteryLifeTask.execute();
                    }
                };
                Handler h = new Handler();
                h.postDelayed(r, waitTime);
             }
     }
    

    Be aware that this code is untested. But I hope it gives you an idea :-)