I have a FirestoreRecyclerAdapter inside a fragment. First, I populate items in my FirestoreRecyclerAdapter from Firestore, then for each item in my RecyclerView, i have a Url to FirebaseStorage where i keep a recorded audio message. How can i play this message when the user clicks on a button inside my RecyclerView item and a have the AsyncTask associated with playing this audio update a SeekBar that is found in the same RecyclerView item?

I have been able to play the audio using MediaPlayer, but i can't get the AsyncTask to Update my UI. Here' my AsyncTask:

public class MyTask extends AsyncTask {

private MediaPlayer mPlayer;
private Callback  mCb;
private FirebaseFirestore db;
private StorageReference storageRef;
private SeekBar seekBar;

private Post post;


public interface Callback {
    void onDataLoaded(Integer result);
}


public MyTask (final Post post, Callback cb, SeekBar seekBar){

    this.post = post;
    this.mCb = cb;
    this.seekBar = seekBar;


    // Initialize media player
    mPlayer = new MediaPlayer();
    mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {

            db = FirebaseFirestore.getInstance();

            DocumentReference postRef = db.collection("Posts")
                    .document(post.getPost_Id());
            Map<String, Object> map = new HashMap<>();
            map.put("score", FieldValue.increment(2));
            map.put("listens", FieldValue.increment(1));
            postRef.update(map);
        }



    });
}

@Override
protected String doInBackground(String... strings) {

    mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    try{ mPlayer.setDataSource(strings[0]);} catch (Exception e) {e.printStackTrace();}
    // wait for media player to get prepare
    mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
            mp.start();
            // Get the current audio stats

            for(int i =0; i<mp.getDuration(); i = mp.getCurrentPosition()) {
                //int duration = mPlayer.getDuration() / 1000; // In milliseconds
                //int due = (mPlayer.getDuration() - mPlayer.getCurrentPosition()) / 1000;
                //int pass = duration - due;

                int mCurrentPosition = mp.getCurrentPosition(); // In milliseconds

                //seekBar.setProgress(mCurrentPosition);
                publishProgress(mCurrentPosition);

                try {
                    Thread.sleep(1);
                } catch (Exception e){
                    e.printStackTrace();
                }

            }

        }
    });
    mPlayer.prepareAsync();
    return null;
}

@Override
protected void onProgressUpdate(Integer... values) {
    super.onProgressUpdate(values);
    //Using the callback, I get data logged on the console but the 
    //item on the RecyclerView is not updated
    mCb.onDataLoaded(values[0]);
    //Pass the Seekbar to the AsyncTas doesnt update
    //seekBar.setProgress(values[0]);
}

@Override
protected void onPostExecute(String s) {
    super.onPostExecute(s);
} }

I implement the Callback inteface in the ViewHolder of my FirestoreRecyclerAdapter. Here's My adapter:

private class PostViewHolder extends RecyclerView.ViewHolder implements MyTask.Callback {


    private PostViewHolder holder;
    private LinearLayout root, llp,;
    private RelativeLayout rlp;
    private TextView  tv_due, tv_pass;
    private Button btn_play;
    private SeekBar seekBar;

    private FirebaseFirestore db;
    private final StorageReference storageRef;

    public PostViewHolder(@NonNull View itemView) {
        super(itemView);

        root = itemView.findViewById(R.id.list_root);

        llp = root.findViewById(R.id.llp);
        rlp = root.findViewById(R.id.rlp);

        btn_play = llp.findViewById(R.id.btn_play);


        tv_due = rlp.findViewById(R.id.tv_due);
        tv_pass = rlp.findViewById(R.id.tv_pass);
        seekBar = rlp.findViewById(R.id.seek_bar);

        db = FirebaseFirestore.getInstance();
        storageRef = FirebaseStorage.getInstance().getReference();

    }

    @Override
    public void onDataLoaded(Integer result) {
        Log.d("NEW TAG", result.toString());
        holder.seekBar.setProgress(result);

    }


    void setData(final Post post, final PostViewHolder holder) {

        this.holder = holder;

        btn_play.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                if (btn_play.getText().equals("Play")) {



                    playMusic(seekBar, tv_pass, tv_due, post, mPlayer, holder);
                }

            }
        });


        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                if(mPlayer!=null && b){

                    mPlayer.seekTo(i*1000);
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

    }
}

And playMusic() is as follows:

private void playMusic(final Post post, final MediaPlayer mPlayer, final MyTask.Callback cb) {
    final FirebaseStorage storage = FirebaseStorage.getInstance();


    StorageReference storageRef = storage.getReference().child("/" + post.getAudio());
    storageRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
        @Override
        public void onSuccess(Uri uri) {

            final String url = uri.toString();

            MyTask task = new MyTask(post, cb, seekBar);
            task.execute(url);

        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Log.i("TAG", e.getMessage());
        }
    });

}

0 Answers