So this is actually an update to my previous (now deleted) subpar post about the custom adapter-for some reason it thinks I'm generating null object references for it and won't work as a result.
These are the components of my project:
DBHelper-supplementary section:
package com.myapplicationdev.android.songdbmanager;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import androidx.annotation.Nullable;
import java.util.ArrayList;
public class DBHelper extends SQLiteOpenHelper { // Start version with 1
// increment by 1 whenever db schema changes.
private static final int DATABASE_VER = 1;
private static final String TABLE_SONG = "song";
private static final String COLUMN_ID = "id";
private static final String COLUMN_TITLE = "title";
private static final String COLUMN_SINGERS = "singers";
private static final String COLUMN_YEAR="year";
private static final String COLUMN_STARS="stars";
// Filename of the database
private static final String DATABASE_NAME = "songs.db";
public DBHelper(@Nullable Context context) {
super(context, DATABASE_NAME, null, DATABASE_VER);
}
@Override
public void onCreate(SQLiteDatabase db) {
String dropTableSql = "DROP TABLE IF EXISTS " + TABLE_SONG;
db.execSQL(dropTableSql);
String createTableSql = "CREATE TABLE " + TABLE_SONG + "("
+ COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ COLUMN_TITLE + " TEXT,"
+ COLUMN_SINGERS+ " TEXT ,"
+ COLUMN_YEAR + " INTEGER ,"
+ COLUMN_STARS+ " INTEGER )";
db.execSQL(createTableSql);
Log.i("info" ,"created tables");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_SONG);
// Create table(s) again
onCreate(db);
}
public void insertSong(String title, String singers, int year, int stars){
// Get an instance of the database for writing
SQLiteDatabase db = this.getWritableDatabase();
// We use ContentValues object to store the values for
// the db operation
ContentValues values = new ContentValues();
// Store the column name as key and the description as value
values.put(COLUMN_TITLE, title);
values.put(COLUMN_SINGERS, singers);
values.put(COLUMN_YEAR, year);
values.put(COLUMN_STARS, stars);
// Store the column name as key and the date as value
// Insert the row into the TABLE_TASK
db.insert(TABLE_SONG, null, values);
// Close the database connection
db.close();
}
public ArrayList<song> getAllSongs() {
ArrayList<song> songlist = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
String[] columns= {COLUMN_ID, COLUMN_TITLE, COLUMN_SINGERS,COLUMN_YEAR,COLUMN_STARS};
Cursor cursor = db.query(TABLE_SONG, columns, null, null,
null, null, null, null);
if (cursor.moveToFirst()) {
do {
int id = cursor.getInt(0);
String title=cursor.getString(1);
String singers = cursor.getString(2);
int year=cursor.getInt(3);
int stars=cursor.getInt(4);
song Song = new song(id,title,singers,year,stars);
songlist.add(Song);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return songlist;
}
public ArrayList<song> getBestSongs() {
ArrayList<song> bestsonglist = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
String[] columns= {COLUMN_ID, COLUMN_TITLE, COLUMN_SINGERS,COLUMN_YEAR,COLUMN_STARS};
String condition = COLUMN_STARS + "= ?";
String[] args = {"5"};
Cursor cursor = db.query(TABLE_SONG, columns, condition, args,
null, null, null, null);
if (cursor.moveToFirst()) {
do {
int id = cursor.getInt(0);
String title=cursor.getString(1);
String singers = cursor.getString(2);
int year=cursor.getInt(3);
int stars=cursor.getInt(4);
song Song = new song(id,title,singers,year,stars);
bestsonglist.add(Song);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return bestsonglist;
}
public int updateSong(song Song) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_TITLE, Song.getTitle());
values.put(COLUMN_SINGERS, Song.getSingers());
values.put(COLUMN_YEAR, Song.getYear());
values.put(COLUMN_STARS, Song.getStars());
String whereClause = COLUMN_ID + "=?";
String[] whereArgs = {String.valueOf(Song.getId())};
int result=db.update(TABLE_SONG, values, whereClause, whereArgs);
if (result < 1) {
Log.d("DBHelper", "Update failed");
db.close();
return result;
}
return result;
}
public void deleteSong(int songId) {
SQLiteDatabase db = this.getWritableDatabase();
String whereClause = COLUMN_ID + "=?";
String[] whereArgs = {String.valueOf(songId)};
db.delete(TABLE_SONG, whereClause, whereArgs);
db.close();
}}
MainActivity-where the initial processing is done:
package com.myapplicationdev.android.songdbmanager;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.ToggleButton;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
Button btnInsert, btnGetSongs;
TextView tvResults;
EditText YearInput;
EditText SongInput;
EditText SingerInput;
RadioGroup RadioGroupRating;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnInsert = findViewById(R.id.btnInsert);
btnGetSongs = findViewById(R.id.btnGetTasks);
//List View->
YearInput=findViewById(R.id.insertYear);
SongInput=findViewById(R.id.insertTitle);
SingerInput=findViewById(R.id.insertSingers);
RadioGroupRating=findViewById(R.id.radio_group);
btnInsert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DBHelper db = new DBHelper(MainActivity.this);
String title=SongInput.getText().toString();
String singers=SingerInput.getText().toString();
int year=Integer.parseInt(YearInput.getText().toString());
int selectedRatingId=RadioGroupRating.getCheckedRadioButtonId();
RadioButton selectedRatingButton=findViewById(selectedRatingId);
int rating=Integer.parseInt(selectedRatingButton.getText().toString());
db.insertSong(title,singers,year,rating);
SongInput.setText("");
SingerInput.setText("");
YearInput.setText("");
RadioGroupRating.clearCheck();
}
});
btnGetSongs.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
// Create the DBHelper object, passing in the
// activity's Context
// Insert a task
Intent intent = new Intent(MainActivity.this, EditActivity.class);
//Label the actual editactivity EditActivity2
startActivity(intent);
}
});
}
}
EditActivity:Where the list is displayed:
{
ListView lv;
ArrayList<song> songsList;
//ArrayAdapter<song> adapter;
CustomAdapter adapter;
Button fivestarsongs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit);
lv = findViewById(R.id.list_view);
fivestarsongs = findViewById(R.id.btnShow5starsongs);
DBHelper db = new DBHelper(EditActivity.this);
songsList = db.getAllSongs();
//ArrayAdapter<song> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, songs);
if (songsList != null && !songsList.isEmpty()) {
adapter = new CustomAdapter(this, android.R.layout.simple_list_item_1, songsList); // Remove the CustomAdapter declaration here
lv.setAdapter(adapter);
}
fivestarsongs.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ArrayList<song> BestSongs = db.getBestSongs();
adapter.clear();
adapter.addAll(BestSongs);
adapter.notifyDataSetChanged();
}
});
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int
position, long id) {
song ClickedSong = songsList.get(position);
Intent i = new Intent(EditActivity.this,
MainActivity2.class);
i.putExtra("song", ClickedSong);
startActivity(i);
}
});
}
}
MainActivity2-supposed to handle delete/update:
package com.myapplicationdev.android.songdbmanager;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
public class MainActivity2 extends AppCompatActivity {
Button btnUpdate,btnCancel,btnDelete;
EditText YearInput;
EditText SongInput;
EditText SingerInput;
RadioGroup RadioGroupRating;
song selectedSong;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
DBHelper db = new DBHelper(MainActivity2.this);
Intent intent = getIntent();
song clickedSong = (song) intent.getSerializableExtra("song");
btnUpdate=findViewById(R.id.btnupdate);
btnCancel=findViewById(R.id.btnCancel);
btnDelete=findViewById(R.id.btndelete);
YearInput=findViewById(R.id.insertYear);
SongInput=findViewById(R.id.insertTitle);
SingerInput=findViewById(R.id.insertSingers);
RadioGroupRating=findViewById(R.id.radio_group);
selectedSong = clickedSong;
YearInput.setText(String.valueOf(clickedSong.getYear()));
SongInput.setText(clickedSong.getTitle());
SingerInput.setText(clickedSong.getSingers());
setStarsSelection(selectedSong.getStars());
btnUpdate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectedSong.setTitle(SongInput.getText().toString());
selectedSong.setSingers(SingerInput.getText().toString());
selectedSong.setYear(Integer.parseInt(YearInput.getText().toString()));
selectedSong.setStars(getSelectedStars());
db.updateSong(selectedSong);
db.close();
finish();
}
});
btnDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
db.deleteSong(selectedSong.getId());
db.close();
finish();
}
});
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity2.this, MainActivity.class);
startActivity(intent);
finish();
}
});
}
private int getSelectedStars() {
int selectedId = RadioGroupRating.getCheckedRadioButtonId();
RadioButton rbSelected = findViewById(selectedId);
return Integer.parseInt(rbSelected.getText().toString());
}
private void setStarsSelection(int stars) {
int radioButtonId = 0;
switch (stars) {
case 1:
radioButtonId = R.id.radio_1;
break;
case 2:
radioButtonId = R.id.radio_2;
break;
case 3:
radioButtonId = R.id.radio_3;
break;
case 4:
radioButtonId = R.id.radio_4;
break;
case 5:
radioButtonId = R.id.radio_5;
break;
}
RadioGroupRating.check(radioButtonId);
}
}
Song-class involved in all this:
package com.myapplicationdev.android.songdbmanager;
import androidx.annotation.NonNull;
import java.io.Serializable;
public class song implements Serializable {
private int id;
private String title;
private String singers;
private int year;
private int stars;
public void setSingers(String singers) {
this.singers = singers;
}
public void setStars(int stars) {
this.stars = stars;
}
public void setTitle(String title) {
this.title = title;
}
public void setYear(int year) {
this.year = year;
}
public song (
String title,
String singers,
int year,
int stars
){
this.title=title;
this.singers=singers;
this.year=year;
this.stars=stars;
}
public song (
int id,
String title,
String singers,
int year,
int stars
){
this.id=id;
this.title=title;
this.singers=singers;
this.year=year;
this.stars=stars;
}
public String getTitle() {
return title;
}
public int getId(){
return id;
}
public int getYear() {
return year;
}
public int getStars() {
return stars;
}
public String getSingers() {
return singers;
}
@NonNull
@Override
public String toString() {
return
"title='" + title + '\'' +
", singers='" + singers + '\'' +
", year=" + year +
", stars=" + stars
;
}
}
CustomAdapter:
public class CustomAdapter extends ArrayAdapter {
private Context context;
private int layoutResourceId;
private ArrayList<song> songList;
public CustomAdapter(Context context, int resource, ArrayList<song> objects) {
super(context, resource, objects);
this.context = context;
this.layoutResourceId = resource;
this.songList = objects;
}
@NonNull
@Override
public View getView(int position, View rowView, ViewGroup parent) {
if (rowView == null) {
LayoutInflater inflater = LayoutInflater.from(context);
rowView = inflater.inflate(layoutResourceId, parent, false);
}
song currentSong = songList.get(position);
TextView yearInput = rowView.findViewById(R.id.insertYear);
TextView singerInput = rowView.findViewById(R.id.insertSingers);
TextView titleInput = rowView.findViewById(R.id.insertTitle);
RadioGroup radioGroupRating =rowView.findViewById(R.id.radio_group);
titleInput.setText(currentSong.getTitle());
singerInput.setText(currentSong.getSingers());
yearInput.setText(String.valueOf(currentSong.getYear()));
int selectedValue = currentSong.getStars();
int radioButtonId = 0;
switch (selectedValue) {
case 1:
radioButtonId = R.id.radio_1;
break;
case 2:
radioButtonId = R.id.radio_2;
break;
case 3:
radioButtonId = R.id.radio_3;
break;
case 4:
radioButtonId = R.id.radio_4;
break;
case 5:
radioButtonId = R.id.radio_5;
break;
}
radioGroupRating.check(radioButtonId);
return rowView;
}}
And here's the error message associated with these (I'd share the full stack but the text limit likely won't allow me):
It refers to the line where I set the year in the adapter, which is otherwise working as intended.
FATAL EXCEPTION: main
Process: com.myapplicationdev.android.songdbmanager, PID: 27730
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.myapplicationdev.android.songdbmanager.CustomAdapter.getView(CustomAdapter.java:44)
at android.widget.AbsListView.obtainView(AbsListView.java:2387)
at android.widget.ListView.makeAndAddView(ListView.java:2067)
at android.widget.ListView.fillDown(ListView.java:793)
at android.widget.ListView.fillFromTop(ListView.java:855)
at android.widget.ListView.layoutChildren(ListView.java:1838)
at android.widget.AbsListView.onLayout(AbsListView.java:2184)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1818)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1584)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:784)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3470)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2938)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1952)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8171)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
at android.view.Choreographer.doCallbacks(Choreographer.java:796)
at android.view.Choreographer.doFrame(Choreographer.java:731)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
I tried editing the code to check for nulls and even making an object just to check if that's causing the glitch.
Neither of them had much of an effect.