Je travaille sur une application avec enregistreur et lecteur. J'utilise mediaplayer pour lire le fichier .wav enregistré et entre-temps, je souhaite effectuer une mise à jour vers une barre de recherche. Tout fonctionne bien Mais mon problème est que la progression de Mediaplayer ne fonctionne pas correctement. Si nous lisons un petit fichier, le pouce de la barre de recherche saute en secondes ou entre.
Est-ce que n'importe qui peut m'aider avec une solution de contournement pour le rendre lisse cherchant le progrès dans seekbar. Mon code est indiqué ci-dessous. Je suis bloqué ici.
mediaPlayerIntiate();
mediaPlayerSetSource();
mMediaPlayer.start();
task = new TimerTask() {
@Override
public void run() {
Graphbar.post(new Runnable() {
@Override
public void run() {
if (mMediaPlayer != null) {
if (playButtonState == MediaMode.PLAY) {
if (mMediaPlayer.isPlaying()) {
Graphbar.setProgress(mMediaPlayer
.getCurrentPosition());
mediaPlayerUpdateTimer(mMediaPlayer
.getCurrentPosition());
enableRewindandForward();
}
}
}
}
});
}
};
timer = new Timer();
timer.schedule(task, 0, 8);
mMediaPlayer.getCurrentPosition () Renvoie l'heure actuelle en millisecondes et vous mettez à jour cette action en Seekbar dont la capacité maximale est de 100. Créez une formule avec longueur de fichier et 100. essayez cette fonction
MediaPlayer mMediaPlayer = new MediaPlayer();
final SeekBar mSeelBar = new SeekBar(this);
final int duration = mMediaPlayer.getDuration();
final int amoungToupdate = duration / 100;
Timer mTimer = new Timer();
mTimer.schedule(new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!(amoungToupdate * mSeelBar.getProgress() >= duration)) {
int p = mSeelBar.getProgress();
p += 1;
mSeelBar.setProgress(p);
}
}
});
};
}, amoungToupdate);
Et ce processus devrait être appelé lorsque le lecteur multimédia commence à jouer. à l'intérieur
mediaPlayer.setOnPreparedListener(new OnPreparedListener(){
@Override
public void onPrepared(MediaPlayer mp) {
**// call here**
});
Mettre à jour
Mettre à jour 125 fois en quelques secondes n’est pas quelque chose que vous devriez faire. Veuillez augmenter votre intervalle pour mettre à jour SeekBar. J'ajoute cela après avoir lu les commentaires de NullPointer
player.prepare(); // or start()
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.scheduleWithFixedDelay(new Runnable()
{
@Override
public void run()
{
progressBar.setProgress(player.getCurrentPosition());
}
}, 1, 1, TimeUnit.MICROSECONDS);
Voici comment je gère le seekbar;
mediaPlayer.setOnPreparedListener(new OnPreparedListener(){
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();
new SeekBarHandler().execute();
});
Maintenant, j'ai une tâche asynchrone appelée SeekBarHandler qui gère la seekbar comme ceci:
public class SeekBarHandler extends AsyncTask<Void, Void, Void> {
@Override
protected void onPostExecute(Void result) {
Log.d("##########Seek Bar Handler ################","###################Destroyed##################");
super.onPostExecute(result);
}
@Override
protected void onProgressUpdate(Void... values) {
seekBar.setProgress(mediaPlayer.getCurrentPosition());
super.onProgressUpdate(values);
}
@Override
protected Void doInBackground(Void... arg0) {
while(mediaPlayer.isPlaying()&&isViewOn==true) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
onProgressUpdate();
}
return null;
}
}
Maintenant, dans mon onPause, je termine l'AsyncTask car cela n'a pas de sens de garder le thread en cours lorsque l'utilisateur ne peut pas voir la barre de recherche
protected void onPause() {
isViewOn=false;
super.onPause();
}
Et sur onResume je commence le AsyncTaskAgain comme ceci
protected void onResume() {
isViewOn=true;
new SeekBarHandler().execute();
super.onResume();
}
Comme vous pouvez le voir, j'utilise un indicateur booléen isViewOn pour vérifier si la vue est activée ou non pour gérer la barre de recherche.
seekbar.setProgress () accepte uniquement int. Par conséquent, la plupart d’entre nous ont tendance à passer le pourcentage écoulé à cette méthode. Cependant, si vous avez besoin d'une progression beaucoup plus douce, vous pouvez utiliser la durée en millisecondes comme MAX. Ensuite, nous actualisons chaque milliseconde la progression de la barre de recherche. Vous trouverez ci-dessous un exemple que j'ai mis à jour toutes les 15 millisecondes, car presque tous les téléphones Android sont livrés avec un taux de rafraîchissement de 60 fps (images par seconde).
try{
mediaPlayer.start();
seekbar.setProgress(0);
seekbar.setMax(mediaPlayer.getDuration());
// Updating progress bar
seekHandler.postDelayed(updateSeekBar, 15);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
/**
* Background Runnable thread
* */
private Runnable updateSeekBar = new Runnable() {
public void run() {
long totalDuration = mediaPlayer.getDuration();
long currentDuration = mediaPlayer.getCurrentPosition();
// Displaying Total Duration time
remaining.setText(""+ milliSecondsToTimer(totalDuration-currentDuration));
// Displaying time completed playing
elapsed.setText(""+ milliSecondsToTimer(currentDuration));
// Updating progress bar
seekbar.setProgress((int)currentDuration);
// Call this thread again after 15 milliseconds => ~ 1000/60fps
seekHandler.postDelayed(this, 15);
}
};
/**
* Function to convert milliseconds time to
* Timer Format
* Hours:Minutes:Seconds
* */
public String milliSecondsToTimer(long milliseconds){
String finalTimerString = "";
String secondsString = "";
// Convert total duration into time
int hours = (int)( milliseconds / (1000*60*60));
int minutes = (int)(milliseconds % (1000*60*60)) / (1000*60);
int seconds = (int) ((milliseconds % (1000*60*60)) % (1000*60) / 1000);
// Add hours if there
if(hours > 0){
finalTimerString = hours + ":";
}
// Prepending 0 to seconds if it is one digit
if(seconds < 10) {
secondsString = "0" + seconds;
}else {
secondsString = "" + seconds;
}
finalTimerString = finalTimerString + minutes + ":" + secondsString;
// return timer string
return finalTimerString;
}
Le problème que vous rencontrez a à voir avec la façon dont le SeekBar d'Android est conçu/implémenté Bien que cela fonctionne très bien, vous êtes limité par une combinaison de segments utilisés (par exemple, seekbar.setMax(int)
) et par le temps de retard de votre gestionnaire.
Cela étant dit, j'ai sous-classé SeekBar pour créer mon propre SmoothSeekBar qui utilise ViewPropertyAnimators au lieu d'un gestionnaire.
Découvrez-le ici: https://github.com/Indatus/Android-SmoothSeekBar