简体   繁体   中英

I want to execute code every X seconds, but handler.postDelayed not working

Okay so I want to register the accelerometer values every X seconds to my database. He takes the first delay, but ignores the second handler.postDelayed, does anybody know what it can be? I've tried with a Timer, but that didn't work either so I'm kinda running out of options here...

Here's the code:

public class MainActivity extends AppCompatActivity implements SensorEventListener{

private Button receiveButton;
private ListView listView;

private DatabaseReference database;

private ArrayAdapter<String> adapter;
private List<String> items;

private SensorManager sensorManager;
private Sensor senAccelerometer;

private Handler handler = new Handler();
private final int delay = 5000; //in milliseconds

private Accelerometer accelerometer;

private float xValue;
private float yValue;
private float zValue;

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

    sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    senAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    sensorManager.registerListener(this, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);

    receiveButton = findViewById(R.id.receiveButton);
    listView = findViewById(R.id.listView);

    database = FirebaseDatabase.getInstance().getReference("Accelerometer");

    items = new ArrayList<>();


    items.add("X Value: " + Float.toString(xValue));
    items.add("Y Value: " + Float.toString(yValue));
    items.add("Z Value: " + Float.toString(zValue));
    updateUI();

    receiveButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            database.addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    Accelerometer accelerometer = dataSnapshot.getValue(Accelerometer.class);
                    xValue = accelerometer.xValue;
                    yValue = accelerometer.yValue;
                    zValue = accelerometer.zValue;
                    for (Iterator<String> iterator = items.iterator(); iterator.hasNext();){
                        iterator.next();
                        iterator.remove();
                    }
                    items.add("X Value: " + Float.toString(xValue));
                    items.add("Y Value: " + Float.toString(yValue));
                    items.add("Z Value: " + Float.toString(zValue));
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {

                }
            });
            updateUI();
        }
    });
}

private void updateUI(){
    if(adapter == null){
        adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, items);
        listView.setAdapter(adapter);

    } else{
        adapter.notifyDataSetChanged();
    }
}

@Override
public void onSensorChanged(final SensorEvent sensorEvent) {
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            if(sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                accelerometer = new Accelerometer(sensorEvent.values[0], sensorEvent.values[1], sensorEvent.values[2]);
            }
            database.setValue(accelerometer);
            handler.postDelayed(this, delay);
        }
    }, delay);
}

@Override
public void onAccuracyChanged(Sensor sensor, int i) {

}
}

Thanks in advance!

You should use this pattern:

Handler handler = new Handler()
Runnable yourRunnable = new Runnable()
    {

        @Override
        public void run() {
            doYourAction();
            handler.postDelayed(yourRunnable, UPDATE_INTERVAL);
        }
    };

You could try a recursive call with AsyncTask. Something like:

public void checkAccelerometer() {
    final Handler handler = new Handler();
    new AsyncTask<Void, Void, Void>() {
        @Override
        protected void onPreExecute() {
            //Update UI if you want/need to
            super.onPreExecute();
        }

        @Override
        protected Void doInBackground(Void... voids) {
            //Do your thing
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    checkAccelerometer();
                }
            }, 5000);
            super.onPostExecute(aVoid);
        }
    }.execute();
}

This will execute your code in a background thread and call itself after 5 seconds to continue repeatedly. If you want a way to stop this loop you could just throw everything into an if statement at the beginning and check for a boolean that you can control elsewhere.

I've solved it, I had to put it in the oncreate method. Because if you put it in the onSensorChanged it will be executed every time the data changes. So if you execute the data outside of the onSensorChanged, it will be executed only once which will make sure it doesn't infinitely update every .5 ms.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM