Search code examples
androidandroid-contextandroid-sensorsimesensormanager

ERROR: Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference


I am trying to implement MovementDetector in my soft keyboard, but I get this error. When I compile my code everything works, but when I start using my keyboard it shows error in logcat. Here is my code:

public class MovementDetector implements SensorEventListener {

protected final String TAG = getClass().getSimpleName();
private Sensor accelerometer;
private SensorManager mSensorMgr;
public static Context mContext;
float [] history = new float[2];
public static String [] direction = {"NONE","NONE"};

private MovementDetector(Context context) {
    mContext = context;
}

private static MovementDetector mInstance;

public static MovementDetector getInstance() {
    if (mInstance == null) {
        mInstance = new MovementDetector(mContext);
        mInstance.init();
    }
    return mInstance;
}

private HashSet<Listener> mListeners = new HashSet<MovementDetector.Listener>();

private void init() {
    mSensorMgr = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
    accelerometer = mSensorMgr.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
}

public void start() {
    mSensorMgr.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}

public void stop() {
    mSensorMgr.unregisterListener(this);
}

public void addListener(Listener listener) {
    mListeners.add(listener);
}

@Override
public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {

        float x = event.values[0];
        float y = event.values[1];
        float z = event.values[2];

        float xChange = history[0] - event.values[0];
        float yChange = history[1] - event.values[1];

        history[0] = event.values[0];
        history[1] = event.values[1];

        float diff = (float) Math.sqrt(x * x + y * y + z * z);
        if (diff > 0.5)
            if (xChange > 2){
                direction[0] = "LEFT";
            }else if (xChange < -2){
                direction[0] = "RIGHT";
            }

            if (yChange > 2){
                direction[1] = "DOWN";
            }else if (yChange < -2){
                direction[1] = "UP";
            }

        for (Listener listener : mListeners) {
            listener.onMotionDetected(event, diff);
        }
    }
}

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

}

public interface Listener {
    void onMotionDetected(SensorEvent event, float acceleration);
}

}

I get error in this line:

mSensorMgr = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);

I start MovementDetector in OnCreateInputView() and stop it in OnDestory(), but this is not the problem. The problem is in MovementDetector class. Can someone please tell me what should i do and what I did wrong? Thanks in advance. Really need this MovementDetector to work.


Solution

  • Ok, so finally based upon your inputs from above in the comments, I've been able to identify the issue. It seems that MovementDetector class is using the singleton design pattern.

    To get the instance of the MovementDetector you are using the following code

    MovementDetector.getInstance()
    

    and the getInstance() method in MovementDetector is defined as

    public static MovementDetector getInstance() {
        if (mInstance == null) {
            mInstance = new MovementDetector(mContext);
            mInstance.init();
        }
        return mInstance;
    }
    

    Now when this code (getInstance()) is called for the very first time, the mInstance is null, so it instantiates it.

    mInstance = new MovementDetector(mContext);
    

    But the problem above is that mContext is null and that is why you're getting the error! To solve your problem, you should pass the context to the getInstance() method. It should look like something like this.

    public static MovementDetector getInstance(Context context) {
            if (mInstance == null) {
                mInstance = new MovementDetector(context);
                mInstance.init();
            }
            return mInstance;
        }
    

    And wherever you're calling this method getInstance() it should change to something like

    MovementDetector.getInstance(context).start();