문제

I'm making an app that tracks exercise movements based on orientation and accelerometer readings(the exercise movements are very slow). What I have is a strategy pattern kind of a situation where I have an abstract class for exercise movement and the concrete exercise movements implement the actual thing. Problem is, I am spawning threads to track different exercises in the onSensorChanged() method in my activity. since this is going to be called a lot of times, I don't know if my code will spawn as many threads. Do they get garbage collected?

Code:

public class WorkoutBuddy extends Activity implements SensorEventListener {

    TextView t1, t2, t3, t4, t5, t6, t7; 
    SensorManager sensorManager;;
    private Sensor sensorAccelerometer;
    private Sensor sensorMagneticField;
    private float[] valuesAccelerometer;
    private float[] valuesMagneticField;
    private float[] valuesOrientation;

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

        sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
        sensorAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        sensorMagneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

        valuesAccelerometer = new float[3];
        valuesMagneticField = new float[3];
        valuesOrientation = new float[3];

        matrixR = new float[9];
        matrixI = new float[9];
        matrixValues = new float[3];

        //mediaPlayer = MediaPlayer.create(this, R.raw.first_position_confirmation);
    }

    @Override
    protected void onPause() {
        sensorManager.unregisterListener(this,sensorAccelerometer);
        sensorManager.unregisterListener(this,sensorMagneticField);
        super.onPause();
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // TODO Auto-generated method stub
    }

    float[] orientation;
    private float[] matrixR;
    private float[] matrixI;
    private float[] matrixValues;

    @Override
    public void onSensorChanged(SensorEvent event) {


        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            valuesAccelerometer = lowPass(event.values.clone(), valuesAccelerometer);
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            valuesMagneticField = lowPass(event.values.clone(), valuesMagneticField);
        }
        if (valuesAccelerometer != null && valuesMagneticField != null) {
            SensorManager.getRotationMatrix(matrixR, matrixI, valuesAccelerometer, valuesMagneticField);

            if(true){
                SensorManager.getOrientation(matrixR, matrixValues);

                double azimuth = Math.toDegrees(matrixValues[0]);
                double pitch = Math.toDegrees(matrixValues[1]);
                double roll = Math.toDegrees(matrixValues[2]);

                valuesOrientation[0]=(float) pitch;
                valuesOrientation[1]=(float) roll;
                valuesOrientation[0]=(float) azimuth;


                Thread forExc1 = new Thread(new LeftShoulder(valuesAccelerometer, valuesOrientation, this));
                Thread forExc2 = new Thread(new RightShoulder(valuesAccelerometer, valuesOrientation, this));

                forExc1.run();
                forExc2.run();

            }

        }
    }

    @Override
    protected void onResume() {
        sensorManager.registerListener(this,sensorAccelerometer,SensorManager.SENSOR_DELAY_NORMAL);
        sensorManager.registerListener(this,sensorMagneticField,SensorManager.SENSOR_DELAY_NORMAL);
        super.onResume();
    }

    //Low pass filter used to smooth the sensor readings
    protected float[] lowPass( float[] input, float[] output ) {
        float ALPHA = 0.25f;
        if ( output == null ) return input;     
        for ( int i=0; i<input.length; i++ ) {
            output[i] = output[i] + ALPHA * (input[i] - output[i]);
        }
        return output;
    }


}



package com.example.msapp2;


public abstract class ExerciseMovement implements Runnable{
    protected float[] acc, ori;
    protected boolean played = false;

}



package com.example.msapp2;

import android.content.Context;
import android.media.MediaPlayer;

public class LeftShoulder extends ExerciseMovement {

    MediaPlayer mediaPlayer;
    public LeftShoulder(float[] accelerometer, float[] orientation, Context context){
        mediaPlayer = MediaPlayer.create(context, R.raw.first_position_confirmation);
        acc = accelerometer;
        //this.ori = orientation;
    }

    public void run(){
        if(acc[0]> -10 && acc[0] < -8.5 && !played){
            mediaPlayer.start();
            played = true;
        }
    }


}
도움이 되었습니까?

해결책

If you just override OnSensorChanged and output a Log.d , you'll see it's called hundreds, if not thousands, of times per second.

I suggest you the opposite approach: Create just one thread to process in background the different received events, then feed such thread from onSensorChanged.

Implement kind of an event queue in the thread. Assume thousands of events will arrive, constantly.

SOmething like:

        private class ShoulderMovementProcessorThread extends Thread {

               .....

               // this will be called from the UI thread, just add event to the (synchronized) queue.

               public void publish (int[] valuesAccelerometer, int[] valuesWhatever) {

                     add_event_to_queue();

               }

               // this is the typical event loop where you read one from the queue, process it, then wait for the next
               public void run() {
                   -> get event
                   -> process event
                   -> wait for next event
               }

        }

        ShoulderMovementProcessorThread mShoulderProcessor=new ShoulderMovementProcessorThread(...);

        @Override
        public void onSensorChanged(SensorEvent event) {
              decodeEvent (event); // fills up azimuth, roll, etc.
              mShoulderProcessor.publish(valuesAccelerometer, valuesWhatever);           

        }


        // decode an event
        private void decodeEvent (SensorEvent event) {

            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                valuesAccelerometer = lowPass(event.values.clone(), valuesAccelerometer);
            } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                valuesMagneticField = lowPass(event.values.clone(), valuesMagneticField);
            }
            if (valuesAccelerometer != null && valuesMagneticField != null) {
                SensorManager.getRotationMatrix(matrixR, matrixI, valuesAccelerometer, valuesMagneticField);

                if(true){
                    SensorManager.getOrientation(matrixR, matrixValues);

                    double azimuth = Math.toDegrees(matrixValues[0]);
                    double pitch = Math.toDegrees(matrixValues[1]);
                    double roll = Math.toDegrees(matrixValues[2]);

                    valuesOrientation[0]=(float) pitch;
                    valuesOrientation[1]=(float) roll;
                    valuesOrientation[0]=(float) azimuth;

                }

            }
        }

다른 팁

I implemented something similar recently:

public class DBWorkerThread implements Runnable
{
    private  SensorEnum sensorType;
    private LinkedBlockingQueue<float[]> sensorData;
    private DBService dbService;

    public DBWorkerThread(SensorEnum type, DBService dbService)
    {
        this.sensorType = type;
        this.dbService = dbService;
        this.sensorData = new LinkedBlockingQueue<float[]>();
    }

    /**
     * Add data to queue
     * @param values
     */
    public void addDataToProcess(float[] values)
    {
        if (sensorData.size() < sensorData.remainingCapacity())
        {
            try
            {
                this.sensorData.put(values);
            }
            catch (Exception ex)
            {
                LogService.log("Error adding queue: " + ex.getMessage());
            }
            LogService.log("Added to queue. Size: " + sensorData.size());
        }
    }

    /**
     * Processes queue of data
     */
    @Override
    public void run()
    {
        // Moves the current Thread into the background
        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);

        while (sensorData.size() > 0)
        {
            try
            {
                float[] values = sensorData.take();
                storeData(values);
            }
            catch (Exception ex)
            {
                LogService.log("Error in queue: " + ex.getMessage());
            }
        }
    }

    /**
     * Store data to database
     * @param values
     */
    private void storeData(float[] values)
    {
        // store data
    }
}

Hopes this helps

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top