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

标签 java android multithreading design-patterns android-sensors

我正在制作一个应用程序,它根据方向和加速度计读数跟踪锻炼 Action (锻炼 Action 非常慢)。我所拥有的是一种策略模式,在这种情况下,我有一个锻炼 Action 的抽象类,而具体的锻炼 Action 实现了实际的东西。问题是,我正在生成线程来跟踪 Activity 中 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;
        }
    }


}

最佳答案

如果您只是覆盖 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;

                }

            }
        }

关于java - 在 Android 的 onSensorChanged() 中生成线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22725926/

相关文章:

java - 消息对话框错误

java - 如何将工具提示添加到 JavaFX 8 中的 TableView 标题单元格

c# - 与 C# 服务器的 Android TCP 通信 -> socket.Close

android - 我应该用什么来制作角色动画?

windows - 监听多个套接字 : select vs. 多线程

python - 在主线程中调用 queue.join() 对非主线程有何作用?

java - GraphStream中的自动布局,节点位置

android - 在屏幕上的特定坐标上设置 TextView

c# - C#中自制线程池的多线程死锁

java - JPA 在循环之前或之后合并不正确