Here's what worked out for me using SensorManager.SENSOR_DELAY_GAME for a fast update i.e.
@Override
protected void onResume() {
    super.onResume();
    sensor_manager.registerListener(this, sensor_manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME);
    sensor_manager.registerListener(this, sensor_manager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_GAME);
}
MOVING AVERAGE
(less efficient)
private float[] gravity;
private float[] geomagnetic;
private float azimuth;
private float pitch;
private float roll; 
@Override
public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
        gravity = moving_average_gravity(event.values);
    if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
        geomagnetic = moving_average_geomagnetic(event.values);
    if (gravity != null && geomagnetic != null) {
        float R[] = new float[9];
        float I[] = new float[9];
        boolean success = SensorManager.getRotationMatrix(R, I, gravity, geomagnetic);
        if (success) {
            float orientation[] = new float[3];
            SensorManager.getOrientation(R, orientation);
            azimuth = (float) Math.toDegrees(orientation[0]);
            pitch = (float) Math.toDegrees(orientation[1]);
            roll = (float) Math.toDegrees(orientation[2]);
            //if(roll>-46F && roll<46F)view.setTranslationX((roll/45F)*max_translation); //tilt from -45° to 45° to x-translate a view positioned centrally in a layout, from 0 - max_translation
            Log.i("TAG","azimuth: "+azimuth+" | pitch: "+pitch+" | roll: "+roll);
        }
    }
}
private ArrayList<Float[]> moving_gravity;
private ArrayList<Float[]> moving_geomagnetic;
private static final float moving_average_size=12;//change
private float[] moving_average_gravity(float[] gravity) {
    if(moving_gravity ==null){
        moving_gravity =new ArrayList<>();
        for (int i = 0; i < moving_average_size; i++) {
            moving_gravity.add(new Float[]{0F,0F,0F});
        }return new float[]{0F,0F,0F};
    }
    moving_gravity.remove(0);
    moving_gravity.add(new Float[]{gravity[0],gravity[1],gravity[2]});
    return moving_average(moving_gravity);
}
private float[] moving_average_geomagnetic(float[] geomagnetic) {
    if(moving_geomagnetic ==null){
        this.moving_geomagnetic =new ArrayList<>();
        for (int i = 0; i < moving_average_size; i++) {
            moving_geomagnetic.add(new Float[]{0F,0F,0F});
        }return new float[]{0F,0F,0F};
    }
    moving_geomagnetic.remove(0);
    moving_geomagnetic.add(new Float[]{geomagnetic[0],geomagnetic[1],geomagnetic[2]});
    return moving_average(moving_geomagnetic);
}
private float[] moving_average(ArrayList<Float[]> moving_values){
    float[] moving_average =new float[]{0F,0F,0F};
    for (int i = 0; i < moving_average_size; i++) {
        moving_average[0]+= moving_values.get(i)[0];
        moving_average[1]+= moving_values.get(i)[1];
        moving_average[2]+= moving_values.get(i)[2];
    }
    moving_average[0]= moving_average[0]/moving_average_size;
    moving_average[1]= moving_average[1]/moving_average_size;
    moving_average[2]= moving_average[2]/moving_average_size;
    return moving_average;
}
LOW PASS FILTER
(more efficient)
private float[] gravity;
private float[] geomagnetic;
private float azimuth;
private float pitch;
private float roll; 
@Override
public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
        gravity = LPF(event.values.clone(), gravity);
    if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
        geomagnetic = LPF(event.values.clone(), geomagnetic);
    if (gravity != null && geomagnetic != null) {
        float R[] = new float[9];
        float I[] = new float[9];
        boolean success = SensorManager.getRotationMatrix(R, I, gravity, geomagnetic);
        if (success) {
            float orientation[] = new float[3];
            SensorManager.getOrientation(R, orientation);
            azimuth = (float) Math.toDegrees(orientation[0]);
            pitch = (float) Math.toDegrees(orientation[1]);
            roll = (float) Math.toDegrees(orientation[2]);
            //if(roll>-46F && roll<46F)view.setTranslationX((roll/45F)*max_translation); //tilt from -45° to 45° to x-translate a view positioned centrally in a layout, from 0 - max_translation
            Log.i("TAG","azimuth: "+azimuth+" | pitch: "+pitch+" | roll: "+roll);
        }
    }
}
private static final float ALPHA = 1/16F;//adjust sensitivity
private float[] LPF(float[] input, float[] output) {
    if ( output == null ) return input;
    for ( int i=0; i<input.length; i++ ) {
        output[i] = output[i] + ALPHA * (input[i] - output[i]);
    }return output;
}
N.B 
moving average of 12 values instead as per here 
low pass filter of ALPHA = 0.0625 instead as per here