title: Android - Playing song when listview item is clicked
body: <p>I am trying to implement a music player application (given in tutsplus.com) I am getting this following exception :</p>
  
  <pre><code>06-19 12:28:06.457 14867-14867/com.example.adityakrishnakumar.mymusicplayer E/AndroidRuntime: FATAL EXCEPTION: main
  Process: com.example.adityakrishnakumar.mymusicplayer, PID: 14867
  java.lang.IllegalStateException: Could not execute method of the activity
      at android.view.View$1.onClick(View.java:3978)
      at android.view.View.performClick(View.java:4646)
      at android.view.View$PerformClick.run(View.java:19403)
      at android.os.Handler.handleCallback(Handler.java:733)
      at android.os.Handler.dispatchMessage(Handler.java:95)
      at android.os.Looper.loop(Looper.java:146)
      at android.app.ActivityThread.main(ActivityThread.java:5511)
      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:1283)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
      at dalvik.system.NativeStart.main(Native Method)
   Caused by: java.lang.reflect.InvocationTargetException
      at java.lang.reflect.Method.invokeNative(Native Method)
      at java.lang.reflect.Method.invoke(Method.java:515)
      at android.view.View$1.onClick(View.java:3973)
      at android.view.View.performClick(View.java:4646) 
      at android.view.View$PerformClick.run(View.java:19403) 
      at android.os.Handler.handleCallback(Handler.java:733) 
      at android.os.Handler.dispatchMessage(Handler.java:95) 
      at android.os.Looper.loop(Looper.java:146) 
      at android.app.ActivityThread.main(ActivityThread.java:5511) 
      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:1283) 
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099) 
      at dalvik.system.NativeStart.main(Native Method) 
   Caused by: java.lang.NullPointerException
      at com.example.adityakrishnakumar.mymusicplayer.MainActivity.songPicked(MainActivity.java:98)
      at java.lang.reflect.Method.invokeNative(Native Method) 
      at java.lang.reflect.Method.invoke(Method.java:515) 
      at android.view.View$1.onClick(View.java:3973) 
      at android.view.View.performClick(View.java:4646) 
      at android.view.View$PerformClick.run(View.java:19403) 
      at android.os.Handler.handleCallback(Handler.java:733) 
      at android.os.Handler.dispatchMessage(Handler.java:95) 
      at android.os.Looper.loop(Looper.java:146) 
      at android.app.ActivityThread.main(ActivityThread.java:5511) 
      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:1283) 
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099) 
      at dalvik.system.NativeStart.main(Native Method) 
  </code></pre>
  
  <p>The code for MainActivity is as follows :</p>
  
  <pre><code>    package com.example.adityakrishnakumar.mymusicplayer;
  
      import android.content.ComponentName;
      import android.content.ContentResolver;
      import android.content.Context;
      import android.content.Intent;
      import android.content.ServiceConnection;
      import android.database.Cursor;
      import android.media.MediaPlayer;
      import android.net.Uri;
      import android.os.Bundle;
      import android.os.IBinder;
      import android.provider.MediaStore;
      import android.support.design.widget.FloatingActionButton;
      import android.support.design.widget.Snackbar;
      import android.support.v7.app.AppCompatActivity;
      import android.support.v7.widget.Toolbar;
      import android.view.View;
      import android.view.Menu;
      import android.view.MenuItem;
      import android.widget.ListView;
      import android.widget.MediaController;
  
      import java.util.ArrayList;
      import java.util.Collections;
      import java.util.Comparator;
  
      public class MainActivity extends AppCompatActivity implements MediaController.MediaPlayerControl{
  
      private ArrayList&lt;Song&gt; songList;
      private ListView songView;
      private MusicService musicService;
      private Intent playIntent;
      private boolean musicBound = false;
      private MusicController controller;
      private boolean paused = false, playbackPaused = false;
  
      @Override
      protected void onPause(){
          super.onPause();
          paused = true;
      }
  
      @Override
      protected void onResume(){
          super.onResume();
          if(paused){
              setController();
              paused = false;
          }
      }
  
      @Override
      protected void onStop(){
          controller.hide();
          super.onStop();
      }
  
      private void setController(){
       controller = new MusicController(this);
          controller.setPrevNextListeners(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  playNext();
              }
          }, new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  playPrev();
              }
          });
          controller.setMediaPlayer(this);
          controller.setAnchorView(findViewById(R.id.song_list));
          controller.setEnabled(true);
      }
  
      private void playPrev() {
          musicService.playPrev();
          if(playbackPaused){
              setController();
              playbackPaused = false;
          }
          controller.show(0);
      }
  
      private void playNext() {
          musicService.playNext();
          if(playbackPaused){
              setController();
              playbackPaused = false;
          }
          controller.show(0);
      }
  
      public void songPicked(View view)
      {
          int songIndex = Integer.parseInt(view.getTag().toString());
          musicService.setSong(songIndex);
          musicService.playSong();
          if(playbackPaused){
              setController();
              playbackPaused = false;
          }
          controller.show(0);
      }
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
          Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
          setSupportActionBar(toolbar);
          setController();
          FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
          fab.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                          .setAction("Action", null).show();
              }
          });
          songView = (ListView) findViewById(R.id.song_list);
          songList = new ArrayList&lt;Song&gt;();
          getSongList();
  
          //Displaying the songs
  
          Collections.sort(songList, new Comparator&lt;Song&gt;() {
              @Override
              public int compare(Song lhs, Song rhs) {
                  return lhs.getTitle().compareTo(rhs.getTitle());
              }
          });
  
          SongAdapter songAdapter = new SongAdapter(this,songList);
          songView.setAdapter(songAdapter);
      }
  
      private ServiceConnection musicConnection = new ServiceConnection(){
  
          @Override
          public void onServiceConnected(ComponentName name, IBinder service) {
              MusicService.MusicBinder binder = (MusicService.MusicBinder) service;
              // get service
              musicService = binder.getService();
              //pass the list
              musicService.setList(songList);
              musicBound = true;
          }
  
          @Override
          public void onServiceDisconnected(ComponentName name) {
              musicBound = false;
          }
      };
  
      @Override
      protected void onStart(){
          super.onStart();
          if(playIntent == null)
          {
              playIntent = new Intent(this, MusicService.class);
              bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
              startService(playIntent);
          }
      }
  
      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          // Inflate the menu; this adds items to the action bar if it is present.
          getMenuInflater().inflate(R.menu.menu_main, menu);
          return true;
      }
  
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          // Handle action bar item clicks here. The action bar will
          // automatically handle clicks on the Home/Up button, so long
          // as you specify a parent activity in AndroidManifest.xml.
          switch (item.getItemId())
          {
              case R.id.action_shuffle:
                  musicService.setShuffle();
                  break;
              case R.id.action_end:
                  stopService(playIntent);
                  musicService = null;
                  System.exit(0);
                  break;
          }
  
          //noinspection SimplifiableIfStatement
  
          return super.onOptionsItemSelected(item);
      }
  
      public void getSongList()
      {
          // retrieve song info
          ContentResolver musicResolver = getContentResolver();
          Uri musicUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
          Cursor musicCursor = musicResolver.query(musicUri,null,null,null,null);
          int idColumn = 0;
          int titleColumn = 0;
          int artistColumn = 0;
  
          // Checking whether we have valid data
  
          if(musicCursor != null &amp;&amp; musicCursor.moveToFirst())
              {
                  titleColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
                  idColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media._ID);
                  artistColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
              }
          // Adding songs to list
          do
              {
                  long thisID = musicCursor.getLong(idColumn);
                  String thisTitle = musicCursor.getString(titleColumn);
                  String thisArtist = musicCursor.getString(artistColumn);
                  songList.add(new Song(thisID,thisTitle,thisArtist));
              } while(musicCursor.moveToNext());
      }
  
      @Override
      protected void onDestroy()
      {
          stopService(playIntent);
          musicService = null;
          super.onDestroy();
      }
  
      @Override
      public void start() {
          musicService.go();
      }
  
      @Override
      public void pause() {
          playbackPaused = true;
          musicService.pausePlayer();
      }
  
      @Override
      public int getDuration() {
          if(musicService != null &amp;&amp; musicBound &amp;&amp; musicService.isPng())
          {
              return musicService.getDur();
          }
          else
          {
              return 0;
          }
      }
  
      @Override
      public int getCurrentPosition() {
          if(musicService != null &amp;&amp; musicBound &amp;&amp; musicService.isPng())
          {
              return musicService.getPosn();
          }
          else
          {
              return 0;
          }
      }
  
      @Override
      public void seekTo(int pos) {
          musicService.seek(pos);
      }
  
      @Override
      public boolean isPlaying() {
          if(musicService != null &amp;&amp; musicBound)
          {
              return musicService.isPng();
          }
          else
          {
              return false;
          }
      }
  
      @Override
      public int getBufferPercentage() {
          return 0;
      }
  
      @Override
      public boolean canPause() {
          return true;
      }
  
      @Override
      public boolean canSeekBackward() {
          return true;
      }
  
      @Override
      public boolean canSeekForward() {
          return true;
      }
  
      @Override
      public int getAudioSessionId() {
          return 0;
      }
  
      public void onCompletion(MediaPlayer mp)
      {
  
      }
      public boolean onError(MediaPlayer mp, int a, int b)
      {
          return false;
      }
      }
  </code></pre>
  
  <p>The Custom MusicService Java class is as follows : </p>
  
  <pre><code>    package com.example.adityakrishnakumar.mymusicplayer;
  
      import android.app.Notification;
      import android.app.PendingIntent;
      import android.app.Service;
      import android.content.ContentUris;
      import android.content.Intent;
      import android.media.AudioManager;
      import android.media.MediaPlayer;
      import android.net.Uri;
      import android.os.Binder;
      import android.os.IBinder;
      import android.os.PowerManager;
      import android.provider.MediaStore;
      import android.util.Log;
  
      import java.util.ArrayList;
      import java.util.Random;
  
      public class MusicService extends Service implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener,MediaPlayer.OnCompletionListener{
      private static final int NOTIFY_ID = 1;
      private String songTitle = null;
  
      private boolean shuffle = false;
      private Random rand;
  
      public MusicService() {
      }
      private MediaPlayer player;
      private ArrayList&lt;Song&gt; songs;
      private int songPosn;
      private final IBinder musicBind = new MusicBinder();
  
      public IBinder onIBind(Intent intent){
          return musicBind;
      }
  
      public boolean onUnbind(Intent intent){
          player.stop();
          player.release();
          return false;
      }
  
      public void playSong(){
          player.reset();
          Song playSong = songs.get(songPosn);
          songTitle = playSong.getTitle();
          long currSong = playSong.getId();
          Uri trackUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,currSong);
          try{
              player.setDataSource(getApplicationContext(), trackUri);
          }catch (Exception e){
              Log.e("MUSIC SERVICE","Error Setting Data Source",e);
          }
          player.prepareAsync();
      }
      @Override
      public IBinder onBind(Intent intent) {
          // TODO: Return the communication channel to the service.
          return null;
      }
  
      @Override
      public void onCompletion(MediaPlayer mp) {
              if(player.getCurrentPosition() &gt; 0)
              {
                  mp.reset();
                  playNext();
              }
      }
  
      @Override
      public void onCreate(){
          // create service
          super.onCreate();
          //initialize position
          rand = new Random();
          songPosn = 0;
          player = new MediaPlayer();
          initMusicPlayer();
  
      }
  
      public void setShuffle(){
          if(shuffle) shuffle = false;
          else
              shuffle = true;
      }
  
      public void initMusicPlayer(){
          player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
          player.setAudioStreamType(AudioManager.STREAM_MUSIC);
          player.setOnPreparedListener(this);
          player.setOnCompletionListener(this);
          player.setOnErrorListener(this);
      }
  
      public void setList(ArrayList&lt;Song&gt; theSongs)
      {
          songs = theSongs;
      }
  
      public class MusicBinder extends Binder{
          MusicService getService(){
              return MusicService.this;
          }
      }
      @Override
      public boolean onError(MediaPlayer mp, int what, int extra) {
          mp.reset();
          return false;
      }
  
      @Override
      public void onPrepared(MediaPlayer mp)
      {
      mp.start();
          Intent notIntent = new Intent(this, MainActivity.class);
          notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
          PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notIntent,PendingIntent.FLAG_UPDATE_CURRENT);
          Notification.Builder builder = new Notification.Builder(this);
  
          builder.setContentIntent(pendingIntent)
                  .setSmallIcon(R.drawable.play)
                  .setTicker(songTitle)
                  .setOngoing(true)
                  .setContentTitle("Playing")
                  .setContentText(songTitle);
          Notification not = builder.build();
          startForeground(NOTIFY_ID,not);
      }
  
      public void setSong(int songIndex)
      {
          songPosn = songIndex;
      }
  
      public int getPosn()
      {
          return player.getCurrentPosition();
      }
      public int getDur()
      {
          return player.getDuration();
      }
      public boolean isPng()
      {
          return player.isPlaying();
      }
      public void pausePlayer(){
          player.pause();
      }
      public void seek(int posn)
      {
          player.seekTo(posn);
      }
      public void go()
      {
          player.start();
      }
      public void playPrev()
      {
          songPosn--;
          if(songPosn &lt; 0 )
          {
              songPosn = songs.size()-1;
          }
          playSong();
      }
      public void playNext(){
          if(shuffle)
          {
              int newSong = songPosn;
              while(newSong == songPosn)
              {
                  newSong = rand.nextInt(songs.size());
              }
              songPosn = newSong;
          }
          else
          {
              songPosn++;
              if(songPosn &gt;= songs.size()) songPosn = 0;
          }
          playSong();
      }
  
      @Override
      public void onDestroy()
      {
          stopForeground(true);
      }
      }
  </code></pre>
  
  <p>The SongAdapter (that stores the music info is as follows : </p>
  
  <pre><code>    package com.example.adityakrishnakumar.mymusicplayer;
  
      import android.content.Context;
      import android.view.LayoutInflater;
      import android.view.View;
      import android.view.ViewGroup;
      import android.widget.BaseAdapter;
      import android.widget.LinearLayout;
      import android.widget.TextView;
  
      import java.util.ArrayList;
  
      public class SongAdapter extends BaseAdapter {
  
      private ArrayList&lt;Song&gt; songs;
      private LayoutInflater songInf;
  
      public SongAdapter(Context c, ArrayList&lt;Song&gt; theSongs)
      {
          songs = theSongs;
          songInf = LayoutInflater.from(c);
      }
  
      @Override
      public int getCount() {
          return songs.size();
      }
  
      @Override
      public Object getItem(int position) {
          return null;
      }
  
      @Override
      public long getItemId(int position) {
          return 0;
      }
  
      @Override
      public View getView(int position, View convertView, ViewGroup parent) {
          // map to song layout
          LinearLayout songLay = (LinearLayout)songInf.inflate(R.layout.song,parent,false);
          //Get Title and artist views
          TextView songView = (TextView) songLay.findViewById(R.id.song_title);
          TextView artistView = (TextView) songLay.findViewById(R.id.song_artist);
          // get the song using position
          Song currSong = songs.get(position);
          // Get Title &amp; Artist Strings
          songView.setText(currSong.getTitle());
          artistView.setText(currSong.getArtist());
          // Set Position as tag
          songLay.setTag(position);
          return songLay;
      }
      }
  </code></pre>
  
  <p>The Controller for music playback (MusicController) is as follows :</p>
  
  <pre><code>    package com.example.adityakrishnakumar.mymusicplayer;
  
      import android.annotation.TargetApi;
      import android.content.Context;
      import android.widget.MediaController;
      import android.os.Build;
  
      public class MusicController extends MediaController {
  
      public MusicController(Context c)
      {
          super(c);
      }
      public void hide(){}
      }
  </code></pre>
  
  <p>I have also given the following permissions in Manifest :</p>
  
  <pre><code>     &lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
      &lt;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/&gt;
  
  The XML that gives the song name and artist name is as follows (song.xml)
  
      &lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;LinearLayout 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:onClick="songPicked"
      android:orientation="vertical"
      android:padding="5dp"&gt;
  
      &lt;TextView
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:id="@+id/song_title"
          android:textColor="#ffffff99"
          android:textSize="20sp"
          android:textStyle="bold"/&gt;
  
      &lt;TextView
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:id="@+id/song_artist"
          android:textColor="#ffffff99"
          android:textSize="15sp"
          /&gt;
  &lt;/LinearLayout&gt;
  </code></pre>
  
  <p>Thanks in Advance...</p>