Search code examples
javascriptjavacordovaclasscordova-plugins

Redesigning a non-singleton Java class for a Cordova plugin?


When you create a Java class for a Cordova plugin and want to make that available to the JavaScript side, then you have to design the Java class as a singleton. At least that how I understand it.
This is pretty problematic for several obvious reason. Now my question is if there is a best-practice or anything like that on how to design that Java class, so that I can work on multiple instances or at least get the illusion that I am, on the JavaScript side.
Note: I don't need inheritence to work on the JavaScript class.

For instance, if this is my plugin code:

public class Player extends CordovaPlugin {
    private static int idCounter = 0;
    private int id;
    private int health;
    private int gold;
    private String area = "Home";

    public Player(health,gold) {
        this.health = health;
        this.gold = gold;
        this.id = idCounter++;
    }

    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        if (action.equals("move")) {
            String area = args.getString(0); 
            this.move(area, callbackContext);
            return true;
        }
        return false;
    }

    private void move(String area, CallbackContext callbackContext) {
        if (area != null && area.length() > 0) { 
            this.area = area
            callbackContext.success();
        } else {
            callbackContext.error("Expected one non-empty string argument.");
        }
    }
}

How could I implement this to actually be compatible with Cordova?

Edit: I should mention that the app I'm developing is just for Android.


Solution

  • I would split the logic across two classes: a singleton plugin class and an instantiable player class, something like this:

    Updated for multiple player instances

    public class PlayerPlugin extends CordovaPlugin {
    
        private HashMap<int, Player> players = new HashMap<int, Player>();
    
        @Override
        public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
            if (action.equals("create")) {
                this.create(args, callbackContext);
                return true;
            }else if (action.equals("move")) {
                this.move(args, callbackContext);
                return true;
            }else if (action.equals("get")) {
                this.get(args, callbackContext);
                return true;
            }
            return false;
        }
    
        private void create(JSONArray args, CallbackContext callbackContext) {
                int health = args.getInt(0); 
                int gold = args.getInt(1);
                Player player = new Player(health, gold);
                players.put(player.id, player);
                callbackContext.success(player.id);
        }
    
        private void move(JSONArray args, CallbackContext callbackContext) {
            int playerId = args.getInt(0);
            String area = args.getString(1); 
            if (area != null && area.length() > 0) { 
                Player player = players.get(playerId);
                player.area = area;
                callbackContext.success();
            } else {
                callbackContext.error("Expected one non-empty string argument.");
            }
        }
    
        private void get(JSONArray args, CallbackContext callbackContext) {
            int playerId = args.getInt(0);
            Player player = players.get(playerId);
    
            JSONObject jsPlayer = new JSONObject();
            jsPlayer.put("health", player.health);
            jsPlayer.put("gold", player.gold);
            jsPlayer.put("area", player.area);
            callbackContext.success(jsPlayer);
        }
    }
    
    public class Player {
        private static int idCounter = 0;
        private int id;
        private int health;
        private int gold;
        private String area = "Home";
    
        public Player(health,gold) {
            this.health = health;
            this.gold = gold;
            this.id = idCounter++;
        }
    }