• Android系统示例分析之AccelerometerPlay


    程序界面:

    image

    创建 SimulationView , 实现接口 SensorEventListener , 实现接口中两个抽象方法

    public void onSensorChanged(SensorEvent event);

    public void onAccuracyChanged(Sensor sensor, int accuracy);

    SimulationView 扩展了 View ,至少需要一个构造方法,例如

    public SimulationView(Context context) {

      super(context);

    }

    SimulationView 构造方法中

    // 得到加速传感器

    mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

     

    得到屏幕上X/Y方向上每英寸有多少个物理像素

    DisplayMetrics metrics = new DisplayMetrics();

    getWindowManager().getDefaultDisplay().getMetrics(metrics);

    mXDpi = metrics.xdpi;

    mYDpi = metrics.ydpi;

     

    注:float android.util.DisplayMetrics.xdpi

    The exact physical pixels per inch of the screen in the X dimension.

    译:在屏幕的X方向,每英寸有多少个物理像素。

     

    将“每英寸有多少个物理像素”换算成“每米有多少个物理像素”,其中1.0英寸等于0.0254米。

    mMetersToPixelsX = mXDpi / 0.0254f;

    mMetersToPixelsY = mYDpi / 0.0254f;

     

    将小球位图进行缩放处理,宽度 = 小球直径 X (每米有多少个像素),高度计算方法类似

    Bitmap ball = BitmapFactory.decodeResource(getResources(), R.drawable.ball);

    final int dstWidth = (int) (sBallDiameter * mMetersToPixelsX + 0.5f);

    final int dstHeight = (int) (sBallDiameter * mMetersToPixelsY + 0.5f);

    mBitmap = Bitmap.createScaledBitmap(ball, dstWidth, dstHeight, true);

     

    得到 wood 位图

    Options opts = new Options();

    opts.inDither = true;

    opts.preferredConfig = Bitmap.Config.RGB_656;

    mWood = BitmapFactory.decodeResource(getResources(), R.drawable.wood, opts);

     

    注:boolean android.graphics.BitmapFactory.Options.inDither
    If dither is true, the decoder will attempt to dither the decoded image.

    生词:

    dither 抖,发抖,兴奋,犹豫不决;

     

    在 SimulationView 类中,除构造方法SimulationView,onSensorChanged, onAccuracyChanged,还有

    public void onSizeChanged(int w, int h, int oldW, int oldH);

    public void onDraw(Canvas canvas);

     

    在 SimulationView 类中,定义了子类 Particle。

    在 Particle 构造方法中,

    final float r = ((float) Math.random() – 0.5f) * 0.2f;

    mOneMinusFriction = 1.0f – sFriction + r;

     

    在AccelerometerPlayActivity.onCreate()方法中

    // 得到 SensorManager 对象

    mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

    // 得到 PowerManager 对象

    mPowerManager = (PowerManager) getSystemService(POWER_SERVICE);

    // 得到 WindowManager 对象

    mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

    // 得到 Display 对象

    mDisplay = mWindowManager.getDefaultDisplay();

    // 得到 WakeLock 对象

    mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, getClass().getName());

    // 创建 SimulationView 对象

    mSimulationView = new SimulationView(this);

    // 设置 ContentView

    setContentView(mSimulationView);

     

    在AccelerometerPlayActivity类中,除了onCreate方法,还有onResume和onPause方法

     

    在AccelerometerPlayActivity.onResume方法中

    mWakeLock.acquire();

    mSimulationView.startSimulation();

     

    在SimulationView.startSimulation()方法中注册加速器传感器。

    mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_UI);

     

    注:int android.hardware.SensorManager.SENSOR_DELAY_UI = 2 [0x2]
    rate suitable for the user interface

    生词:

    rate 比率,速度,价格,费用,等级;

     

    在AccelerometerPlayActivity.onPause方法中

    mSimulationView.stopSimulation();

    mWakeLock.release();

     

    在SimulationView.stopSimulation()方法中注销加速器传感器。

    mSensorManager.unregisterListener(this);

     

    在SimulationView中,定义ParticleSystem变量

    private final ParticleSystem mParticleSystem = new ParticleSystem();

     

    在SimulationView.onSensorChanged方法中

    注:SensorEventListener.onSensorChanged: Called when sensor values have changed.

    // 判断是加速计传感器数据发生了变化

    if(event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)

      return;

    // 当SensorValue发生变化时,重新计算mSensorX和mSensorY两个数值

    switch (mDisplay.getRotation()) {

      case Surface.ROTATION_0:

        mSensorX = event.values[0];

        mSensorY = event.values[1];

        break;

      case Surface.ROTATION_90:

        mSensorX = -event.values[1];

        mSensorY = event.values[0];

        break;

      case Surface.ROTATION_180:

        mSensorX = -event.values[0];

        mSensorY = -event.values[1];

        break;

      case Surface.ROTATION_270:

        mSensorX = event.values[1];

        mSensorY = -event.values[0];

        break;   

    }

    得到事件发生的时间

    mSensorTimeStamp = event.timestamp;

    mCpuTimeStamp = System.nanoTime();

     

    注:long java.lang.System.nanoTime()

    the current timestamp in nanoseconds.

    生词:nanoseconds 纳秒

    注:long android.hardware.SensorEvent.timestamp

    The time in nanosecond at which the event happened

     

    在 SimulationView.onDraw(Canvas) 方法中

    // 绘出背景图片(木板)

    canvas.draw(mWood, 0, 0, null);

     

    方法解析:

    public void SimulationView.ParticleSystem.update(float sx, float sy, long now)

    Performs one iteration of the simulation. First updating the position of all the particles and resolving the constraints and collisions.

    生词:

    perform 执行,履行,表演,运转,举行;

    iteration 迭代,循环,重复;

    resolve 分解,溶解,解析;

    constraints 强制,约束,被约束;

    collisions 碰撞

     

    方法解析

    private void SimulationView.ParticleSystem.updatePositions(float sx, float sy, long timestamp)

    Update the position of each particle in the system using the Verlet integrator.

    译:更新每个粒子的位置。

     

    方法解析

    public void SimulationView.Particle.computePhysics(float sx, float sy, float dT, float dTC)

     

    计算小球的坐标,在画布上绘出小球

    final float x = xc + particleSystem.getPosX(i) * xs;

    final float y = yc - particleSystem.getPosY(i) * ys;

    canvas.drawBitmap(bitmap, x, y, null);

     

    xc和yc都在onSizeChanged方法中计算。

    mXOrigin = (w - mBitmap.getWidth()) * 0.5f;

    mYOrigin = (h - mBitmap.getHeight()) * 0.5f;

    xc和yc在使用时都被赋值mXOrigin和mYOrigin。

    两条语句表现出,小球的起始位置在屏幕的中间。

     

    xc, yc, xs, ys, bitmap直接被赋值,很容易理解

    final float xc = mXOrigin;
    final float yc = mYOrigin;
    final float xs = mMetersToPixelsX;
    final float ys = mMetersToPixelsY;
    final Bitmap bitmap = mBitmap;

    其中mXOrigin, mYOrigin在onSizeChanged计算。

    mMetersToPixelsX, mMetersToPixelsY在onCreate中计算。

    mBitmap在onCreate中赋值。

     

    注:void SimulationView.onSizeChanged(int w, int h, int oldw, int oldh)

    This is called during layout when the size of this view has changed. If you were just added to the view hierarchy, you're called with the old values of 0.

    译:当view的大小发生变化时调用。如果是加入到view hierarchy中,oldw和oldh的数值都为0。


    在onDraw(Canvas)方法最后调用invalidate方法。

    注:void android.view.View.invalidate()
    Invalidate the whole view. If the view is visible, onDraw will be called at some point in the future. This must be called from a UI thread. To call from a non-UI thread, call postInvalidate().

    生词:
    invalidate 使作废,使无效;

    注:void SimulationView.Particle.resolveCollisionWithBounds()

    Resolving constraints and collisions with the Verlet integrator can be very simple, we simply need to move a colliding or constrained particle in such way that the constraint is satisfied.

    生词:

    collide 碰撞

    相关:Source/HelixToolkit.Wpf/Physics/VerletIntegrator.cs

     

    在onSizeChanged方法中计算HorizontalBound和mVerticalBound

    mHorizontalBound = ((w / mMetersToPixelsX - sBallDiameter) * 0.5f);
    mVerticalBound = ((h / mMetersToPixelsY - sBallDiameter) * 0.5f);

    跟踪记录:

    mHorizontalBound = (0.076 – 0.004) * 0.5f = 0.036;

    mVerticalBound = (0.127 – 0.004) * 0.5f = 0.0615;

     

    到目前为止,小球的位置如何计算,就不是很清楚了。

    其实这个示例蛮简单的,只是让小球以某个规律/算法移动位置,每移动一次就重绘一次。

  • 相关阅读:
    java9的JShell小工具和编译器两种自动优化
    运算符
    数据类型
    常量&&变量
    强化学习复习笔记
    强化学习复习笔记
    DQN算法原理详解
    语言模型评价指标Perplexity
    C++ STL标准容器插入删除算法的复杂度
    集束搜索beam search和贪心搜索greedy search
  • 原文地址:https://www.cnblogs.com/fengzhblog/p/3167647.html
Copyright © 2020-2023  润新知