1

First of all, thank you for taking the time to read this. I am quite new to android development and appreciate all the help I can get. I'll keep the description brief.

I'm developing an app as a side project to speed up the d&d sessions of me and my friends by automating the initiative rolls (rolling a 20-sided dice, adding a personal modifier and sorting from largest to smallest). Everything was going great until I hit a bug which to my frustration I haven't been able to fix. The length of the sorted Arraylist with names and of the complimentary dictionary always seems to be zero and I cannot find out why. Code is posted below.

First step is to collect user data from the input. the input works like this (this explains the weird ID's)

enter image description here

//updates player database with user input
private void updateDictionaryManager(int _partySize) {
    listManager.empty();

    if (_partySize > 0) {
        for (int i = 0; i < _partySize + 1; i++) {
            EditText Name = (EditText)findViewById(i);
            EditText dexMod = (EditText)findViewById(i + 10);
            String playerName = "player " + String.valueOf(i);
            int playerDexMod = 0;

            if (Name.getText() != null) {
                playerName = Name.getText().toString();
            }

            if (dexMod.getText() != null) {
                try {
                    playerDexMod = Integer.parseInt(dexMod.getText().toString());
                } catch (Exception e) {
                    playerDexMod = 0;
                }
            }
            listManager.append(playerName, playerDexMod, i);
        }
    }
}

This is the code from the listmanager class

public void append(String _name, int _dexMod, int _playerNumber) {
    if (!_name.equals("")) {
        playerNames.add(_name);
    } else {
        String defaultName = "player " + String.valueOf(_playerNumber);
        playerNames.add(defaultName);
    }
    dexMod.add(_dexMod);
}

public void empty() {
    playerNames.clear();
    dexMod.clear();
}

I guess the problem hides here (but I send the prvious just in case I missed something there)

final class InitiativeRoller extends ListManager{
Map<Integer, List<String>> playerRolls = new HashMap<>();
Map<String, Integer> outputDictionary = new HashMap<>();

List<Integer> alreadyRolled = new ArrayList<>();
List<String> outputOrder = new ArrayList<>();

public void roll() {
    //retrieve lists from manager
    List<String> _names = getPlayerNames();
    List<Integer> _dexMod = getDexMod();

    //rolling the dice and saving values
    for (int i = 0; i < getSize(); i++) {
        int _roll = (int) Math.round(Math.random() * 19) + 1 + _dexMod.get(i);

        if (alreadyRolled.contains(_roll)) {
            //add name to list in dictionary with corresponding roll
            playerRolls.get(_roll).add(_names.get(i));
        } else {
            //generate new list for players with this roll and add to playerRolls
            List<String> _list = new ArrayList<>();
            _list.add(_names.get(i));
            playerRolls.put(_roll, _list);

            alreadyRolled.add(_roll);
        }
    }

    //sorting the rolls from largest to smallest
    Collections.sort(alreadyRolled);
    Collections.reverse(alreadyRolled);

    //generating output dictionary
    for (int i = 0; i < alreadyRolled.size(); i++) {
        int _roll = alreadyRolled.get(i);
        List<String> list = playerRolls.get(_roll);

        //shuffling order of players with the same roll
        Collections.shuffle(list);

        //add to output dictionary and list
        for (int x = 0; x < list.size(); x++) {
            outputDictionary.put(list.get(x), _roll);
            outputOrder.add(list.get(x));
        }
    }
}

public Map<String, Integer> getOutputDictionary() {
    return outputDictionary;
}

public List<String> getOutputOrder() {
    return outputOrder;
}

}

Every time I check, the resulting outputDictionary and outputorder have a length of zero. What am I missing? Sorry for the long post.

EDIT: I have checked the code and there does not seem to be a problem with the length of the list until the point where getPlayerNames and getDexMod are called inside the InitiativeRollerClass.

EDIT: Here are the get-methods

public List<String> getPlayerNames() {
    return playerNames;
}

public List<Integer> getDexMod() {
    return dexMod;
}

UPDATE: This is the code bound to the roll-button:

rollInitiative.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //update dictionary
            int roundedProgress = Math.round(playerSlider.getProgress());

            try {
                updateDictionaryManager(roundedProgress);
            } catch (Exception e) {
                updateDictionaryManagerOnException(roundedProgress, playerList);
            }

            initiativeRoller.roll();
            displayResult(initiativeRoller.getOutputOrder(), initiativeRoller.getOutputDictionary(), InitiativeList);
        }
    });

the method is described here, this is just for debugging

//displays output to user
    private void displayResult(List<String> _outputOrder, Map<String, Integer> _outputDictionary, TextView _initiativelist) {
        _initiativelist.setText(listManager.getDexMod() + "\n" + listManager.getPlayerNames()
        + "\n" + initiativeRoller.getOutputOrder());
    }

This brings me the following

enter image description here

I also checked online if the code itself for the roll class was even functioning, it was. Here is the result for four hard coded names and values after a number of runs:

[Aaron, Josh, Clide, Li]
{Aaron=24, Clide=20, Josh=22, Li=8}
sh-4.3$ java -Xmx128M -Xms16M HelloWorld
[Josh, Li, Aaron, Clide]
{Aaron=6, Clide=6, Josh=20, Li=12}
sh-4.3$ java -Xmx128M -Xms16M HelloWorld
[Aaron, Clide, Li, Josh]
{Aaron=20, Clide=17, Josh=10, Li=11}
sh-4.3$ java -Xmx128M -Xms16M HelloWorld
[Li, Aaron, Clide, Josh]
{Aaron=19, Clide=18, Josh=18, Li=21}

Everything seems to be working just fine, I just don't understand why the returned list has a length of zero.

p.s. the code for the getSize() method

public int getSize() {
    return playerNames.size();
}
  • I think, posting`getPlayerNames` and `getDexMod` methods will be helpful. – pawel-schmidt Apr 02 '17 at 13:26
  • Yes, getPlayerNames() and getDexMod() look like the only points where something can go wrong. I tried your code with direct access to these variables, and roll() does fill outputDictionary and outputOrder with info. Or maybe you should double check whether the input info is read correctly from the UI. – Gyrotank Apr 02 '17 at 13:34
  • The code for the get methods is very simple. It just returns the list of PlayerNames and the list for DexMod. – Osama Benrottihalen Apr 02 '17 at 14:38
  • You say that you have a "dictionary" (which in Java would be a Map), however it looks like you have two parallel Arraylists... You *could* make a simple Java class to hold both values (name and dexMod), and store only one List, then you don't need to maintain a two lists and build a Map at all – OneCricketeer Apr 02 '17 at 15:08
  • Not the part you're asking about, but it doesn't look like your `findViewById` lines are going to work. If you need to find out the `int` identifying the view at runtime you'll probably need `getResources().getIdentifier()`. See: http://stackoverflow.com/a/14058142/5251523 – Lewis McGeary Apr 02 '17 at 15:21
  • Where is your `getSize` code that is called under "rolling the dice and saving values"? – Anna Apr 02 '17 at 14:50
  • Yea, I previously used a dictionary. But then I decided to use two parallel lists instead and didn't rename the comments. The reason I chose the two lists is because I change the order of the roll list and use the map to keep track of what name belongs to what value. And use that to make a list of names based on who threw the highest value. It seemed the fastest solution at the time. – Osama Benrottihalen Apr 02 '17 at 18:28
  • @Lewis. When generating the layout for the player to enter the values. I assigned ID's based on the number of the player (so just an int value) and for the dexMod 10 (max amount of players) + that same number. It isn't the most elegant solution but it works. I already tested if this was the issue, but the lists come out just fine. – Osama Benrottihalen Apr 02 '17 at 18:31

1 Answers1

1

Ok, this might be the error: keep in mind that in Java every variable just as any other compiled language has a scope. Now you decleare playerName and playerDexMod inside the for and you append them inside that for, up until now everything is in check. When you exit the for however those variables just die, and by that I mean that the java garbage collector, since they're out of scope, should deallocate them. Now the listManager ( which I suppose is an ArrayList) finds itself with objects that don't exist anymore, so basically null. And that's just an empty array list. If the listManager you use is decleared in a class try to decleare also the other variables in a class, so they won't get out of scope. Tell me if this helps.