Search code examples
javaandroidobjectarraylistparcelable

Issue Implementing Parcelable and retriving custom object


I have been trying to implement Parcelable into my custom object in order to send and retrieve it between activities. However, the app crashes when setting the object's values but I do not understand why. The console outputs the following:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.musicalstructureapp, PID: 10537
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.musicalstructureapp/com.example.musicalstructureapp.MusicPlayerActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.example.musicalstructureapp.Songs.getArtist()' on a null object reference
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3792)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3968)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:246)
    at android.app.ActivityThread.main(ActivityThread.java:8506)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.example.musicalstructureapp.Songs.getArtist()' on a null object reference
    at com.example.musicalstructureapp.MusicPlayerActivity.onCreate(MusicPlayerActivity.java:21)
    at android.app.Activity.performCreate(Activity.java:8198)
    at android.app.Activity.performCreate(Activity.java:8182)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3765)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3968) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:246) 
    at android.app.ActivityThread.main(ActivityThread.java:8506) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130) 

What does this output mean?

Attempt to invoke virtual method 'java.lang.String com.example.musicalstructureapp.Songs.getArtist()' on a null object reference

I've implemented Parcelable like this:

package com.example.musicalstructureapp;
import android.os.Parcel;
import android.os.Parcelable;

public class Songs implements Parcelable {

/**
 * Artist's name.
 */
private String mArtist;

/**
 * Album name.
 */
private String mAlbum;

/**
 * Track name.
 */
private String mTrack;

/**
 * Track name.
 */
private int mCover;

/**
 * Create a new Song object.
 *
 * @param artist is the artist's name.
 * @param album  is the name of the album.
 * @param track  is the name of the track.
 */
public Songs(String artist, String album, String track, int cover) {
    mArtist = artist;
    mAlbum = album;
    mTrack = track;
    mCover = cover;
}

/**
 * Get the artist's name.
 */
public String getArtist() {
    return mArtist;
}

/**
 * Get the album name.
 */
public String getAlbum() {
    return mAlbum;
}

/**
 * Get the track name.
 */
public String getTrack() {
    return mTrack;
}

/**
 * Get the cover of the album.
 */
public int getCover() {
    return mCover;
}

@Override
public int describeContents() {
    return 0;
}

/**
 * Write object's data to the passed-in Parcel.
 */
@Override
public void writeToParcel(Parcel parcel, int i) {
    parcel.writeString(mArtist);
    parcel.writeString(mAlbum);
    parcel.writeString(mTrack);
    parcel.writeInt(mCover);
}

/**
 * This is used to regenerate the object.
 */
public static final Parcelable.Creator<Songs> CREATOR = new Parcelable.Creator<Songs>() {
    public Songs createFromParcel(Parcel in) {
        return new Songs(in);
    }

    public Songs[] newArray(int size) {
        return new Songs[size];
    }
};

private Songs(Parcel in) {
    mArtist = in.readString();
    mAlbum = in.readString();
    mTrack = in.readString();
    mCover = in.readInt();
}
}

My TracksActivity that includes a list of objects and uses an onItemClickListener to open a new activity and pass the object:

package com.example.musicalstructureapp;

import android.content.Intent;
import android.os.Bundle;
import android.widget.ListView;

import androidx.appcompat.app.AppCompatActivity;

import java.util.ArrayList;

public class TracksActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_tracks);

    // New list of songs
    ArrayList<Songs> songs = new ArrayList<>();
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_one), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_two), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_three), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_four), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_five), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_six), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_seven), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_eight), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_nine), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_ten), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_eleven), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_twelve), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_thirteen), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_fourteen), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_fifteen), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_sixteen), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_seventeen), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_eighteen), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_nineteen), R.drawable.cover_sample));
    songs.add(new Songs(getString(R.string.NF), getString(R.string.the_search), getString(R.string.track_twenty), R.drawable.cover_sample));

    // Create an SongAdapter, whose data source is a list of Songs. The adapter knows how to create list items for each item in the list.
    SongAdapter adapter = new SongAdapter(this, songs);

    // Find the ListView object in the view hierarchy of the Activity.
    // There should be a ListView with the view ID called activity_tracks_list_view, which is declared in the
    // activity_tracks.xml layout file.
    ListView listView = findViewById(R.id.activity_tracks_list_view);

    // Make the ListView use the SongAdapter we created above, so that the
    // ListView will display list items for each Songs in the list.
    listView.setAdapter(adapter);

    // Open new Activity on click. Passes clicked object to MusicPlayerActivity.
    listView.setOnItemClickListener((parent, view, position, id) -> {
        Intent openPlayer = new Intent(TracksActivity.this, MusicPlayerActivity.class);
        openPlayer.putExtra("song", position);
        startActivity(openPlayer);
    });

}
}

The activity I want to retrieve the passed object:

package com.example.musicalstructureapp;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;

public class MusicPlayerActivity extends TracksActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_music_player);

    Intent passedIntent = getIntent();
    Songs song = (Songs) passedIntent.getParcelableExtra("song");

    TextView currentArtist = findViewById(R.id.currentArtistName_text_view);
    TextView currentTrack = findViewById(R.id.currentTrackName_text_view);
    TextView currentAlbum = findViewById(R.id.currentAlbumName_text_view);
    ImageView currentCover = findViewById(R.id.currentAlbumCover_image_view);

    currentArtist.setText(song.getArtist());
    currentTrack.setText(song.getTrack());
    currentAlbum.setText(song.getAlbum());
    currentCover.setImageResource(song.getCover());

}
}

Solution

  • Change openPlayer.putExtra("song", position); to openPlayer.putExtra("song", songs.get(position));

    As right now you are sending int (position is int) value to your MusicPlayerActivity and casting it to Songs. hence at currentArtist.setText(song.getArtist()); you are getting nullpointerexception.