How to detect each RecyclerView item after it is displayed

12,065

Solution 1

You need to add listener for TTS. Then update your RecyclerView to show right image when speech starts and ends.

I've created a test project to show how it can be implemented. Here you can see how it works. Here is my github repository.

Here is main part of my MainActivity class.

private void initTts() {
    tts = new TextToSpeech(this, this);
    tts.setLanguage(Locale.US);
    tts.setOnUtteranceProgressListener(new MyListener());
}

@Override
public void onInit(int status) {
    playSound(0);
}

private void playSound(int index) {
    HashMap<String, String> hashMap = new HashMap<>();
    hashMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, String.valueOf(index));
    tts.speak(data.get(index), TextToSpeech.QUEUE_ADD, hashMap);
}

class MyListener extends UtteranceProgressListener {
    @Override
    public void onStart(String utteranceId) {
        int currentIndex = Integer.parseInt(utteranceId);
        mMainAdapter.setCurrentPosition(currentIndex);
        handler.post(new Runnable() {
            @Override
            public void run() {
                mMainAdapter.notifyDataSetChanged();
            }
        });
    }

    @Override
    public void onDone(String utteranceId) {
        int currentIndex = Integer.parseInt(utteranceId);
        mMainAdapter.setCurrentPosition(-1);
        handler.post(new Runnable() {
            @Override
            public void run() {
                mMainAdapter.notifyDataSetChanged();
            }
        });
        if (currentIndex < data.size() - 1) {
            playSound(currentIndex + 1);
        }
    }

    @Override
    public void onError(String utteranceId) {
    }
}

Solution 2

you need to override onViewAttachedToWindow and onViewDetachedFromWindow. but for detecting holer type you need getItemViewType() just like that:

public class PostAdapter extends RecyclerView.Adapter {

@Override
public int getItemViewType(int position) {
    switch (types.get(position)){
        case 1:
            return 1;
        case 2:
            return 2;
        default:
            return position;


    }
}
@Override
public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) {
    super.onViewAttachedToWindow(holder);
    if (holder.getItemViewType() == 1){
        //play song

    }

}

@Override
public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) {
    super.onViewDetachedFromWindow(holder);
    if (holder.getItemViewType() == 1){
        //pause song

    }
}

Solution 3

You can simply use onViewAttachedToWindow(VH) in your adapter. See https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#onViewAttachedToWindow(VH)

Update:

As you know RecyclerView will be call OnBindViewHolder only once for each item.

RecyclerView will not call this method again if the position of the item changes in the data set unless the item itself is invalidated or the new position cannot be determined.

So you can use onViewAttachedToWindow

(onViewAttachedToWindow) Called when a view created by this adapter has been attached to a window.

This can be used as a reasonable signal that the view is about to be seen by the user. If the adapter previously freed any resources in onViewDetachedFromWindow those resources should be restored here.

You can use it like this:

public class Adapter extends RecyclerView.Adapter<MyViewHolder> {
   
    // rest of your code

   
    @Override
    public void onViewAttachedToWindow(MyViewHolder holder) {
         super.onViewAttachedToWindow(holder);
        // play your sound
    }
}

Hope it helps!

Share:
12,065
Dan
Author by

Dan

Updated on July 26, 2022

Comments

  • Dan
    Dan almost 2 years

    I want to detect each item in my RecylerView after it is displayed to the user.

    Basically, I am trying to play a sound on each item after it is loaded on the screen.

    But I am not able to detect whenever each item is loaded on the screen! Is there any method I have to call to detect each item rendered

    E.g 1st RecyclerView item displayed -> play sound
        2st RecyclerView item displayed -> play sound...
    

    My Adapter class looks like this -

    public class AdapterListAnimation extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    
        private List<Multiples> items = new ArrayList<>();
    
        private Context ctx;
        private OnItemClickListener mOnItemClickListener;
        private int animation_type = 0;
        .........
        .........
    

    I am calling this initComponent() method from onCreated() method. Can you give advice on what should I do to achieve my goal as described above?

    private void initComponent() {
        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setHasFixedSize(true);
        items = DataGenerator.getPeopleData(this,of,value);
        setAdapter();
    
        /* MediaPlayer mp=MediaPlayer.create(this, R.raw.sword);
        if (mp.isPlaying()) {
            mp.stop();
            mp.release();
            mp = MediaPlayer.create(this, R.raw.sword);
        } mp.start();*/
    }
    
    private void setAdapter() {
        // Set data and list adapter
        mAdapter = new AdapterListAnimation(this, items, animation_type);
        recyclerView.setAdapter(mAdapter);
    
        // on item list clicked
        mAdapter.setOnItemClickListener(new AdapterListAnimation.OnItemClickListener() {
            @Override
            public void onItemClick(View view, com.math.multiplication.model.Multiples obj, int position) {
                Snackbar.make(parent_view, "Item " + obj.first + " clicked", Snackbar.LENGTH_SHORT).show();
            }
        });
    }
    
  • Dan
    Dan about 5 years
    I could not understand your answer. Plz elaborate it . I have updated my question.
  • Dan
    Dan about 5 years
    @Override is showing error as there is no method to overide
  • Amin Mastani
    Amin Mastani about 5 years
    Replace MyViewHolder with RecyclerView.ViewHolder
  • Dan
    Dan about 5 years
    Hi ! Please help me on same question: stackoverflow.com/q/55516858/1684778 I have explained here very clearly & better way. I think you can only in SO can help me
  • FindOutIslamNow
    FindOutIslamNow about 4 years
    As you know RecyclerView will be call OnBindViewHolder only once for each item. Not necessary. RecyclerView can "re"use a view holder again and again