Android: using SharedPreferences in a shaking listener class

Firstly, I'm pretty new to Android and programming in general, so please take it easy ;-) Secondly, I think this site is a lifesaver! Okay, now to the meat of the question ...

In my attempts to learn more about Android development and using custom settings, I created a small app that works great and has a number of settings that the user can change to make it look different. However, I ran into a small problem trying to tweak it to adjust the sensitivity of the jitter detection and the time between jitter detection.

Everything works for me so that if the user shakes the phone, he does what I want. Here's the basics of what I did for Shake Detection (based on an excellent post here on stackoverflow ( Android: I want to shake it )):

Created a new class named ShakeDetector and injected the following code into it:

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.FloatMath;

public class ShakeDetector implements SensorEventListener {

/*
 * The gForce that is necessary to register as shake.
 * Must be greater than 1G (one earth gravity unit).
 * You can install "G-Force", by Blake La Pierre
 * from the Google Play Store and run it to see how
 *  many G it takes to register a shake
 */
private static final float SHAKE_THRESHOLD_GRAVITY = 2.7F;
private static final int SHAKE_SLOP_TIME_MS = 500;
private static final int SHAKE_COUNT_RESET_TIME_MS = 3000;

private OnShakeListener mListener;
private long mShakeTimestamp;
private int mShakeCount;

public void setOnShakeListener(OnShakeListener listener) {
    this.mListener = listener;
}

public interface OnShakeListener {
    public void onShake(int count);
}

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

@Override
public void onSensorChanged(SensorEvent event) {

    if (mListener != null) {
        float x = event.values[0];
        float y = event.values[1];
        float z = event.values[2];

        float gX = x / SensorManager.GRAVITY_EARTH;
        float gY = y / SensorManager.GRAVITY_EARTH;
        float gZ = z / SensorManager.GRAVITY_EARTH;

        // gForce will be close to 1 when there is no movement.
        float gForce = FloatMath.sqrt(gX * gX + gY * gY + gZ * gZ);

        if (gForce > SHAKE_THRESHOLD_GRAVITY) {
            final long now = System.currentTimeMillis();
            // ignore shake events too close to each other (500ms)
            if (mShakeTimestamp + SHAKE_SLOP_TIME_MS > now) {
                return;
            }

            // reset the shake count after 3 seconds of no shakes
            if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now) {
                mShakeCount = 0;
            }

            mShakeTimestamp = now;
            mShakeCount++;

            mListener.onShake(mShakeCount);
        }
    }
}
}

      

Then I added the following to my onCreate method of my main activity:

        // ShakeDetector initialization
    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mAccelerometer = mSensorManager
            .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    mShakeDetector = new ShakeDetector();
    mShakeDetector.setOnShakeListener(new OnShakeListener() {

        @Override
        public void onShake(int count) {
            /*
             * The following method, "handleShakeEvent(count):" is a stub //
             * method you would use to setup whatever you want done once the
             * device has been shook.
             */
            handleShakeEvent(count);
        }
    });

      

Again, at this stage, everything works as desired. However, I'm not sure how to do this: set SHAKE_THRESHOLD_GRAVITY and SHAKE_COUNT_RESET_TIME_MS in the ShakeDetector class to use the general settings I already have in my application. Everything is set up in the app (and works) to allow the user to log in and select a different value for both of these parameters, but I'm not sure how to pass the SharedPreferences settings from this activity to this class. I've tried several different things with no luck and I can't find anything on the internet detailing how to do this. This is probably something pretty simple, but I don't really like figuring it out.

In a nutshell, I tried to create another method in the ShakeDetector class (for example, setShakePreferences ()) and then put code in it that looks something like this:

    public void setShakePreferences() {

    shake_sensitivity = myPrefs.getString(SHAKE_THRESHOLD_GRAVITY2, "2.7");
    shake_time_between = myPrefs.getString(SHAKE_COUNT_RESET_TIME_MS2, "3000");
    float shake_threshold_gravity = Float.valueOf(shake_sensitivity);
    int shake_count_reset_time_ms = Integer.valueOf(shake_time_between);

}

      

I've tried passing to SharedPreferences (e.g. setShakePreferences (SharedPreferences myPrefs)) in various ways, however everything I've tried to make myPrefs actually contain SharedPreferences only ever seems to end up with a null value for myPrefs. I have some settings in my main activity that are controlled via user settings and I have methods similar to the one above this work. I just don't know how to set myPrefs for the actual SharedPreferences in the ShakeDetector class.

Please, help. Detailed examples of solution examples will best help me understand how I can do this. Thank!

+3


source to share


1 answer


Thought about it after reading a little more about how to implement interfaces. It was pretty simple once I figured it out (not sure why I didn't catch it to start with).

Basically, I changed onCreate () to pass sharedPreferences like this (just added "this.myPrefs" as a parameter):

        // ShakeDetector initialization
    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    mShakeDetector = new ShakeDetector();
    mShakeDetector.setOnShakeListener(new OnShakeListener() {

        @Override
        public void onShake(int count) {
            /*
             * The following method, "handleShakeEvent(count):" is a stub //
             * method you would use to setup whatever you want done once the
             * device has been shook.
             */
            handleShakeEvent(count);
        }
    }, this.myPrefs); // <<<--- ADDED IT HERE

      



Then I had to change the setOnShakeListener in the ShakeDetector class to accept myPrefs as a parameter and add everything so that it handles the variables correctly. This is what I ended up with:

import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.FloatMath;
import android.util.Log;

public class ShakeDetector implements SensorEventListener {

/*
 * The gForce that is necessary to register as shake.
 * Must be greater than 1G (one earth gravity unit).
 * You can install "G-Force", by Blake La Pierre
 * from the Google Play Store and run it to see how
 *  many G it takes to register a shake
 */
private static final String SHAKE_THRESHOLD_GRAVITY = "<replace this with the android:key value you have configured in you preferences XML file.>";
private static final String SHAKE_COUNT_RESET_TIME_MS = "<replace this with the android:key value you have configured in you preferences XML file.>";
private static final String SHAKE_SLOP_TIME_MS = "<replace this with the android:key value you have configured in you preferences XML file.>";

private OnShakeListener mListener;
private long mShakeTimestamp;
private int mShakeCount;
private SharedPreferences myPrefs;

public void setOnShakeListener(OnShakeListener listener, SharedPreferences myPrefs) {
    this.mListener = listener;
    this.myPrefs = myPrefs;
}

public interface OnShakeListener {
    public void onShake(int count);
}

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

@Override
public void onSensorChanged(SensorEvent event) {

    if (mListener != null) {
        float x = event.values[0];
        float y = event.values[1];
        float z = event.values[2];

        float gX = x / SensorManager.GRAVITY_EARTH;
        float gY = y / SensorManager.GRAVITY_EARTH;
        float gZ = z / SensorManager.GRAVITY_EARTH;

        // gForce will be close to 1 when there is no movement.
        float gForce = FloatMath.sqrt(gX * gX + gY * gY + gZ * gZ);

        if (gForce > Float.parseFloat(myPrefs.getString(SHAKE_THRESHOLD_GRAVITY, "2.7F"))) {
            final long now = System.currentTimeMillis();
            // ignore shake events too close to each other (500ms)
            if (mShakeTimestamp + Integer.parseInt(myPrefs.getString(SHAKE_SLOP_TIME_MS, "500")) > now) {
                return;
            }

            // reset the shake count after 3 seconds of no shakes
            if (mShakeTimestamp + Integer.parseInt(myPrefs.getString(SHAKE_COUNT_RESET_TIME_MS, "3000")) < now) {
                mShakeCount = 0;
            }

            mShakeTimestamp = now;
            mShakeCount++;

            mListener.onShake(mShakeCount);
        }
    }
}
}

      

Hope this helps if anyone else is interested.

0


source







All Articles