可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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!!
回答1:
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); } }
回答2:
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(); } }