【问题标题】:How to detect each RecyclerView item after it is displayed显示后如何检测每个 RecyclerView 项目
【发布时间】:2019-03-31 18:04:27
【问题描述】:

我想在RecylerView 中的每个项目显示给用户后对其进行检测。

基本上,我试图在每个项目加载到屏幕后播放声音。

但我无法检测到每个项目何时加载到屏幕上!有没有我必须调用的方法来检测呈现的每个项目

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

我的适配器类看起来像这样 -

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;
    .........
    .........

我从onCreated() 方法调用这个initComponent() 方法。您能否就我应该如何实现上述目标提供建议?

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

【问题讨论】:

标签: java android android-recyclerview android-viewholder


【解决方案1】:

您需要覆盖onViewAttachedToWindowonViewDetachedFromWindow。但是要检测空洞类型,您需要getItemViewType(),就像这样:

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

    }
}

【讨论】:

    【解决方案2】:

    您需要为 TTS 添加监听器。然后更新您的RecyclerView 以在演讲开始和结束时显示正确的图像。

    我创建了一个测试项目来展示它是如何实现的。 Here 你可以看到它是如何工作的。 Here 是我的 github 仓库。

    这是我的MainActivity 课程的主要部分。

    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) {
        }
    }
    

    【讨论】:

      【解决方案3】:

      您可以在适配器中简单地使用 onViewAttachedToWindow(VH)。 见https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#onViewAttachedToWindow(VH)

      更新:

      如您所知,RecyclerView 每件商品只会调用一次OnBindViewHolder

      如果item在数据集中的位置发生变化,RecyclerView将不会再次调用该方法,除非item本身失效或无法确定新的位置。

      所以你可以使用onViewAttachedToWindow

      (onViewAttachedToWindow) 当此适配器创建的视图已附加到窗口时调用。

      这可以用作用户即将看到视图的合理信号。如果适配器之前释放了 onViewDetachedFromWindow 中的任何资源,则这些资源应该是在这里恢复。

      你可以这样使用它:

      public class Adapter extends RecyclerView.Adapter<MyViewHolder> {
         
          // rest of your code
      
         
          @Override
          public void onViewAttachedToWindow(MyViewHolder holder) {
               super.onViewAttachedToWindow(holder);
              // play your sound
          }
      }
      
      

      希望对你有帮助!

      【讨论】:

      • 我无法理解您的回答。请详细说明。我已经更新了我的问题。
      • @Override 显示错误,因为没有方法可以覆盖
      • RecyclerView.ViewHolder替换MyViewHolder
      • 嗨!请帮助我解决同样的问题:stackoverflow.com/q/55516858/1684778 我已经在这里解释得非常清楚和更好的方式。我想你只能在 SO 可以帮助我
      • As you know RecyclerView will be call OnBindViewHolder only once for each item. 没必要。 RecyclerView 可以一次又一次地“重新”使用视图持有者
      【解决方案4】:

      如果我正确理解了您的问题,您希望在加载 RecyclerView 中的项目时播放声音。

      因此,我想在这里想一个解决方法。您可以考虑在播放前一个项目的声音后添加一个项目。

      我想为我要解释的内容提供一个伪代码。如果您的声音停止播放,您可能会考虑使用MediaPlayer.OnCompletionListener 来收听,然后将下一个项目添加到RecyclerView,然后在您的适配器上调用notifyDataSetChanged 以加载您的RecyclerView 中的下一个项目。

      因此,您可能希望首先在适配器中进行以下修改。

      // Declare a function in your adapter which adds new item in the RecyclerView
      public void addItem(Multiples item) {
          items.add(item);
          notifyItemInserted(items.size());
      }
      

      现在在您设置RecyclerViewActivity 中,您需要有以下数组。

      ArrayList<Multiples> allItems = new ArrayList<Multiples>(); // This list will contain all the data
      int soundToBePlayed = -1; // Initialize the value with -1
      ArrayList<Integer> soundList = getAllSoundsInAList(); 
      

      如下修改你的函数。

      private void initComponent() {
          recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
          recyclerView.setLayoutManager(new LinearLayoutManager(this));
          recyclerView.setHasFixedSize(true);
          allItems = DataGenerator.getPeopleData(this,of,value);
          setAdapter();
      }
      
      private void setAdapter() {
          mAdapter = new AdapterListAnimation(this, animation_type); // Do not pass the items list
          recyclerView.setAdapter(mAdapter);
      
          // .. Your item click listener goes here
      }
      

      由于 items 已从构造函数中删除,您还需要修改适配器的构造函数。只需删除采用items 的变量即可。因为稍后我们将向items 添加元素。

      然后您需要编写另一个函数,该函数需要在您调用 initComponent 函数之后在您的活动的 onCreate 函数中调用。该函数应如下所示。

      private void addItemInRecyclerViewAndPlaySound() {
      
          soundToBePlayed++;
      
          adapter.addItem(allItems.get(soundToBePlayed));
          recyclerView.scrollToPosition(adapter.getItemCount() - 1);
      
          Integer soundId = soundList.get(soundToBePlayed);
      
          MediaPlayer mp = MediaPlayer.create(this, soundId);
      
          if (mp.isPlaying()) {
              mp.stop();
              mp.release();
              mp = MediaPlayer.create(this, soundId);
              mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                  public void onCompletion(MediaPlayer mp) {
                      // Call this function again to add next item
                      // and play the next sound at the same time
                      if(soundToBePlayed < allItems.size() - 1)
                          addItemInRecyclerViewAndPlaySound();
                  }
              });
          }
      
          mp.start();
      }
      

      我没有测试过代码,但是,我想你已经明白了。这也可以使用适配器内部的interface 优雅地实现。实施技术是您的选择。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-25
        • 2021-12-20
        • 1970-01-01
        相关资源
        最近更新 更多