-1

First post on this site, so forgive me my sins. I am attempting to create a custom ListView layout that is populated by fields from my SQLite Database Adapter class. Below is the method I tried to use for this, and it is called in the onCreate method of its class, as well as the onClick method of a button to save to the Database:

//Method to re-populate custom list view songlist_layout when a new entry is added
    private void populateSongList() {

        //Cursor to navigate through records of the database
        Cursor cursor = myDb.getAllRows();

        //Need two arrays to work with the Cursor. First is from field names
        String [] fromFieldNames = new String[] {DBAdapter.KEY_ROWID, 
                                                 DBAdapter.KEY_SONGTITLE, 
                                                 DBAdapter.KEY_SONGDURATION};

        //Second is int array
        int [] toViewIDs = new int [] {R.id.textViewSongNumber, R.id.textViewSongName, 
                                       R.id.textViewSongDuration};

        //Cursor Adapter Object
        SimpleCursorAdapter myCursorAdapter;
        myCursorAdapter = new SimpleCursorAdapter(getBaseContext(), 
                      R.layout.songlist_layout, cursor, fromFieldNames, toViewIDs,0);

        //Need to grab ListView from activity_add_song to set the adapter to it
        ListView songList = (ListView)findViewById(R.id.songsListView);
        songList.setAdapter(myCursorAdapter);
    }
 //Method to handle the click event of the Save button, adding the data into the database
    public void onClickSaveSong (View v) {

        //Song Title and duration are essential fields, so we want to check if they 
        //     have text before saving to the database
        if(!TextUtils.isEmpty(etSongTitle.getText().toString()) && 
           !TextUtils.isEmpty(etSongDuration.getText().toString())) {

            myDb.insertRow(etSongTitle.getText().toString(), 
                           etSongKey.getText().toString(), 
                           etSongTuning.getText().toString(),
                           etSongDuration.getText().toString());

            //Pop-up to inform user the Data has been saved
            Toast.makeText(getBaseContext(), "Song Added!", Toast.LENGTH_LONG).show();
        }//if

        //Otherwise a pop-up to tell the user to enter the essential info
        else {Toast.makeText(getBaseContext(), "Enter Title and Duration", 
              Toast.LENGTH_LONG).show();}

        //Call to repopulate songs ListView
        populateSongList();

    }//onClickSaveSong()

The custom XML Layout for the ListView contains three TextViews to hold the songNumber, the songName and the songDuration:

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Text"
        android:id="@+id/textViewSongNumber"
        android:paddingRight="10dp"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Text"
        android:id="@+id/textViewSongName"
        android:paddingRight="60dp"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Text"
        android:id="@+id/textViewSongDuration"
        android:paddingRight="70dp"/>

I have read elsewhere that the problem could be because the ListView is grabbing from the wrong ListView ID ListView songList = (ListView)findViewById(R.id.songsListView); However comparing it to the XML Layout for the ListView, I don't see how this would be the case:

<ListView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/songsListView"
        android:layout_below="@+id/imageView"
        android:layout_centerHorizontal="true"
        android:layout_above="@+id/addSongButton" />

Finally, the logcat:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.blob.gigstrofinal/com.blob.gigstrofinal.AddSong}: java.lang.NullPointerException
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2184)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
            at android.app.ActivityThread.access$800(ActivityThread.java:135)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5001)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.NullPointerException
            at com.blob.gigstrofinal.AddSong.populateSongList(AddSong.java:121)
            at com.blob.gigstrofinal.AddSong.onCreate(AddSong.java:45)

I cannot figure this out. I haven't been using Android for long, and a lot of this is over my head, so I would appreciate any help at all on this matter. The App is for a University Project, and it is due next week!

EDIT: I forgot to specify, the Null Pointer Exception is pointing to line 121 of AddSong.java which is: songList.setAdapter(myCursorAdapter);

I am calling the populateSongList()method from the onCreate method in the AddSong class:

public class AddSong extends Activity {

    //Declare Database Adapter
    DBAdapter myDb;

    //Declare EditText objects to be used for each field in the SQLite Database
    EditText etSongTitle;
    EditText etSongKey;
    EditText etSongTuning;
    EditText etSongDuration;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_song);


        //Initialise EditText objects by assigning them to the corresponding ID
        etSongTitle = (EditText)findViewById(R.id.editSongTitle);
        etSongKey = (EditText)findViewById(R.id.editSongKey);
        etSongTuning = (EditText)findViewById(R.id.editSongTuning);
        etSongDuration = (EditText)findViewById(R.id.editSongDuration);

        //Call method to open Database
        openDB();
        //Call to populate songs ListView
        populateSongList();
    }

and again for the onClickSaveSong method of AddSong.java (see second code snippet of original post.

EDIT2: The full contents of activity_add_song.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.blob.gigstrofinal.AddSong"
    android:background="@color/colorPrimary"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tvSongTitle"
        android:id="@+id/songTitle"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true"
        android:textStyle="bold"
        android:textSize="13sp"
        android:textColor="@color/colorPrimary2" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/songTitle"
        android:id="@+id/editSongTitle"
        android:layout_alignParentStart="true"
        android:editable="true"
        android:inputType="text"
        android:background="#e6e6e6"
        android:textColor="@color/colorPrimary3"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tvKey"
        android:id="@+id/songKey"
        android:textStyle="bold"
        android:textSize="13sp"
        android:textColor="@color/colorPrimary2"
        android:layout_marginTop="15dp"
        android:layout_below="@+id/editSongTitle"
        android:layout_alignParentStart="true" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editSongKey"
        android:layout_below="@+id/songKey"
        android:layout_alignParentStart="true"
        android:layout_alignEnd="@+id/editSongTitle"
        android:background="#e6e6e6"
        android:inputType="text"
        android:textColor="@color/colorPrimary3" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tvTuning"
        android:id="@+id/songTuning"
        android:textStyle="bold"
        android:textSize="13sp"
        android:textColor="@color/colorPrimary2"
        android:layout_marginTop="13dp"
        android:layout_below="@+id/editSongKey"
        android:layout_alignParentStart="true" />


    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editSongTuning"
        android:layout_below="@+id/songTuning"
        android:layout_alignParentStart="true"
        android:layout_alignEnd="@+id/editSongKey"
        android:background="#e6e6e6"
        android:textColor="@color/colorPrimary3"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tvDuration"
        android:id="@+id/songDuration"
        android:textStyle="bold"
        android:textSize="13dp"
        android:textColor="@color/colorPrimary2"
        android:layout_marginTop="15dp"
        android:layout_below="@+id/editSongTuning"
        android:layout_alignParentStart="true" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editSongDuration"
        android:layout_below="@+id/songDuration"
        android:layout_alignParentStart="true"
        android:layout_alignEnd="@+id/editSongTuning"
        android:background="#e6e6e6"
        android:textColor="@color/colorPrimary3"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tvLyrics"
        android:id="@+id/songLyrics"
        android:textStyle="bold"
        android:textSize="13sp"
        android:textColor="@color/colorPrimary2"
        android:layout_below="@+id/editSongDuration"
        android:layout_alignParentStart="true"
        android:layout_marginTop="15sp"
        android:textIsSelectable="false" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="textMultiLine"
        android:ems="10"
        android:id="@+id/editSongLyrics"
        android:layout_below="@+id/songLyrics"
        android:layout_alignParentStart="true"
        android:layout_alignEnd="@+id/editSongDuration"
        android:background="#e6e6e6"
        android:layout_above="@+id/saveButton"
        android:layout_marginBottom="20dp"
        android:textColor="@color/colorPrimary3"/>

    <Button
        android:id="@+id/saveButton"
        android:text="@string/buttonSaveText"

        android:background="@color/colorPrimary"
        android:textColor="@color/colorPrimary2"
        android:textStyle="bold"
        android:textSize="11sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="19dp"
        android:layout_marginRight="22dp"
        android:onClick="onClickSaveSong"
        android:layout_alignParentBottom="true"
         />

    <Button
        android:id="@+id/backButton"
        android:text="@string/backButtonText"
        android:background="@color/colorPrimary"
        android:textColor="@color/colorPrimary2"
        android:textStyle="bold"
        android:textSize="11sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClickBack"
        android:layout_alignBottom="@+id/saveButton"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:layout_marginRight="19dp"
        />

</RelativeLayout>

It is perhaps worth mentioning that the ListView itself is not located in Activity_add_song, it is in another Activity activity_songs. Would that cause a null pointer exception?

4 Answers4

0

Make sure you call populateSongList() after setContentView().

And please be more specific about where the line 121 is.

Caused by: java.lang.NullPointerException at com.blob.gigstrofinal.AddSong.populateSongList(AddSong.java:121)

Eric Liu
  • 1,516
  • 13
  • 19
  • Sorry, I didn't even realise myself it was pointing to 121. `songList.setAdapter(myCursorAdapter);` is at line 121. – Savien Traliard Dec 01 '15 at 00:42
  • `protected void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_song); //Call method to open Database openDB(); //Call to populate songs ListView populateSongList(); }` `populateSongList();` is called after `setContentView()` – Savien Traliard Dec 01 '15 at 00:46
  • Which means the ListView songsListView is null. Make sure you are inflating the correct layout file and make the call after setContentView is called. – Eric Liu Dec 01 '15 at 00:46
  • When you say inflating, do you mean when I'm passing the layout in as a parameter to create a new SimpleCursorAdapter in the line: `myCursorAdapter = new SimpleCursorAdapter(getBaseContext(), R.layout.songs_layout, cursor, fromFieldNames, toViewIDs,0);` Or do you meant something else entirely? I have checked, and that should be the correct layout file. It's the custom xml layout that I want to use to set to the ListView from my other Activity. – Savien Traliard Dec 01 '15 at 01:26
0

Since line 121 is this:

songList.setAdapter(myCursorAdapter);

and that is where you are getting null, then either songList or myCursorAdapter is null. myCursorAdapter is clearly not null, so you likely have the wrong name for your findViewById method in this line:

ListView songList = (ListView)findViewById(R.id.songsListView);

Check that the listview is actually called "songsListView" in your XML - it probably isn't.

Alex K
  • 8,269
  • 9
  • 39
  • 57
  • I have triple checked, and even created a new custom xml layout file with different IDs and changed the IDs in my method accordingly, but I still get the same null pointer error. Can you think of any other reason why this is happening? Thanks for your reply! – Savien Traliard Dec 01 '15 at 01:24
0

The problem is that the ListView is not in the layout xml that you're inflating in this Activity.

When you call this in onCreate():

setContentView(R.layout.activity_add_song);

You're inflating the activity_add_song.xml layout xml to the current Window.

Then when you call:

ListView songList = (ListView)findViewById(R.id.songsListView);

It's looking at the currently inflated layout for a ListView with ID songsListView. Since there is no songsListView in the currently inflated layout (activity_add_song.xml), it will be null.

Move all code dealing with songsListView to the Activity that inflates the layout with the ListView.

Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
  • Ah I understand! However, what I want to have happen is that when the user fills in the EditTexts in activity_add_song and clicks the save Button, the onClickSaveButton is called, which creates a new row in a database using my DBAdapter class and then re-populates the ListView by calling populateSongList() again. How would I accomplish this if I moved the method and all the other code relating to songsListView over? Hopefully I've articulated that clearly enough, and sorry for the terrible format! Thanks again for your comment – Savien Traliard Dec 01 '15 at 02:28
  • You can add data to the database from anywhere in your app. The code dealing with the ListView, however, needs to stay contained in the Activity that displays it. – Daniel Nugent Dec 01 '15 at 03:23
  • I moved all the code over and it worked! Thanks Daniel, I owe you a pint! One more question for you. Would it be possible to have a button in my custom XML layout `songlist_layout` for each record, that deletes that specific record from the database? – Savien Traliard Dec 01 '15 at 15:40
  • @savien yes you could do that, but a contextual action bar is the Android way to do it. Long press of a row brings up a contextual action bar with a delete icon. – Daniel Nugent Dec 01 '15 at 15:59
0

Your activity_add_song.xml should contain the ListView, which is missing in your code.

<ListView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/songsListView"
    android:layout_below="@+id/imageView"
    android:layout_centerHorizontal="true"
    android:layout_above="@+id/addSongButton" />

and R.layout.songlist_layout should contain the layout for each row

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="New Text"
    android:id="@+id/textViewSongNumber"
    android:paddingRight="10dp"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="New Text"
    android:id="@+id/textViewSongName"
    android:paddingRight="60dp"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="New Text"
    android:id="@+id/textViewSongDuration"
    android:paddingRight="70dp"/>
Eric Liu
  • 1,516
  • 13
  • 19