Search code examples
androidcordovaphonegap-pluginscordova-plugins

Why can't I access an instance of CordovaInterface in a CordovaPlugin constructor?


So, none of the example Cordova Plugins I saw have a constructor, so I might be doing something fundamentally wrong here. I'm creating one for Android and using Phonegap 3.3.0, and this is my problem:

public class MypluginClass extends CordovaPlugin  {

    //...things

    public MyPluginClass(){

        SharedPreferences settings = cordova.getActivity().getPreferences(Activity.MODE_PRIVATE); 
        //The line above fails with a null pointer exception

        String localVar = settings.getString("importantVariable", "importantDefault");

        //...do other things

    }

    @Override   
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
        //...many things
    }

    ...
}

At the line

SharedPreferences settings = cordova.getActivity().getPreferences(Activity.MODE_PRIVATE); 

I get:

java.lang.NullPointerException
    at com.abc.cde.def.MyPluginClass.<init>(MyPluginClass.java:69)
    at java.lang.Class.newInstanceImpl(Native Method)
    at java.lang.Class.newInstance(Class.java:1208)
    at org.apache.cordova.PluginEntry.createPlugin(PluginEntry.java:95)
    at org.apache.cordova.PluginManager.getPlugin(PluginManager.java:278)
    at org.apache.cordova.PluginManager.execHelper(PluginManager.java:232)
    at org.apache.cordova.PluginManager.exec(PluginManager.java:227)
    at org.apache.cordova.ExposedJsApi.exec(ExposedJsApi.java:53)
    at com.android.org.chromium.base.SystemMessageHandler.nativeDoRunLoopOnce(Native Method)
    at com.android.org.chromium.base.SystemMessageHandler.handleMessage(SystemMessageHandler.java:27)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:136)
    at android.os.HandlerThread.run(HandlerThread.java:61)
Error adding plugin com.abc.cde.def.MyPluginClass.

The reason I am trying to do this is the following code:

public class MyClass extends CordovaActivity{
     public void onCreate(Bundle savedInstanceState){
          //...things

          File appDir = context.getExternalFilesDir(null);
          //create some files at the location above   -   (step1)

          SharedPreferences settings = getPreferences(MODE_PRIVATE);
          SharedPreferences.Editor editor = settings.edit();
          editor.putString("importantVariable", variablesCreatedByStep1);
          editor.commit();

          //...other things
     }
}

As I type this, I understand this kind of data exchange should not even be happening in the first place. On rethinking moving code in the MyClass.onCreate into MyPluginClass, two questions come to mind:

  1. Can I still use a constructor, or a called-only-once equivalent, because I want this code to execute only once, on initialization (maybe pluginInitialize() ?)
  2. If yes, how do I do the equivalent of this : context.getExternalFilesDir(null);

Which brings me back to the question I really want to ask. Why does

cordova.getActivity()

fail with a null pointer exception inside the Cordova Plugin constructor?


Solution

  • I am not sure about the constructor initialization mechanism in Java by heart but afaik, cordova plugin instances are static instances and you may not be able to make sure the CordovaActivity has been created & initialized before your plugin ctor. You can check it by debugging pretty easily though.

    I would rather add an init method to the plugin class. You can even get the variable from shared storage (code in your plugin ctor) in your execute() function I suppose. You have several alternatives I think.