Veloxigami Veloxigami - 28 days ago 9
Android Question

How to pass on the cursor position from RecyclerViewAdapter to Activity

I'm trying to build a simple media player app. I created a RecyclerViewAdapter with CursorAdapter in it's constructor and managed to implement a way to use External Storage to create a playlist. Now I want to make an onClickListener but I'm having trouble. I just need to get the TAG of the view that is clicked so that I can get the necessary values from it and pass it on to media player to play. Please help. I tried to do this using an interface but it's not working.

This is my onClick method implementation through interface

public class MainActivity extends AppCompatActivity implements RecyclerViewAdapter.OnItemClickListener{

@Override
protected void onCreate(Bundle savedInstanceState) {

ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
1);

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);



selectedFile = (TextView) findViewById(R.id.selected_file);
seekBar = (SeekBar) findViewById(R.id.seekbar);
playButton = (ImageButton) findViewById(R.id.play);
nextButton = (ImageButton) findViewById(R.id.next);
prevButton = (ImageButton) findViewById(R.id.prev);

player = new MediaPlayer();

player.setOnCompletionListener(onCompletion);
player.setOnErrorListener(onError);
seekBar.setOnSeekBarChangeListener(seekBarChanged);
recyclerView = (RecyclerView) findViewById(R.id.playlist);


c = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null,null,null,null);

if(null != c) {
c.moveToFirst();

layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
mAdapter = new RecyclerViewAdapter(this, c);

recyclerView.setAdapter(mAdapter);

playButton.setOnClickListener(onButtonClick);
nextButton.setOnClickListener(onButtonClick);
prevButton.setOnClickListener(onButtonClick);
}

public void onItemClick(View v) {
songName = ((TextView) v.findViewById(R.id.songname)).getText().toString();
albumName = ((TextView)v.findViewById(R.id.album)).getText().toString();
currentFile = (String) v.getTag();

Log.e("File","Selected");
selectedFile.setText(songName);

startPlay(currentFile);

}

/*other code */


And this is my recyclerview adapter

package com.veloxigami.android.audioplayerusingservice;

import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.provider.MediaStore;
import android.support.v4.widget.CursorAdapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import org.w3c.dom.Text;


public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

// Because RecyclerView.Adapter in its current form doesn't natively
// support cursors, we wrap a CursorAdapter that will do all the job
// for us.
CursorAdapter mCursorAdapter;

Context mContext;

public interface OnItemClickListener {
void onItemClick(View view);
}

public RecyclerViewAdapter.OnItemClickListener clickListener;

public RecyclerViewAdapter(Context context, Cursor c) {

mContext = context;
mCursorAdapter = new CursorAdapter(mContext, c, 0) {

@Override
public void bindView(View view, Context context, Cursor cursor) {
// Binding operations
TextView songName = (TextView) view.findViewById(R.id.songname);
TextView album = (TextView) view.findViewById(R.id.album);
TextView duration = (TextView) view.findViewById(R.id.duration);

songName.setText(cursor.getString(
cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME)
));

album.setText(cursor.getString(
cursor.getColumnIndex(MediaStore.Audio.AlbumColumns.ALBUM)
));

if(cursor.getString(cursor.getColumnIndex(
MediaStore.Audio.AudioColumns.DURATION
))!=null){
long durationInMs = Long.parseLong(cursor.getString(
cursor.getColumnIndex(MediaStore.Audio.AudioColumns.DURATION)
));

int durationInMin = ((int) durationInMs / 1000) /60;

int durationInSec = ((int) durationInMs / 1000) % 60;

duration.setText(""+ durationInMin+ ":" +String.format("%02d",durationInSec));

view.setTag(cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA)));
}



}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Inflate the view here
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.list_item,parent,false);

bindView(v,context,cursor);
return v;
}


};
}

public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView songName, album, duration;
View layout;
CursorAdapter mCursorAdapter;
LinearLayout ll;

public ViewHolder(View itemView) {
super(itemView);
layout = itemView;
songName = (TextView) itemView.findViewById(R.id.songname);
album = (TextView) itemView.findViewById(R.id.album);
duration = (TextView) itemView.findViewById(R.id.duration);
ll = (LinearLayout) itemView.findViewById(R.id.playlist_item);
ll.setOnClickListener(this);
}

@Override
public void onClick(View v) {
if(v == ll)
clickListener.onItemClick(ll);
}
}

@Override
public int getItemCount() {
return mCursorAdapter.getCount();
}


@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Passing the inflater job to the cursor-adapter
View v = mCursorAdapter.newView(mContext, mCursorAdapter.getCursor(), parent);
return new ViewHolder(v);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Passing the binding operation to cursor loader
mCursorAdapter.getCursor().moveToPosition(position); //EDITED: added this line as suggested in the comments below, thanks :)
mCursorAdapter.bindView(holder.itemView, mContext, mCursorAdapter.getCursor());

}


}


This is the error it shows:

FATAL EXCEPTION: main
Process: com.veloxigami.android.audioplayerusingservice, PID: 24341
java.lang.NullPointerException: Attempt to invoke interface method 'void com.veloxigami.android.audioplayerusingservice.RecyclerViewAdapter$OnItemClickListener.onItemClick(android.view.View)' on a null object reference
at com.veloxigami.android.audioplayerusingservice.RecyclerViewAdapter$ViewHolder.onClick(RecyclerViewAdapter.java:106)
at android.view.View.performClick(View.java:5207)
at android.view.View$PerformClick.run(View.java:21168)
at android.os.Handler.handleCallback(Handler.java:746)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5443)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

Answer Source

You need to assign the listener.

You can try this since you made the Activity implement the listener.

public RecyclerViewAdapter.OnItemClickListener clickListener;

public RecyclerViewAdapter(Context context, Cursor c) {

    mContext = context;
    if (context instanceof RecyclerViewAdapter.OnItemClickListener) {
        clickListener = (RecyclerViewAdapter.OnItemClickListener) context;
    }

Also a good idea to always null-check the listener.

@Override
public void onClick(View v) {
    if(v == ll && clickListener != null)
        clickListener.onItemClick(ll);
}