Bpache
Bpache

Reputation: 305

How to let sensors periodically work?

I am currently developing an app in Android which will record sensor data for a fixed length of time for several cycles. For example, I plan to record the data for 10 seconds, and then stop, let the phone rest for 10 seconds, and start record again, ... working in this pattern for 1 hour. My question is, how to let the phone automatically execute this plan? I am currently using code below ( from Android: How to collect sensor values for a fixed period of time?) , but it only works for one cycle, I have to manually start new cycles after I am sure the previous cycle has finished.

public void onResume() {
mSensorManager.registerListener(mListener, mSensorAcceleration, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(mListener, mSensorMagnetic, SensorManager.SENSOR_DELAY_GAME);
Handler h = new Handler();
h.postDelayed(new Runnable() {

    @Override
    public void run() {
    //    do stuff with sensor values
        mSensorManager.unregisterListener(mListener);               
    }
}, 10000);

...

Any help will be appreciated!!

Upvotes: 2

Views: 1739

Answers (2)

Nicholas
Nicholas

Reputation: 2215

I think there's a better and more correct way to implement this. Specifically, I think it's wrong to let the Activity implement Runnable. It leaks logic in its public interface that should be kept private (and hidden). I.e. no one is ever supposed to invoke run() outside the activity. I would suggest implementing it as follows instead:

public class PostDelayedDemo extends Activity {
  // Declaration of sensor-related fields.

  private static final int PERIOD = 10000;
  private Handler handler;
  private final Runnable processSensors =
      new Runnable() {
         @Override
         public void run() {
           mSensorManager.registerListener(mListener, mSensorAcceleration, SensorManager.SENSOR_DELAY_GAME);
           mSensorManager.registerListener(mListener, mSensorMagnetic, SensorManager.SENSOR_DELAY_GAME);

           // Do work with the sensor values.

           mSensorManager.unregisterListener(mListener);

           // The Runnable is posted to run again here:
           handler.postDelayed(this, PERIOD);
         }
      };

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    handler = new Handler();
  }

  @Override
  public void onResume() {
    super.onResume();

    handler.post(processSensors);
  }

  @Override
  public void onPause() {
    handler.removeCallbacks(processSensors);

    super.onPause();
  }
}

Upvotes: 2

CommonsWare
CommonsWare

Reputation: 1007322

Step #1: Have your activity implement Runnable, rather than use an anonymous inner class, moving your run() method to be implemented on the activity.

Step #2: In your run() method, schedule yourself (the activity) to run again after a delay using postDelayed(). This, plus your existing call to postDelayed(), will effectively set up a periodic call to run().

Step #3: Keep track of whether you are in "sensors on" or "sensors off" mode, and, in run(), either register or unregister the listeners as appropriate.

Step #4: In onPause(), call removeCallbacks() on your Handler to stop the periodic calls to run().

You will see an example of this sort of schedule-yourself-to-run-again logic in this sample project. Here is the activity:

package com.commonsware.android.post;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class PostDelayedDemo extends Activity implements Runnable {
  private static final int PERIOD=5000;
  private View root=null;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    root=findViewById(android.R.id.content);
  }

  @Override
  public void onResume() {
    super.onResume();

    run();
  }

  @Override
  public void onPause() {
    root.removeCallbacks(this);

    super.onPause();
  }

  @Override
  public void run() {
    Toast.makeText(PostDelayedDemo.this, "Who-hoo!", Toast.LENGTH_SHORT)
         .show();
    root.postDelayed(this, PERIOD);
  }
}

Upvotes: 0

Related Questions