java - 无法使用 System.currentTimeMillis() 在 Android 中计算时间差
问题描述
我正在开发一个小的 Android 应用程序来计算使用手机的加速度计击中一个正方形与另一个正方形所需的时间。
我有一个自定义视图定义如下:(为了便于阅读,我删除了几个声明)
public class BallView extends View implements SensorEventListener {
private long startTime = 0;
private long endTime = 0;
private long time = 0;
public BallView( Context context) {
super( context);
init( context );
}
private void init(Context context) {
size = 200;
orignSize = size;
rectBall.set(currentX,currentY,currentX+size,currentY+size);
rectviseur.set(getWidth()/2-10,getHeight()/2-10,getWidth()/2-5,getHeight()/2-5);
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
startT();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
currentX = 0;
currentY = 0;
}
@Override
protected void onDraw(Canvas canvas) {
rectviseur.set(getWidth()/2-4,getHeight()/2-4,getWidth()/2+4,getHeight()/2+4);
super.onDraw(canvas);
paintViseur.setColor(Color.GREEN);
paint.setColor(Color.RED);
rectBall.set(currentX,currentY,currentX+size,currentY+size);
canvas.drawRect(rectBall,paint);
canvas.drawRect(rectviseur,paintViseur);
paint.setTextSize(20);
canvas.drawText(String.valueOf(time),300,300,paint);
}
private void moveImage( float x, float y ) {
currentX += (int) x;
currentY += (int) y;
if ( currentX < 0 ) {
currentX = 0;
} else if ( currentX + size > getWidth() ){
this.currentX = getWidth() - size;
}
if ( currentY < 0 ) {
currentY = 0;
} else if ( currentY + size > getHeight() ){
currentY = getHeight() - size;
}
invalidate();
}
@Override
public void onAccuracyChanged(Sensor arg0, int arg1) {}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER ) {
x = event.values[0];
y = event.values[1];
z = event.values[2];
}
if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE ) {
xg = event.values[0];
yg = event.values[1];
zg = event.values[2];
}
this.moveImage( -x*5, -(z-(float)5.5)*5 );
hit();
}
public void hit(){
if (rectBall.contains(rectviseur)) {
//vibrate
if (Build.VERSION.SDK_INT >= 26) {
vibrator.vibrate(VibrationEffect.createOneShot(200, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
vibrator.vibrate(200);
}
//replace the rectangle
size = size-20;
currentX = random.nextInt(getWidth()-size);
currentY = random.nextInt(getHeight()-size);
if (size < 8) {
size= orignSize;
}
stopT();
time = time(startTime, endTime);
startT();
}
}
private void startT() {
startTime = System.currentTimeMillis();
}
private void stopT() {
endTime = System.currentTimeMillis();
}
private long time(long start, long end) {
return (end - start);
}
}
我有 3 个变量startTime
来存储游戏启动(或重新启动)endTime
的当前时间、存储方块被击中的当前时间以及time
计算所花费的时间。
我通过分别调用和来影响startTime
和。第一个做作是在方法上。我用endTime
startT()
stopT()
startTime
init
canvas.drawText(String.valueOf(time),300,300,paint);
正如您所看到的,当方块碰到另一个方块时,该方法hit()
被调用。在这个方法结束时,我调用stopT()
存储方块被击中的时间,并调用该time
方法来计算它所花费的时间。然后我记得startT()
因为游戏重新开始。
所以从技术上讲,startTime
它应该包含类似“1607303475300”和endTime
类似“1607303477350”的东西。但我time
每次都得到完全不连贯的结果。像 5、7 或 8,而时间以毫秒为单位,这是不可能的。我真的不明白为什么。我尝试了几种解决方案,但都没有奏效,所以我正在寻求您的帮助。
编辑:
这也是使用我的 BallView 的 MainActivity 类:
public class MainActivity extends Activity {
private BallView ballView;
private SensorManager sensorManager = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ballView = new BallView(this);
ballView.setBackgroundColor(Color.BLACK);
setContentView(ballView);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
}
@Override
protected void onResume() {
super.onResume();
sensorManager.registerListener(
ballView,
sensorManager.getDefaultSensor( Sensor.TYPE_ACCELEROMETER ),
sensorManager.SENSOR_DELAY_GAME );
sensorManager.registerListener(
ballView,
sensorManager.getDefaultSensor( Sensor.TYPE_GYROSCOPE ),
sensorManager.SENSOR_DELAY_GAME );
}
@Override
protected void onPause() {
super.onPause();
sensorManager.unregisterListener( ballView );
}
}
解决方案
我没有看到 OnSensorChanged 只被调用一次的限制。假设有一个加速度计事件,紧接着是一个陀螺仪事件。由于您只保留“最后一次”,因此您最终会得到两个事件之间的间隔。
另一种方法是考虑“靠近在一起”的调用是同一时间间隔的一部分。让我试着勾勒一下这种方法。我喜欢一种计时方法而不是三种。
// This is an estimate of how much time needs to
// elapse before we consider an 'event' to be the
// first in a new timing interval. 3 seconds is
// just my guess; it depends on what you want.
final static long shortInterval = 3_000;
// Clock time at start of new interval
long intervalStart = 0;
// Elapsed time in interval since last call
long elapsed = 0;
// The timer. Call on every sensor event.
void intervalTimer() {
long now = System.currentTimeMilliseconds();
if (now - intervalStart > shortInterval)
intervalStart = now;
elapsed = now - intervalStart;
}
你就在那里。intervalTimer
从您的 init 方法和 OnSensorChanged 的末尾调用。只要调用之间的时间超过该shortInterval
值,测量就会自动重置。的值elapsed
在您需要使用时可用。
推荐阅读
- java - 如何从底部开始循环遍历图像中的所有像素?
- node.js - 使用 NPM 安装会出现错误:2406C06E:随机数生成器
- javascript - 在 React 中映射元素时,如何根据特定索引处的字段有条件地渲染节点?
- angular - 为什么 Angular 找不到这个特定的管道?
- python - Python单击确定执行前链接命令的顺序
- mongodb - mongoimport 错误,失败:无效的 JSON 输入
- networking - 配置规则以检测 SMTP、HTTP 和 DNS 流量
- visual-studio - 有没有办法在 Visual Studio 2017 中查看解决方案/项目构建使用的每个文件?
- laravel - Laravel 工厂创建 Eloquent Models 会创建属性错误的模型
- git - 基于 svn 忽略列表配置取消版本/删除文件