Bob
Bob

Reputation: 61

Android Room Database Issues

I'm trying to complete this small in class exercise where we have to save data using Room Database and then display that information in a ListView.

This app is about a player. The player has 4 fields (Id, Name, Position, Number of Goals scored).

Once the user clicks the "SAVE" button, all the fields previously selected will be cleared and their will be a quick toast message displaying the ID# of the player.

In order to view all the saved data the user must click the "VIEW ALL" button which will take them to the second activity and display the Name of the Player, Position, Number of Goals scored in the next activity.

I'm not too familiar with room so whenever I press the "Save"Save button my app crashes. Any help would be greatly appreciated, Thanks!

MainActivity.Java

public class MainActivity extends AppCompatActivity {

private EditText playerEdt, goalsEdt;
private int id = 0;

private RadioGroup groupRad;
private RadioButton radioButton;

private MyDatabase myDb;

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

    playerEdt = findViewById(R.id.edtPlayer);
    goalsEdt = findViewById(R.id.edtGoals);

    myDb = MyDatabase.getInstance(MainActivity.this);


}

public void saveData(View view) {
    id++;
    String name = playerEdt.getText().toString();

    groupRad = findViewById(R.id.radGroup);

    int selectedId = groupRad.getCheckedRadioButtonId();

    radioButton  = findViewById(selectedId);

    String position = radioButton.getText().toString();

    String goalsString = goalsEdt.getText().toString();

    int goals = Integer.valueOf(goalsString);

    Player player = new Player(id, name, position, goals);

    myDb.playerDao().insert(player);

    playerEdt.setText("");
    goalsEdt.setText("");
    groupRad.clearCheck();



}

public void viewData(View view) {
    Intent intent = new Intent(MainActivity.this, SecondActivity.class);

    startActivity(intent);
}
}

SecondActivity.Java

public class SecondActivity extends AppCompatActivity {

ListView listView;
MyDatabase database;

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

    listView = findViewById(R.id.listView);

    database = MyDatabase.getInstance(SecondActivity.this);

    List<Player> players = database.playerDao().getAll();

    ArrayAdapter adapter = new ArrayAdapter(SecondActivity.this, android.R.layout.simple_list_item_1, players);

    listView.setAdapter(adapter);
}
}

Player.Java

@Entity
public class Player {
@PrimaryKey
private int id;

@ColumnInfo(name = "player_name")
private String name;

@ColumnInfo(name = "player_position")
private String position;

@ColumnInfo(name = "player_goals")
private int goals;

public Player(int id, String name, String position, int goals) {
    this.id = id;
    this.name = name;
    this.position = position;
    this.goals = goals;
}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getPosition() {
    return position;
}

public void setPosition(String position) {
    this.position = position;
}

public int getGoals() {
    return goals;
}

public void setGoals(int goals) {
    this.goals = goals;
}
}

PlayerDao.java

@Dao
public abstract class  PlayerDao {
@Insert
public abstract void insert (Player player);

@Delete
public abstract void delete (Player player);

@Update
public abstract void update (Player player);


@Query("select * from Player")
public abstract List<Player> getAll();


}

MyDatabase.Java

@Database(entities = Player.class, version = 1)
public abstract class MyDatabase extends RoomDatabase {

public abstract PlayerDao playerDao();

private static MyDatabase instance;

public  static MyDatabase getInstance(Context context){

    if( instance == null){
        instance = Room.databaseBuilder(context, MyDatabase.class, "PlayerDb")
                .allowMainThreadQueries()
                .build();

    }

    return instance;
}
}

activity_main.xml: https://www.codepile.net/pile/d5rq8mx2

activity_second.xml: https://www.codepile.net/pile/2vbYzXq3

Upvotes: 3

Views: 806

Answers (2)

MikeT
MikeT

Reputation: 56928

It would appear that you have a number of issues:-

You need to have getters for all the members of the Player class.

These were added (and setters) :-

public int getGoals() {
    return goals;
}

public void setGoals(int goals) {
    this.goals = goals;
}

public String getPosition() {
    return position;
}

public void setPosition(String position) {
    this.position = position;
}

The core issue is that the attemps to find the views in the saveData is returning nulls and hence you are getting a null pointer exception (NPE) because the views don't exist within the SAVE button.

The solution is to find the views (i.e use findViewById in the onCreate method).

There is also a lack of data verification which will causes issue. The following version of MainActivity.java handles the issues :-

public class MainActivity extends AppCompatActivity {

    private EditText playerEdt, goalsEdt;
    private int id = 0;

    private RadioGroup groupRad;
    private RadioButton radioButton;
    private MyDatabase myDb;

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

        playerEdt = findViewById(R.id.edtPlayer);
        goalsEdt = findViewById(R.id.edtGoals);
        groupRad = findViewById(R.id.radGroup);
        myDb = MyDatabase.getInstance(MainActivity.this);
    }

    public void saveData(View view) {
        id++;
        String name = playerEdt.getText().toString();
        if (name.length() < 1) {
            Toast.makeText(view.getContext(),"Player Name is blank. Try again.",Toast.LENGTH_SHORT).show();
            playerEdt.requestFocus();
        }
        radioButton = findViewById(groupRad.getCheckedRadioButtonId());
        if (radioButton == null) {
            Toast.makeText(view.getContext(),"You must select Goalie Defence or Forward. Try again",Toast.LENGTH_SHORT).show();
            return;
        }
        String position = radioButton.getText().toString();

        String goalsString = goalsEdt.getText().toString();
        int goals = 0;
        try {
            goals = Integer.valueOf(goalsString);
        } catch (Exception e) {
            Toast.makeText(view.getContext(),"You must give the number of Goals. try again.",Toast.LENGTH_SHORT).show();
            goalsEdt.requestFocus();
        }

        Player player = new Player(id, name, position, goals);
        if (myDb.playerDao().insert(player) < 1) {
            Toast.makeText(view.getContext(),"Player not Added (duplicate)",Toast.LENGTH_SHORT).show();
            return;
        }
        playerEdt.setText("");
        goalsEdt.setText("");
        groupRad.clearCheck();
        Toast.makeText(view.getContext(),"Player Added. Name is " + name + " Position is " + position + " Goals = " + goals,Toast.LENGTH_SHORT).show();
    }

    public void viewData(View view) {
        Intent intent = new Intent(MainActivity.this, SecondActivity.class);
        startActivity(intent);
    }
}

Additionally PlayerDao.java has been changed to not fail if the player name is duplicated and to also return useful values when inserting, deleting or updating. it is :-

@Dao
public abstract class  PlayerDao {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    public abstract long insert (Player player);

    @Delete
    public abstract int delete (Player player);

    @Update
    public abstract int update (Player player);


    @Query("select * from Player")
    public abstract List<Player> getAll();

}

Upvotes: 1

Hamed
Hamed

Reputation: 739

First of all, it would be better if you use autoGenerate = true in your Player.java class for id:

@Entity
public class Player {
@PrimaryKey(autoGenerate = true)
private int id;  

By doing this you don't have to give your players ids and Room does the job for you.

And for the app crash when saving, you must check the log and see what is causing the app to crash. Update your question with that so users can help you.

Upvotes: 0

Related Questions