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());
}
}
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
.