java - 重新打开应用程序并重新启动计数器(摇晃手机)时,停止计步器/加速度计重置为 0?
问题描述
我前段时间问过这个问题(防止步骤计数器在应用关闭时返回 0?)但是我现在已经将每日步骤存储到了 Firebase,我面临着一个不同的问题。我遇到的问题是,当应用程序重新打开时,应用程序会显示数据库中的步数,但是一旦我摇动手机,计数器仍会重置为 0 .. 我不确定它是否与step
方法有关,或updateAccel
方法,我试过移动一些东西,但不幸的是没有任何运气..
这是我的计步器活动:
public class ActivityFragment extends Fragment implements SensorEventListener, StepListener {
private TextView textView;
private TextView stepsTotalMax;
private SimpleStepDetector simpleStepDetector;
private SensorManager sensorManager;
private Sensor accel;
private static final String TEXT_NUM_STEPS = "";
private int numSteps;
private ProgressBar progressBar;
String intentActivity;
String uid;
Dog dog;
private FirebaseAuth firebaseAuth;
private FirebaseUser currentUser;
DatabaseReference databaseReference;
DateTimeFormatter dtf;
LocalDateTime now;
String dateString;
@RequiresApi(api = Build.VERSION_CODES.O)
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_activity, container, false);
intentActivity = getActivity().getIntent().getStringExtra("name");
// ------------- firebase --------------
firebaseAuth = FirebaseAuth.getInstance();
currentUser = firebaseAuth.getCurrentUser();
uid = currentUser.getUid();
databaseReference = FirebaseDatabase.getInstance().getReference("user").child(uid).child("dogs").child(intentActivity);
// -------------------------------------
dtf = DateTimeFormatter.ofPattern("ddMMyyyy");
now = LocalDateTime.now();
dateString = dtf.format(now);
// Get an instance of the SensorManager
sensorManager = (SensorManager) getActivity().getSystemService(SENSOR_SERVICE);
accel = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
textView = view.findViewById(R.id.textViewStepCounter);
progressBar = view.findViewById(R.id.stepsProgress);
stepsTotalMax = view.findViewById(R.id.stepsTotalMax);
textView.setTextSize(30);
getDogData();
dog = new Dog();
simpleStepDetector = new SimpleStepDetector();
simpleStepDetector.registerListener(this);
return view;
}
@Override
public void onResume() {
super.onResume();
textView.setText(TEXT_NUM_STEPS + numSteps);
sensorManager.registerListener(this, accel, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
public void onPause() {
super.onPause();
sensorManager.unregisterListener(this);
}
@Override
public void onStop() {
super.onStop();
}
@Override
public void onSensorChanged(SensorEvent event) {
databaseReference.addValueEventListener(new ValueEventListener() {
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String activity = dataSnapshot.child("activity goal").getValue(String.class);
String steps = dataSnapshot.child("steps").child(dateString).getValue(String.class);
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
simpleStepDetector.updateAccel(
event.timestamp, event.values[0], event.values[1], event.values[2]);
if (steps == null) {
textView.setText("0");
} else {
textView.setText(steps);
}
progressBar.setMax(Integer.parseInt(activity)); // change this so it is dynamically pulled when user sets max value
ObjectAnimator.ofInt(progressBar, "progress", numSteps)
.setDuration(300)
.start();
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w("TAG", "onCancelled", databaseError.toException());
}
});
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
public void step(long timeNs) {
databaseReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String steps = dataSnapshot.child("steps").child(dateString).getValue(String.class);
if (steps == null) {
textView.setText("0");
} else {
textView.setText(steps);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w("TAG", "onCancelled", databaseError.toException());
}
});
numSteps++;
textView.setText(TEXT_NUM_STEPS + numSteps);
databaseReference.child("steps").child(dateString).setValue(String.valueOf(numSteps));
}
private void getDogData() {
databaseReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String name = dataSnapshot.child("name").getValue(String.class);
String activity = dataSnapshot.child("activity goal").getValue(String.class);
String steps = dataSnapshot.child("steps").child(dateString).getValue(String.class);
if (activity.isEmpty()) {
stepsTotalMax.setText("60" + " mins");
} else {
stepsTotalMax.setText(activity + " mins");
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w("TAG", "onCancelled", databaseError.toException());
}
});
}
}
以及来自 Google 的 SimpleStepDetector
public class SimpleStepDetector {
private static final int ACCEL_RING_SIZE = 50;
private static final int VEL_RING_SIZE = 10;
private static final float STEP_THRESHOLD = 4f;
private static final int STEP_DELAY_NS = 250000000;
private int accelRingCounter = 0;
private float[] accelRingX = new float[ACCEL_RING_SIZE];
private float[] accelRingY = new float[ACCEL_RING_SIZE];
private float[] accelRingZ = new float[ACCEL_RING_SIZE];
private int velRingCounter = 0;
private float[] velRing = new float[VEL_RING_SIZE];
private long lastStepTimeNs = 0;
private float oldVelocityEstimate = 0;
private StepListener listener;
public void registerListener(StepListener listener) {
this.listener = listener;
}
/**
* Accepts updates from the accelerometer.
*/
public void updateAccel(long timeNs, float x, float y, float z) {
float[] currentAccel = new float[3];
currentAccel[0] = x;
currentAccel[1] = y;
currentAccel[2] = z;
// First step is to update our guess of where the global z vector is.
accelRingCounter++;
accelRingX[accelRingCounter % ACCEL_RING_SIZE] = currentAccel[0];
accelRingY[accelRingCounter % ACCEL_RING_SIZE] = currentAccel[1];
accelRingZ[accelRingCounter % ACCEL_RING_SIZE] = currentAccel[2];
float[] worldZ = new float[3];
worldZ[0] = SensorFusionMath.sum(accelRingX) / Math.min(accelRingCounter, ACCEL_RING_SIZE);
worldZ[1] = SensorFusionMath.sum(accelRingY) / Math.min(accelRingCounter, ACCEL_RING_SIZE);
worldZ[2] = SensorFusionMath.sum(accelRingZ) / Math.min(accelRingCounter, ACCEL_RING_SIZE);
float normalization_factor = SensorFusionMath.norm(worldZ);
worldZ[0] = worldZ[0] / normalization_factor;
worldZ[1] = worldZ[1] / normalization_factor;
worldZ[2] = worldZ[2] / normalization_factor;
// Next step is to figure out the component of the current acceleration
// in the direction of world_z and subtract gravity's contribution
float currentZ = SensorFusionMath.dot(worldZ, currentAccel) - normalization_factor;
velRingCounter++;
velRing[velRingCounter % VEL_RING_SIZE] = currentZ;
float velocityEstimate = SensorFusionMath.sum(velRing);
if (velocityEstimate > STEP_THRESHOLD && oldVelocityEstimate <= STEP_THRESHOLD
&& (timeNs - lastStepTimeNs > STEP_DELAY_NS)) {
listener.step(timeNs);
lastStepTimeNs = timeNs;
}
oldVelocityEstimate = velocityEstimate;
}
}
解决方案
推荐阅读
- mysql - 如何在 Spring MVC 中使用 JDBC 从数据库中检查用户名和密码?
- html - 调整图像大小
- awk - 如何在多个文件上使用 awk(每个文件的第一个字段)并获取每个输入文件的结果
- eclipse - 在 mac 上安装 Eclipse 时出错
- javascript - 如何将javascript数组转换为特定的对象列表
- c# - Lucene.Net IndexWriter 无法加载文件错误?
- javascript - 如何根据“父”ID 进行填充然后匹配
- python-3.x - 如何导入以数字开头的文件(227exercise.py)?
- c# - 如何在 AngularJS + Web Api 2 中发送跨源请求的自定义标头?
- java - 二维数组按输入排序,然后是第二个