Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android

Android - crystalball runtime exception

Once we added the shakedetector and used the sensor manager I started getting a java.lang.RunTimeException at the android.hardware.sensormanager.

Suggestions?

4 Answers

I think the problem is in the onResume method in MainActivity

@Override
    public void onResume() {
    super.onResume();
    mSensorManager.registerListener((SensorEventListener) mSensorManager, mAccelerometer,
            SensorManager.SENSOR_DELAY_UI);
}

You're passing mSensorManager as the first parameter to mSensorManager.registerListener. You should be passing mShakeDetector instead. Here's my code.

   @Override
   public void onResume()
   {
      super.onResume();
      mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
   }

Post your code.

I posted the MainActivity.java and crystalball.java and shakedetector.java.

MainActivity.java

package com.example.crystalball;

import android.app.Activity; import android.graphics.drawable.AnimationDrawable; import android.hardware.Sensor; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.os.Bundle; import android.view.Menu; import android.view.animation.AlphaAnimation; import android.widget.ImageView; import android.widget.TextView;

import com.example.crystalball.ShakeDetector.OnShakeListener;

public class MainActivity extends Activity {

private CrystalBall mCrystalBall = new CrystalBall();
private TextView mAnswerLabel;
private ImageView mCrystalBallImage;
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private ShakeDetector mShakeDetector;



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // assigning the views from the layout file.
    mAnswerLabel = (TextView) findViewById(R.id.textView1) ;
    mCrystalBallImage = (ImageView) findViewById(R.id.imageView1);
    mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    mShakeDetector = new ShakeDetector(new OnShakeListener() {

        @Override
        public void onShake() {
            handleNewAnswer();
        }
    });
}

@Override
    public void onResume() {
    super.onResume();
    mSensorManager.registerListener((SensorEventListener) mSensorManager, mAccelerometer,
            SensorManager.SENSOR_DELAY_UI);
}

@Override
    public void onPause() {
    super.onPause();
    mSensorManager.unregisterListener(mShakeDetector);
}

private void animateCrystalBall() {
    mCrystalBallImage.setImageResource(R.drawable.ball_animation);
    AnimationDrawable ballAnimation = (AnimationDrawable) mCrystalBallImage.getDrawable();
    if (ballAnimation.isRunning()) {
        ballAnimation.stop();
    }
    ballAnimation.start();

}
private void animateAnswer() {
    AlphaAnimation fadeInAnimation = new AlphaAnimation(0, 1);
    fadeInAnimation.setDuration(1500);
    fadeInAnimation.setFillAfter(true);
    mAnswerLabel.setAnimation(fadeInAnimation);

}

private void playSound() {
    MediaPlayer player = MediaPlayer.create(this, R.raw.crystal_ball);
    player.start();
    player.setOnCompletionListener(new OnCompletionListener() {

        public void onCompletion(MediaPlayer mp) {
            mp.release();
        }
    });
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

private void handleNewAnswer() {
    String answer = mCrystalBall.getAnAnswer();
    mCrystalBall.mAnswers[0] = "test";
    //update your answer
    mAnswerLabel.setText(answer);

    animateCrystalBall();
    animateAnswer();
    playSound();
}

}

==================

crystalball.java

package com.example.crystalball;

import java.util.Random;

public class CrystalBall { // member variables (properties about the object) public String[] mAnswers ={ "It is certian", "It is decidely so", "All the stars say Yes", "The stars are not aligned", "My reply is no", "It is doubtful", "Better not tell you now", "Concentrate and ask again", "Unable to answer now",

};

// Methods (abilities:things an object can do) public String getAnAnswer() {

    // we need an answer when our button is clicked
    String answer = "";

    //randomly select an answer, yes, no, maybe
    Random randomGenerator = new Random();
    //make the lenth fo the array variable
    int randomNumber = randomGenerator.nextInt(mAnswers.length);

    //pull an answer from the array above
    answer = mAnswers[randomNumber];

    return answer;
}

}

==============

shakedetector.java

package com.example.crystalball;

import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener;

public class ShakeDetector implements SensorEventListener {

// Minimum acceleration needed to count as a shake movement
private static final int MIN_SHAKE_ACCELERATION = 5;

// Minimum number of movements to register a shake
private static final int MIN_MOVEMENTS = 2;

// Maximum time (in milliseconds) for the whole shake to occur
private static final int MAX_SHAKE_DURATION = 500;

// Arrays to store gravity and linear acceleration values
private float[] mGravity = { 0.0f, 0.0f, 0.0f };
private float[] mLinearAcceleration = { 0.0f, 0.0f, 0.0f };

// Indexes for x, y, and z values
private static final int X = 0;
private static final int Y = 1;
private static final int Z = 2;

// OnShakeListener that will be notified when the shake is detected
private OnShakeListener mShakeListener;

// Start time for the shake detection
long startTime = 0;

// Counter for shake movements
int moveCount = 0;

// Constructor that sets the shake listener
public ShakeDetector(OnShakeListener shakeListener) {
    mShakeListener = shakeListener;
}

@Override
public void onSensorChanged(SensorEvent event) {
    // This method will be called when the accelerometer detects a change.

    // Call a helper method that wraps code from the Android developer site
    setCurrentAcceleration(event);

    // Get the max linear acceleration in any direction
    float maxLinearAcceleration = getMaxCurrentLinearAcceleration();

    // Check if the acceleration is greater than our minimum threshold
    if (maxLinearAcceleration > MIN_SHAKE_ACCELERATION) {
        long now = System.currentTimeMillis();

        // Set the startTime if it was reset to zero
        if (startTime == 0) {
            startTime = now;
        }

        long elapsedTime = now - startTime;

        // Check if we're still in the shake window we defined
        if (elapsedTime > MAX_SHAKE_DURATION) {
            // Too much time has passed. Start over!
            resetShakeDetection();
        }
        else {
            // Keep track of all the movements
            moveCount++;

            // Check if enough movements have been made to qualify as a shake
            if (moveCount > MIN_MOVEMENTS) {
                // It's a shake! Notify the listener.
                mShakeListener.onShake();

                // Reset for the next one!
                resetShakeDetection();
            }
        }
    }
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
    // Intentionally blank
}

private void setCurrentAcceleration(SensorEvent event) {
    /*
     *  BEGIN SECTION from Android developer site. This code accounts for 
     *  gravity using a high-pass filter
     */

    // alpha is calculated as t / (t + dT)
    // with t, the low-pass filter's time-constant
    // and dT, the event delivery rate

    final float alpha = 0.8f;

    // Gravity components of x, y, and z acceleration
    mGravity[X] = alpha * mGravity[X] + (1 - alpha) * event.values[X];
    mGravity[Y] = alpha * mGravity[Y] + (1 - alpha) * event.values[Y];
    mGravity[Z] = alpha * mGravity[Z] + (1 - alpha) * event.values[Z];

    // Linear acceleration along the x, y, and z axes (gravity effects removed)
    mLinearAcceleration[X] = event.values[X] - mGravity[X];
    mLinearAcceleration[Y] = event.values[Y] - mGravity[Y];
    mLinearAcceleration[Z] = event.values[Z] - mGravity[Z];

    /*
     *  END SECTION from Android developer site
     */
}

private float getMaxCurrentLinearAcceleration() {
    // Start by setting the value to the x value
    float maxLinearAcceleration = mLinearAcceleration[X];

    // Check if the y value is greater
    if (mLinearAcceleration[Y] > maxLinearAcceleration) {
        maxLinearAcceleration = mLinearAcceleration[Y];
    }

    // Check if the z value is greater
    if (mLinearAcceleration[Z] > maxLinearAcceleration) {
        maxLinearAcceleration = mLinearAcceleration[Z];
    }

    // Return the greatest value
    return maxLinearAcceleration;
}

private void resetShakeDetection() {
    startTime = 0;
    moveCount = 0;
}

/*
 * Definition for OnShakeListener definition. I would normally put this
 * into it's own .java file, but I included it here for quick reference
 * and to make it easier to include this file in our project.
 */
public interface OnShakeListener {
    public void onShake();
}

}

wow makes sense. why would I pass mSensorManager to itself, right.

Thank you! rich