-2

I'm making a game with cards, characters cards.

I first create the cards chosen by the user, then add them to a List, shuffle it and then display 'em one by one, with their players name (chosen in a previous activity by the user).

The fact is, when I try to get the a Card class from the List, and invoking its methods getPlayer() & getCharacter (which return the player's name and the characters' name of the specific card) I get the nullPointer Exception.

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.example.leonardo.lupusintabula.characters.Card.getCharacter()' on a null object reference

randomButton.setText(characters.get(0).getCharacter() + " / " + characters.get(0).getPlayer());

The onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_random_assignment);

    //Retrieving
      ...
    //Done retrieving
    initializeVariables();
    createCharacters();
    run();
}

As the issue is probably in characters, I'm listing you all the code it's in:

// Where the characters are stored
private ArrayList<Card> characters;


public void initDeck() {
    addCharacter(demoniac, demoniacAmount, characters);
    addCharacter(guard, guardAmount, characters);
    addCharacter(medium, mediumAmount, characters);
    addCharacter(mythomaniac, mythomaniacAmount, characters);
    addCharacter(owl, owlAmount, characters);
    addCharacter(werehamster, werehamsterAmount, characters);
    addCharacter(getVillagerBundle(), villagerAmount, characters);
    addCharacter(masonOne, 1, characters);
    addCharacter(masonTwo, 1, characters);
}

public void addCharacter(Card card, int amount, List<Card> cards) {
    if (amount < 0) {
        throw new IllegalArgumentException("Must add a non-negative number of characters for " + card.getCharacter() );
    }

    for (int i = 0; i < amount; i++) {
        cards.add(card);
    }
}



//Pick a random one and display it
public void pick(View view){
    if(characters != null) {
        if (i < characters.size()) {
            randomButton.setText(characters.get(i).getCharacter() + " / " + characters.get(i).getPlayer());
            i++;
        } else {
            randomButton.setText(R.string.play);
        }
    }
}

void run() {
    // initialize the characters
    initDeck();

    // shuffle them
    Collections.shuffle(characters);

    //Display the 1st card
    if(characters != null) {
        randomButton.setText(characters.get(0).getCharacter() + " / " + characters.get(0).getPlayer());
    }
}


private void initializeVariables() {
    ...
    ...

    characters = new ArrayList<Card>();
 }

}

What am I doing wrong? If you need other part of the code feel free to ask, I'll provide it to you as soon as possible!

This may drive you crazy but it's the only way I found to achieve the creation of the characters (each character extends the Card class!):

public void createCharacters() {
    if (demoniacAmount != 0) {
        demoniac = new Demoniac(nameList.get(listIndex));
        listIndex++;
    } else if (guardAmount != 0) {
        guard = new Guard(nameList.get(listIndex));
        listIndex++;
    } else if (mediumAmount != 0) {
        medium = new Medium(nameList.get(listIndex));
        listIndex++;
    } else if (mythomaniacAmount != 0) {
        mythomaniac = new Mythomaniac(nameList.get(listIndex));
        listIndex++;
    } else if (owlAmount != 0) {
        owl = new Owl(nameList.get(listIndex));
        listIndex++;
    } else if (werehamsterAmount != 0) {
        werehamster = new Werehamster(nameList.get(listIndex));
        listIndex++;
    } else if (masonsAmount != 0) {
        masonOne = new Masons(nameList.get(listIndex));
        masonTwo = new Masons(nameList.get(listIndex));
        listIndex += masonsAmount;
    } else if (villagerAmount > 5) {
            villagerSix = new Villager(nameList.get(listIndex));
            villagerBundle.add(villagerSix);

            if (villagerAmount > 6) {
                villagerSeven = new Villager(nameList.get(listIndex));
                villagerBundle.add(villagerSeven);

                if (villagerAmount > 7) {
                    villagerEight = new Villager(nameList.get(listIndex));
                    villagerBundle.add(villagerEight);

                    if (villagerAmount > 8) {
                        villagerNine = new Villager(nameList.get(listIndex));
                        villagerBundle.add(villagerNine);

                        if (villagerAmount > 9) {
                            villagerTen = new Villager(nameList.get(listIndex));
                            villagerBundle.add(villagerTen);

                            if (villagerAmount > 10) {
                                villagerEleven = new Villager(nameList.get(listIndex));
                                villagerBundle.add(villagerEleven);

                                if (villagerAmount > 11) {
                                    villagerTwelve = new Villager(nameList.get(listIndex));
                                    villagerBundle.add(villagerTwelve);

                                    Toast.makeText(RandomAssignment.this, "works", Toast.LENGTH_SHORT).show();
                                }
                            }
                        }
                    }
                }
            }
        }
        listIndex += villagerAmount;
    }
FET
  • 942
  • 4
  • 13
  • 35
  • What does the method getVillagerBundle() do? Can it return null? – Blue Feb 06 '16 at 19:26
  • Collections allow to add null values. – Blackbelt Feb 06 '16 at 19:28
  • `public Card getVillagerBundle(){ int i = 0; do{return villagerBundle.get(i); } while(i < villagerBundle.size()); }` @Blue – FET Feb 06 '16 at 19:29
  • When do you actually assign a value to demoniac? – Andrew Williamson Feb 06 '16 at 19:31
  • `public void createCharacters() { if (demoniacAmount != 0) { demoniac = new Demoniac(nameList.get(listIndex)); listIndex++; }` **`...`** `}` @AndrewWilliamson – FET Feb 06 '16 at 19:34
  • Since the first thing in your list of cards is `null`, you should debug what you are inserting... Go through the initDeck function and add a whole bunch of log statements, so you can find where the null entry is coming from. – Andrew Williamson Feb 06 '16 at 19:37
  • If villagerBundle doesn't have anything in it, then that could make the NullPointerException – Blue Feb 06 '16 at 19:37
  • This code looks oddly familiar.... http://stackoverflow.com/a/35073148/2308683 – OneCricketeer Feb 06 '16 at 19:51
  • The question is different @cricket_007 let me know if you find a way – FET Feb 06 '16 at 20:12
  • All you did was strip down my code and make a Card class object. I don't see anywhere in your code where you actually say `new Card()` and add it to the list – OneCricketeer Feb 06 '16 at 20:16

2 Answers2

1

As per your logs : characters.get(0) is giving null and on it you are trying to call getCharacter() hence null pointer exception.

Check where your size of characters is getting 0 or by mistake you are assigning it to a new object.

best way is to apply check for if(characters.size() > 0) then only you get from characters.

You haven't initialized the variables initializeVariables(); is never called.

0

From my other answer, from which you took my code. The initDeck method actually reads like this

public void initDeck() {
    if (characters == null)
        characters = new ArrayList<String>();

        // addCharacter...

That will at least avoid a null pointer on the list...


You need to add more code to your question, but the problem starts in this block

addCharacter(demoniac, demoniacAmount, characters);
addCharacter(guard, guardAmount, characters);
addCharacter(medium, mediumAmount, characters);
addCharacter(mythomaniac, mythomaniacAmount, characters);
addCharacter(owl, owlAmount, characters);
addCharacter(werehamster, werehamsterAmount, characters);
addCharacter(getVillagerBundle(), villagerAmount, characters);
addCharacter(masonOne, 1, characters);
addCharacter(masonTwo, 1, characters);

which (roughly) calls this code

public void addCharacter(Card card, int amount, List<Card> cards) {
    for (int i = 0; i < amount; i++) {
        cards.add(card);
    }
}

The issue is that somewhere ANY of these variables are null and they are being added to the list as such

  • demoniac
  • guard
  • medium
  • mythomaniac
  • owl
  • werehamster
  • getVillagerBundle()
  • masonOne
  • masonTwo

You could either fix that by assigning all those variables to a new Card(), or avoid the problem like so

public void addCharacter(Card card, int amount, List<Card> cards) {
    for (int i = 0; i < amount; i++) {
        if (card != null) {
            cards.add(card);
        } else {
            Log.e("addCharacter", "Hey! Are you sure you meant to add a null card?");
        }
    }
}

Now what you have shown more of the code, the error starts here

if (demoniacAmount != 0) {
    demoniac = new Demoniac(nameList.get(listIndex));
    listIndex++;
} else if (guardAmount != 0) {
    guard = new Guard(nameList.get(listIndex));
    listIndex++;
}

What if demoniacAmount and guardAmount are both not zero, hmm? Only that first if condition will be entered. And guard will end up being null because it was never initialized. It makes no sense to do an else-if for completely different variables!

Properly perform your if-checking like so for all those conditions. (And I will leave the messy code as much as it bothers me)

if (demoniacAmount != 0) {
    demoniac = new Demoniac(nameList.get(listIndex));
    listIndex++;
} 

if (guardAmount != 0) {
    guard = new Guard(nameList.get(listIndex));
    listIndex++;
}
Community
  • 1
  • 1
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • I did found the issue with the starting code, so I tried to change it (uselessly) **but** maybe thanks to this answer I've understood what the problem is: I'm asking for a Card as parameter, in addCHaracter(), but I'm passing all Classes which extend the Card class, but they're not the Card class itself. May that be the problem? – FET Feb 06 '16 at 20:43
  • If they extend Card, that is totally fine. The error is very clear that you've added a null Card – OneCricketeer Feb 06 '16 at 20:49
  • I can't understand where, did you see the updated question by the way? – FET Feb 06 '16 at 20:53
  • I see what you did wrong. Hold on... – OneCricketeer Feb 06 '16 at 20:54
  • Also, is `nameList.get(listIndex)` just returning like "Guard" or "Owl", for example? – OneCricketeer Feb 06 '16 at 21:00
  • As I want the user to be able to enter the players' names, that list holds the names previously entered thanks to an EditText, so you'll get something like "Max","Leonard","Kelly" and so on til the number of the players is reached – FET Feb 06 '16 at 21:03
  • Indeed at the end I want to display the character's name and the player's name – FET Feb 06 '16 at 21:03
  • I wouldn't store the Player's name with the Card object. I would make a Player object that holds a list of Cards. Then you have `getPlayer().getName()` and `getPlayer().getCards()` and "for-each card in getPlayer().getCards(), do `card.getCharacter()`". Make sense? – OneCricketeer Feb 06 '16 at 21:06
  • Alright, I just need to get the player's name and its linked charachetr's name together at once and then display them, if you have a way, I may just learn from it :) – FET Feb 06 '16 at 21:15
  • Make a Player POJO with a string field for a name, pass that string in the constructor, have another field for the list of cards. It is really simple, but you could ask another question on here about how to model that idea. – OneCricketeer Feb 06 '16 at 21:17
  • Shall I edit this question into that one? – FET Feb 06 '16 at 21:18
  • 'cause look all I need is: get a list of names, a list of characters, shuffle one of 'em and then assign 'em in couples before displaying 'em all – FET Feb 06 '16 at 21:19
  • If that's the smartest way to do it (inside my roughly written code, not yours, yours is so well cleaned :P ) I'm with you – FET Feb 06 '16 at 21:20
  • You can keep doing it the way you are, but don't edit your question because my answer already addresses your issue. Just in larger apps, it makes sense to separate out variables and stuff – OneCricketeer Feb 06 '16 at 21:20
  • So how should I achieve my goal? Like what should I edit in my code? – FET Feb 06 '16 at 21:32
  • If you accept this answer and post a new question about how to refactor your code, I would be willing to answer it. – OneCricketeer Feb 06 '16 at 21:36
  • How should I name the other question? Or maybe shall we have a chat? – FET Feb 06 '16 at 21:55
  • "Best way to model a card game?" You also don't need all the code you've shown, just the object classes and an example of how you add the cards – OneCricketeer Feb 06 '16 at 21:57
  • What you really mean as object classes? Where I create 'em or what? – FET Feb 06 '16 at 22:08
  • You have made something that says `class Card { Card(String name) { } }`. Make another one that says `class Player { }` – OneCricketeer Feb 06 '16 at 22:09
  • Here is a tutorial on classes. A class is an extension of a Java object. The terms are used interchageably. http://www.tutorialspoint.com/java/java_object_classes.htm – OneCricketeer Feb 06 '16 at 22:11
  • I meant on the other question, what part of code should I add as object classes – FET Feb 06 '16 at 22:13
  • Do you have a Card.java file? Add that. If it is an inner class of your activity, just copy the `class Card { ... }` code like I just said – OneCricketeer Feb 06 '16 at 22:14
  • Alright, try this one: http://stackoverflow.com/questions/35247244/best-way-to-model-a-card-game – FET Feb 06 '16 at 22:25