在Android中的onSensorChanged()中生成线程

时间:2014-03-29 01:39:53

标签: java android multithreading design-patterns android-sensors

我正在制作一个应用程序,根据方向和加速度计读数跟踪锻炼动作(锻炼动作非常缓慢)。我所拥有的是一种策略模式,在这种情况下,我有一个抽象类用于锻炼运动,而具体的锻炼动作实现了实际的东西。问题是,我正在产生线程来跟踪我的活动中onSensorChanged()方法中的不同练习。因为这将被调用很多次,我不知道我的代码是否会产生尽可能多的线程。他们收集垃圾吗?

代码:

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;
        }
    }


}

2 个答案:

答案 0 :(得分:2)

如果您只是覆盖OnSensorChanged并输出Log.d,您会看到它每秒被称为数百次(如果不是数千次)。

我建议你采用相反的方法:创建只需一个线程来处理后台收到的不同事件,然后从onSensorChanged提供这样的线程。

在线程中实现事件队列的种类。假设数千个事件将不断到来。

类似的东西:

        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;

                }

            }
        }

答案 1 :(得分:0)

我最近实施了类似的东西:

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
    }
}

希望这有帮助