简体   繁体   中英

Why does the TYPE_ROTATION_VECTOR sensor return a null value?

I am new to Android Studio and do not understand why the onSensorChanged() method does not give errors and warnings, but returns zero. I want to "roll the ball on the screen of the device." The graphic component works well. I see a ball with a constant speed of movement, and I want to adjust the speed by multiplying it by the angle of the screen and therefore my speed becomes - zero. Please help me fix it.

I'm testing the application on a real device Xiaomi MI9 SE.

//MAIN ACTIVITY
package com.example.app_2;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class Gravity extends AppCompatActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_gravity);
        setContentView(new MovementView(this));
    }
}
//PHYSICS

package com.example.app_2;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MovementView extends SurfaceView implements SurfaceHolder.Callback {
    public float xPos;
    public float yPos;
    public float xVel;
    public float yVel;
    public float width;
    public float height;
    private float circleRadius;
    private Paint circlePaint;
    UpdateThread updateThread;
   public MovementView(Context context) {
        super(context);
        getHolder().addCallback(this);
        circleRadius = 30;
        circlePaint = new Paint();
        circlePaint.setColor(Color.RED);
        xVel = 2 ; // скорость движения
        yVel = 2 ; //  шарика
    }

    @Override
    public void onDraw(Canvas c) {
        c.drawColor(Color.WHITE);
        c.drawCircle(xPos, yPos, circleRadius, circlePaint);
    }
    public void updatePhysics() {
        float xz, zy;
        xz = Acceleration.Accel(1);
        zy = Acceleration.Accel(-1);
        xPos += xVel - xz;
        yPos += yVel - zy;
        if (yPos - circleRadius < 0 || yPos + circleRadius > height) {
            //В случае ударов о верх или низ холста
            if (yPos - circleRadius < 0) {
                //Удар о верхнюю грань
                yPos = circleRadius;
            }else{
                //Удар о нижнюю грань
                yPos = height - circleRadius;
            }
            //Меняем направление шарика
            yVel *= -1;
        }
        if (xPos - circleRadius < 0 || xPos + circleRadius > width) {
            //В случае столкновений с правой или левой стенками
            if (xPos - circleRadius < 0) {
                //В случае столкновений с левой стенкой
                xPos = circleRadius;
            } else {
                //В случае столкновений с правой стенкой
                xPos = width - circleRadius;
            }
            //Меняем x направление на обратное
            xVel *= -1;
        }
    }
    public void surfaceCreated(SurfaceHolder holder) {

        Rect surfaceFrame = holder.getSurfaceFrame();
        width = surfaceFrame.width();
        height = surfaceFrame.height();

        xPos = width / 2;
        yPos = height / 2;

        updateThread = new UpdateThread(this);
        updateThread.setRunning(true);
        updateThread.start();
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    public void surfaceDestroyed(SurfaceHolder holder) {

        boolean retry = true;

        updateThread.setRunning(false);
        while (retry) {
            try {
                updateThread.join();
                retry = false;
            } catch (InterruptedException e) {
            }
        }
    }
}
//THREAD
package com.example.app_2;
import android.graphics.Canvas;
import android.view.SurfaceHolder;


public class UpdateThread extends Thread{
    private long time;
    private final int fps = 5;
    private boolean toRun = false;
    private MovementView movementView;
    private SurfaceHolder surfaceHolder;
    UpdateThread(MovementView rMovementView) {
        movementView = rMovementView;
        surfaceHolder = movementView.getHolder();
    }

    void setRunning(boolean run) {
        toRun = run;
    }


    @Override
    public void run() {
        Canvas c;
        while (toRun) {

            long cTime = System.currentTimeMillis();

            //if ((cTime - time) <= (100000 / fps)) {

                c = null;
                try {
                    c = surfaceHolder.lockCanvas(null);
                    movementView.updatePhysics();
                    movementView.onDraw(c);
                } finally {

                    if (c != null) {
                        surfaceHolder.unlockCanvasAndPost(c);
                    }
                }
            //}
            time = cTime;
        }
    }
}
//ACCELERATION
package com.example.app_2;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.IBinder;

import androidx.core.content.ContextCompat;

import static android.content.Context.SENSOR_SERVICE;
import static android.hardware.Sensor.TYPE_ROTATION_VECTOR;
import static androidx.core.content.ContextCompat.getSystemService;

public class Acceleration extends Service implements SensorEventListener {
    public SensorManager sensorManager;
    public static float xy_angle, xz_angle, zy_angle;

    public Acceleration(Context pContext) {
        sensorManager = (SensorManager) pContext.getSystemService(SENSOR_SERVICE);
        assert sensorManager != null;
        sensorManager.registerListener(this,
                sensorManager.getDefaultSensor(TYPE_ROTATION_VECTOR),
                SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        assert sensorManager != null;

        xy_angle = sensorEvent.values[0];
        xz_angle = sensorEvent.values[1];
        zy_angle = sensorEvent.values[2];
    }

    public static float Accel(int a){
        float angle;
        if (a > 0){
           angle = xz_angle;
        } else {
            angle = zy_angle;
        }
        return angle;
    }

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


    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

I expect Acceleration.Accel(1) to return the value of the TYPE_ROTATION_VECTOR sensor at the time of the data request, but I always get zero.

What you need to do is pass your application's Context to your Acceleration class so that your SensorManager can get initialized. The way you had the SensorManager getting initialized inside the onSensorChanged() method meant that the SensorManager was never even getting setup because onSensorChanged() was never even getting called.

So in the revised Acceleration class below, I added a constructor which you will then need to call with your application's Context passed in as an argument:

public class Acceleration extends Service implements SensorEventListener {
    public SensorManager sensorManager;
    public static float xy_angle, xz_angle, zy_angle;

    public Acceleration(Context pContext) {
        sensorManager = (SensorManager) pContext.getSystemService(SENSOR_SERVICE);
        assert sensorManager != null;
        sensorManager.registerListener(this,
                sensorManager.getDefaultSensor(TYPE_ROTATION_VECTOR),
                SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        xy_angle = sensorEvent.values[0];
        xz_angle = sensorEvent.values[1];
        zy_angle = sensorEvent.values[2];
    }

    public static float accel(int a) {
        float angle;
        if (a > 0) {
            angle = xz_angle;
        } else {
            angle = zy_angle;
        }
        return angle;
    }
}

In your Gravity class, just initialize an Acceleration object:

public class Gravity extends AppCompatActivity {

    Acceleration acceleration;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MovementView(this));

        acceleration = new Acceleration(this);
    }
}

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