如何使用 Android 中的歌曲自动移动 Seekbar?

How to automate Seekbar movement with a song in Android?

我知道以前有人问过类似的问题,但其中 none 可以解决我的问题。我正在制作音乐播放器并希望在播放歌曲时自动执行 Seekbar。我正在使用 RecyclerView 并且 onBindViewHolder 部分中存在以下代码段。

public class ListViewPopulator extends       
RecyclerView.Adapter<ListViewPopulator.ViewHolder>{
List<String> musicName;
List<String> musicAdd;
Context context;
MediaPlayer mediaPlayer;
Button media_play;
Button media_stop;
SeekBar seekBar;
final Handler mhandler=new Handler();
TextView timer;

public ListViewPopulator(Activity context, List<String> musicName, List<String> musicAdd)
{
    this.context=context;
    this.musicName=musicName;
    this.musicAdd=musicAdd;
    media_play= (Button)context.findViewById(R.id.play);
    media_stop=(Button)context.findViewById(R.id.pause);
    seekBar= (SeekBar) context.findViewById(R.id.seekbar);
    timer=(TextView) context.findViewById(R.id.timer);


}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(context).inflate(R.layout.listview,parent,false);
    return new ViewHolder(v);
}
void something(String s)
{
    try{mediaPlayer.stop();}catch (NullPointerException e){e.printStackTrace();}
    //To fetch the location of audio files on disk
    mediaPlayer=MediaPlayer.create(context, Uri.fromFile(new File(s)));
    mediaPlayer.start();
    //seekBar.setProgress(0);
    //seekBar.setMax(mediaPlayer.getDuration());

} int temp=0;

int i=0;
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
    final String s = musicAdd.get(position);
    final String v = musicName.get(position);
    holder.data.setText(v);
    seeker();
    cont_seek();
    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            temp = position + 1;
            something(s);
            seekBar.setProgress(0);
            seekBar.setMax(mediaPlayer.getDuration());
            // mediaPlayer.reset();
            change();
            op();
        }
    });


    media_play.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            try {
                mediaPlayer.start();
                Log.d("click", "Kuch bhi");
            } catch (NullPointerException e) {
                e.printStackTrace();
            }
        }
    });
    media_stop.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            try {
                mediaPlayer.pause();
                Log.d("click2", "Kuch bhi2");
            } catch (NullPointerException e) {
                e.printStackTrace();
            }
        }
    });

}

void cont_seek(){
    Log.d("auto","seek");
    Runnable runnable=new Runnable() {

        @Override
        public void run() {
            String time;
            if((mediaPlayer != null) && mediaPlayer.isPlaying()){
                int progress = mediaPlayer.getCurrentPosition();
                int min = (progress / 1000) / 60;
                Log.d("auto","seek");
                int sec = (progress / 1000) % 60;
                if (sec < 10)
                    time = "0" + sec;
                else
                    time = "" + sec;
                String elapsedTime = min + ":" + time + "";
                timer.setText(elapsedTime);
                seekBar.setMax(mediaPlayer.getDuration());
                seekBar.setProgress(progress);
                mhandler.postDelayed(this, 1000);
            }

        }
    };
       mhandler.postDelayed(runnable,1000);

}


void seeker(){
    seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        int seek_progress;
        String time_sec;
        @Override
        public void onProgressChanged(final SeekBar seekBar, int progress, boolean fromUser) {
            seek_progress=progress;
            //seek_progress=seek_progress*1000;
            new Runnable() {
                @Override
                public void run() {
                    int min=(seek_progress/1000)/60;
                    int sec=(seek_progress/1000)%60;
                    if(sec<10)
                        time_sec="0"+sec;
                    else
                        time_sec=""+sec;
                    String elapsedTime=min+":"+time_sec+"";
                    timer.setText(elapsedTime);
                    //mediaPlayer.seekTo(seek_progress);
                    new Handler().postDelayed(this,1000);
                }
            }.run();

            if(fromUser) {
                    Log.d("blah","blah");
                new Runnable() {
                    @Override
                    public void run() {
                        int min=(seek_progress/1000)/60;
                        int sec=(seek_progress/1000)%60;
                        if(sec<10)
                            time_sec="0"+sec;
                        else
                            time_sec=""+sec;
                        String elapsedTime=min+":"+time_sec+"";
                        timer.setText(elapsedTime);
                        //mediaPlayer.seekTo(seek_progress);
                        new Handler().postDelayed(this,1000);
                        }


                }.run();
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
                if(mediaPlayer!=null){mediaPlayer.seekTo(seek_progress);}
        }
    });

}
int h=0;
void change(){
    try{mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
    @Override
    public void onCompletion(MediaPlayer mp) {

        if(temp!=musicAdd.size())
        something(musicAdd.get(temp));
        temp=temp+1;
        seekBar.setProgress(0);
        seekBar.setMax(mediaPlayer.getDuration());
        change();
    }


});


    }catch(Throwable throwable){throwable.printStackTrace();}}
void op()
 {
        Sensey.getInstance().startFlipDetection(new FlipDetector.FlipListener() {
    @Override
    public void onFaceUp() {
        if (i == 0) {
            try {
                mediaPlayer.start();
                i = 1;
                h=1;
            }catch (NullPointerException e){e.printStackTrace();}
        }
    }

    @Override
    public void onFaceDown() {
        if (i == 1) {
            try {
                mediaPlayer.pause();
                i = 0;
                h=0;
            }catch (NullPointerException e){e.printStackTrace();}
        }
    }
});

Sensey.getInstance().startShakeDetection(15, new          ShakeDetector.ShakeListener() {
    @Override
    public void onShakeDetected() {
        try {
            if(h==1)
            something(musicAdd.get(randomG(musicAdd.size()-1,0)));
        }catch (Throwable throwable)
        {
            throwable.printStackTrace();
        }
    }
  });
  }
   int randomG(int max,int min)
  {
       Random random=new Random();
       return random.nextInt((max-min)+1);
} 
@Override
public int getItemCount() {
    return musicName.size();
}

 public class ViewHolder extends RecyclerView.ViewHolder
 {
      TextView data;
       public ViewHolder(View itemView) {
       super(itemView);
       data=(TextView)itemView.findViewById(R.id.data);
     }
  }
 }

我很确定逻辑是正确的并且检查了日志,代码似乎没有执行。有人可以解释为什么吗?

您需要按如下方式使用您的 Handler & Runnable

final Handler handler = new Handler();

final Runnable r = new Runnable() {
    public void run() {

        //YOUR CODE GOES HERE

        handler.postDelayed(this, 1000);
    }
};

handler.postDelayed(r, 0);

在你的回收视图适配器中,你可以使用这样的东西:

  @Override
public VoiceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    return VoiceViewHolder.createVoiceViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.lecture_voice_item_recycler, parent, false));
}

@Override
public void onBindViewHolder(VoiceViewHolder holder, int position) {
    holder.bindHolderToVoice(10000, "your path");
}

public static class VoiceViewHolder extends RecyclerView.ViewHolder {
    CardView cardView;
    TextView voiceDuration;
    ImageView voiceView;
    ImageButton mPlayButton;
    MediaPlayer mPlayer;
    RelativeLayout layoutVoice;
    RelativeLayout layoutVoiceNotFound;
    boolean isPlaying;
    TextView voiceDurationPlayer;
    double timeElapsed = 0, finalTime = 0;
    Handler durationHandler = new Handler();
    Runnable updateSeekBarTime;
    SeekBar seekBarDuration;

    private VoiceViewHolder(final View itemView) {
        super(itemView);
    }

    public static VoiceViewHolder createVoiceViewHolder(View convertView) {
        VoiceViewHolder holder = new VoiceViewHolder(convertView);
        holder.voiceDuration = (TextView) convertView.findViewById(R.id.voice_duration);
        holder.cardView = (CardView) convertView.findViewById(R.id.card_view);
        holder.voiceView = (ImageView) convertView.findViewById(R.id.voiceView);
        holder.mPlayButton = (ImageButton) convertView.findViewById(R.id.playButton);
        holder.layoutVoice = (RelativeLayout) convertView.findViewById(R.id.layoutVoice);
        holder.layoutVoiceNotFound = (RelativeLayout) convertView.findViewById(R.id.layoutVoiceNotFound);
        holder.voiceDurationPlayer = (TextView) convertView.findViewById(R.id.voiceDurationPlayer);
        holder.seekBarDuration = (SeekBar) convertView.findViewById(R.id.seekBarDuration);
        holder.isPlaying = false;
        holder.mPlayer = new MediaPlayer();
        return holder;
    }

    public void bindHolderToVoice(final long duration, final String path) {
        final Context context = itemView.getContext();

        if (duration >= 60000) {
            voiceDuration.setText(String.format("%d %s, %d %s", TimeUnit.MILLISECONDS.toMinutes(duration), context.getString(R.string.min),
                    TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)),
                    context.getString(R.string.sec)));
        } else {
            voiceDuration.setText(String.format("%d %s",
                    TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)),
                    context.getString(R.string.sec)));
        }

        finalTime = duration;
        seekBarDuration.setMax((int) finalTime);
        seekBarDuration.setClickable(false);

        seekBarDuration.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (mPlayer.isPlaying()) {
                    SeekBar sb = (SeekBar) v;
                    mPlayer.seekTo(sb.getProgress());
                }
                return false;
            }
        });

        updateSeekBarTime = new Runnable() {
            public void run() {
                if (mPlayer != null) {
                    if (mPlayer.isPlaying()) {
                        timeElapsed = mPlayer.getCurrentPosition();
                        seekBarDuration.setProgress((int) timeElapsed);
                        voiceDurationPlayer.setText(String.format("%02d:%02d", TimeUnit.MILLISECONDS.toMinutes((long) timeElapsed), TimeUnit.MILLISECONDS.toSeconds((long) timeElapsed) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long) timeElapsed))));
                        durationHandler.postDelayed(this, 100);
                    } else {
                        mPlayer.pause();
                        isPlaying = false;
                    }
                }
            }
        };

        File voiceFile = new File(path);
        mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                isPlaying = false;
            }
        });

        mPlayButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!isPlaying) {
                    isPlaying = true;
                    try {
                        mPlayer = new MediaPlayer();
                        mPlayer.setDataSource(path);
                        mPlayer.prepare();
                    } catch (IOException e) {
                        Log.e("tag", "Start playing prepare() failed");
                        isPlaying = false;
                    }
                    mPlayer.start();
                    timeElapsed = mPlayer.getCurrentPosition();
                    seekBarDuration.setProgress((int) timeElapsed);
                    durationHandler.postDelayed(updateSeekBarTime, 100);
                } else {
                    isPlaying = false;
                    mPlayer.pause();
                }
            }
        });

    }
}

布局lecture_voice_item_recycler.xml是这样的:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/lecture_voice"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/lecture_voice__margin_card">

    <android.support.v7.widget.CardView
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/lecture_voice__margin_card"
        android:clickable="true"
        android:foreground="?android:attr/selectableItemBackground">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/lecture_voice__margin_card"
            android:layout_marginBottom="@dimen/lecture_voice__margin_card">

            <LinearLayout
                android:id="@+id/layoutVoiceInfo"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/grid_annotation_margin"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/voice_duration"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:layout_marginLeft="@dimen/activity_horizontal_margin"
                    android:layout_marginRight="@dimen/activity_horizontal_margin"
                    android:textAppearance="?android:attr/textAppearanceMedium" />

            </LinearLayout>

            <RelativeLayout
                android:id="@+id/layoutVoice"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/layoutVoiceInfo"
                android:gravity="center_vertical"
                android:layout_marginLeft="@dimen/activity_horizontal_margin">

                <ImageButton
                    android:id="@+id/playButton"
                    android:layout_width="@dimen/lecture_voice_icon"
                    android:layout_height="@dimen/lecture_voice_icon"
                    android:background="@android:color/transparent"
                    android:scaleType="fitXY"
                    android:src="@drawable/ic_play" />

                <LinearLayout
                    android:id="@+id/layoutVoiceSeekbar"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:layout_toRightOf="@+id/playButton"
                    android:layout_marginLeft="@dimen/activity_horizontal_margin"
                    android:layout_marginTop="@dimen/activity_horizontal_margin">

                    <SeekBar
                        android:id="@+id/seekBarDuration"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="@dimen/activity_horizontal_margin"
                        android:layout_marginRight="@dimen/activity_horizontal_margin" />

                    <TextView
                        android:id="@+id/voiceDurationPlayer"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="00:00"
                        android:layout_gravity="right"
                        android:layout_marginRight="@dimen/lecture_voice_text_duration_margin_right"/>
                </LinearLayout>

            </RelativeLayout>

            <RelativeLayout
                android:id="@+id/layoutVoiceNotFound"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/layoutVoiceInfo"
                android:layout_marginLeft="@dimen/activity_horizontal_margin"
                android:visibility="gone">

                <ImageView
                    android:id="@+id/voiceView"
                    android:layout_width="@dimen/lecture_voice_icon"
                    android:layout_height="@dimen/lecture_voice_icon"
                    android:src="@drawable/voice_not_found"
                    android:scaleType="fitXY" />

                <TextView
                    android:id="@+id/voiceNotFound"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_toRightOf="@+id/voiceView"
                    android:layout_centerInParent="true"
                    android:text="@string/voice_not_found"
                    android:textAppearance="?android:attr/textAppearanceMedium" />
            </RelativeLayout>
        </RelativeLayout>
    </android.support.v7.widget.CardView>
</RelativeLayout>

strings.xml

<string name="min">min</string>
<string name="sec">sec</string>

注意:示例中可能会丢失一些尺寸或可绘制对象。如果没有编译,你应该使用你自己的维度。

找到解决方案。

 Runnable runnable=new Runnable() {

        @Override
        public void run() {
            String time;
            Log.d(TAG, "run");
            while(mediaPlayer != null && mediaPlayer.isPlaying()){
                final int progress = mediaPlayer.getCurrentPosition();
                int min = (progress / 1000) / 60;
                Log.d("auto","seek");
                int sec = (progress / 1000) % 60;
                if (sec < 10)
                    time = "0" + sec;
                else
                    time = "" + sec;
                final String elapsedTime = min + ":" + time + "";
                context.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        timer.setText(elapsedTime);
                        seekBar.setMax(mediaPlayer.getDuration());
                        seekBar.setProgress(progress);
                    }
                });
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    new Thread(runnable).start();

这里的主要问题是,一旦 mediaplayer.start() 被调用,媒体文件就开始在播放器中加载,然后完成 cont_seek 函数被调用,其条件为

if(mediaplayer!=null && mediaplayer.isplaying())

由于媒体还没有开始播放,条件失败,函数永远不会执行。

已通过 运行 另一个线程中的 runnable 修复了它。