I made these two method to update seekbar every 100ms:
public void updateSeekBar() {
handler.postDelayed(mUpdateTimeTask, 100);
}
private Runnable mUpdateTimeTask = new Runnable() {
#Override
public void run() {
mySeekBar.setMax(mySong.getDuration());
x = mySong.getCurrentPosition();
mySeekBar.setProgress(x);
handler.postDelayed(this, 100);
}
};
and put it inside my playMusic method:
public void playMusic() {
//just a test from intent.getExtra
if(test.equalsIgnoreCase("Jason Mraz")) {
mySong = MediaPlayer.create(MusicClass.this, jm[musicCounter]);
displaySong(jm);
songNumbers = jm.length;
}else if(test.equalsIgnoreCase("fob")) {
mySong = MediaPlayer.create(MusicClass.this, fob[musicCounter]);
displaySong(fob);
songNumbers = fob.length;
}else if(test.equalsIgnoreCase("ed")) {
mySong = MediaPlayer.create(MusicClass.this, ed[musicCounter]);
displaySong(ed);
songNumbers = ed.length;
}
//when the song is completed
mySong.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
nextSong();
}
});
//seekbar update
mySeekBar.setMax(mySong.getDuration());
mySeekBar.setProgress(0);
mySong.start();
updateSeekBar();
}
this is my onCreate method:
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.music);
artistName = (TextView)findViewById(R.id.artistName);
song = (TextView)findViewById(R.id.song);
musicCounter = 0;
ifPlaying = true;
isRandom = false;
random = (ImageButton) findViewById(R.id.random);
stop = (ImageButton)findViewById(R.id.stop);
myImageView = (ImageView)findViewById(R.id.myImageView);
dice = new Random();
mySeekBar = (SeekBar)findViewById(R.id.mySeekBar);
test = getIntent().getStringExtra("test");
if(test.equalsIgnoreCase("Jason Mraz")) {
artistName.setText("Jason Mraz");
displayPP();
songNumbers = jm.length;
myImageView.setImageResource(R.drawable.jason_mraz);
} else if (test.equalsIgnoreCase("fob")) {
artistName.setText("Fall Out Boys");
displayPP();
songNumbers = fob.length;
myImageView.setImageResource(R.drawable.fall_out_boys);
} else if (test.equalsIgnoreCase("ed")) {
artistName.setText("Ed Sheeran");
displayPP();
songNumbers = ed.length;
myImageView.setImageResource(R.drawable.ed_sheeran);
}
playMusic();
mySeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if (b) {
mySong.seekTo(i);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
mySong.pause();
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (ifPlaying == true) {
mySong.start();
} else {
return;
}
}
});
}
My application says Unfortunately stopped. But when I remove the updateSeekbar in playMusic method it works fine, but without the updating seekBar every second. The setOnSeekBarChangeListener works perfectly fine, the only problem is I can't make updateSeekBar method work because it is alwats stopping my application and force exit.
The symptoms you are describing is called an ANR. It means that you is doing to much work in the main thread.
What you need todo is review what you are triggering in your mUpdateTimeTask.
Next make sure your handler is running on the UI since your are updating views:
Handler handler = new Handler(Looper.getMainLooper());
Related
I am playing mp3 file from url, but SeekBar is not updating while playing song.
It showing a buffering but not moving automatically when song starts.
When i am trying to move forcefully then also it working fine.
Below code i am using to play and update SeekBar.
I wanted to create a seekBar that track the progress of a mediaplayer but it doesnt work out quite well, the music is playing but the seekbar stay idle. Is there something that I left out?
Please help me i am new in android.
public class XYZ extends Fragment implements MediaPlayer.OnBufferingUpdateListener,MediaPlayer.OnCompletionListener{
private SeekBar seekBar;
private MediaPlayer mediaPlayer;
private int mediaFileLength;
final Handler handler = new Handler();
private int realtimeLength;
Button b,b3,b4;
private double startTime = 0;
private double finalTime = 0;
public static int oneTimeOnly = 0;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_outside, container,
false);
rootView.setBackgroundResource(R.drawable.jotirling);
seekBar = rootView.findViewById(R.id.seekbar);
seekBar.setMax(99); // 100% (0~99)
seekBar.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (mediaPlayer.isPlaying()) {
SeekBar seekBar = (SeekBar) v;
int playPosition = (mediaFileLength / 100) * seekBar.getProgress();
mediaPlayer.seekTo(playPosition);
}
return false;
}
});
b3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final ProgressDialog mDialog = new ProgressDialog(getActivity());
#SuppressLint("StaticFieldLeak") AsyncTask<String, String, String> mp3Play = new AsyncTask<String, String, String>() {
#Override
protected void onPreExecute() {
mDialog.setMessage("Please wait It will take time according to your network speed...!");
mDialog.show();
mDialog.setCancelable(false);
}
#Override
protected String doInBackground(String... params) {
try {
mediaPlayer.setDataSource(params[0]);
mediaPlayer.prepare();
} catch (Exception ignored) {
}
return "";
}
#Override
protected void onPostExecute(String s) {
mediaFileLength = mediaPlayer.getDuration();
realtimeLength = mediaFileLength;
if (!mediaPlayer.isPlaying()) {
p=1;
mediaPlayer.start();
Toast.makeText(getActivity(), "Playing sound", Toast.LENGTH_SHORT).show();
finalTime = mediaPlayer.getDuration();
startTime = mediaPlayer.getCurrentPosition();
b3.setBackgroundResource(R.drawable.pp);
if (oneTimeOnly == 0) {
oneTimeOnly = 1;
}
} else {
p=0;
mediaPlayer.pause();
Toast.makeText(getActivity(), "Pausing "+
"sound",Toast.LENGTH_SHORT).show();
b3.setBackgroundResource(R.drawable.p);
}
updateSeekBar();
mDialog.dismiss();
}
};
mp3Play.execute("URL"); // direct link mp3 file
}
});
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnCompletionListener(this);
return rootView;
}
private void updateSeekBar() {
seekBar.setProgress((int) (((float) mediaPlayer.getCurrentPosition() / mediaFileLength) * 100));
if (mediaPlayer.isPlaying()) {
Runnable updater = new Runnable() {
#Override
public void run() {
updateSeekBar();
}
};
}
}
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
seekBar.setSecondaryProgress(percent);
}
}
You should consider using setOnSeekbarChangeListener()
Reference : setOnSeekBarChangeListener()
Simple example would be
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {
// TODO Auto-generated method stub
if(fromUser){
//do your things, like updating time durations etc.
}
}
});
Also if u a want working example, look at this link for code (i have just used circularSeekbar instead of regular one) https://github.com/iamSahdeep/Bop/blob/master/app/src/main/java/com/sahdeepsingh/Bop/Activities/PlayerView.java#L324
More Examples : https://www.javatips.net/api/android.widget.seekbar.onseekbarchangelistener
You can create use Timer for this:
seekBar.setMax(mediaPlayer.getDuration());
new Timer().scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
seekBar.setProgress(mediaPlayer.getCurrentPosition());
}
},0,1000);
You are defining Runnable updater but not calling it.
if (mediaPlayer.isPlaying()) {
Runnable updater = new Runnable() {
#Override
public void run() {
updateSeekBar();
}
};
seekBar.post(updater)
}
I am writing code for a music player and everything seems to be working fine except the ActionBar. When a song is playing, a thread probes the service every second for a change in the song and if there is a change in the song, a handler object changes the UI elements.
final Handler uiHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle data = msg.getData();
song = data.getParcelable("song_info");
songText.setText(song.getSongTitle());
artistText.setText(song.getSongArtist());
seekBar.setMax(mService.getDuration()/1000); //All these work
assert getSupportActionBar() != null;
getSupportActionBar().setTitle(mService.getSongName()); //Not updating
super.handleMessage(msg);
}
};
What this does is when there is a message from the thread, it updates the UI. I can confirm that this works and is invoked when I need it to. All the text views and the seekbar get updated as required. However, the getSupportActionBar().setTitle(...) doesn't update the title bar.
The same method of setting action bar title works if I do it in other methods of the same class. Am I missing something here?
Thanks in advance!
Update:
Here's some more code that the Activity has, in case it helps strike something.
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
MusicService.MusicBinder mBinder = (MusicService.MusicBinder)iBinder;
mService = mBinder.getService();
pauseBtn = (ImageButton)findViewById(R.id.pause);
seekBar.setMax(mService.getDuration()/1000);
CounterThread cThread = new CounterThread();
Thread counter = new Thread(cThread);
counter.start();
if(mService.isPaused()) {
pauseBtn.setImageResource(R.drawable.ic_play_arrow_white_36dp);
}
else {
pauseBtn.setImageResource(R.drawable.ic_pause_white_36dp);
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
private class CounterThread implements Runnable {
#Override
public void run() {
while(true) {
try {
if(!mService.getSongName().equals(song.getSongTitle())) //This is invoked when there is a change in the song.{
Message msg = uiHandler.obtainMessage();
Bundle b = new Bundle();
b.putParcelable("song_info", mService.getSong());
msg.setData(b); //I receive this message in the handler
uiHandler.sendMessage(msg);
}
seekBar.setProgress(mService.getCurrPosn()/1000);
Thread.sleep(1000);
} catch (Exception e){
e.printStackTrace();
}
}
}
}
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song_playing);
song = getIntent().getParcelableExtra("song_info");
songText = (TextView) findViewById(R.id.songname);
artistText = (TextView) findViewById(R.id.artistname);
songText.setText(song.getSongTitle());
artistText.setText(song.getSongArtist());
header = getSupportActionBar();
seekBar = (SeekBar)findViewById(R.id.seekBar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
// Do nothing
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// Do nothing
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
mService.seek(progress*1000);
}
});
assert header != null;
header.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
header.setCustomView(R.layout.head_layout);
titleText = (TextView) findViewById(R.id.titleText);
titleText.setText(song.getSongTitle());
}
/*
More operations
*/
public void next(View v) {
mService.nextSong();
pauseBtn.setImageResource(R.drawable.ic_pause_white_36dp);
assert header != null;
header.setTitle(mService.getSongName()); // This works fine
songText.setText(mService.getSongName());
artistText.setText(mService.getArtistName());
titleText.setText(mService.getSongName());
seekBar.setMax(mService.getDuration()/1000);
}
Don't mind the slight indentation offset.
how are you supposed to let the mediaplayer know what it is supposed to play?
wholeTextPlayer = MediaPlayer.create(Lesson1Reading.this, engAu);
It works fine if I declare the file in the top:
MediaPlayer wholeTextPlayer;
private int engAu = R.raw.l1r_en_l10;
Button btn_default_acc_whole;
It doesn't work from within a button click if / else statement wherever I try to put it with the following combination:
MediaPlayer wholeTextPlayer;
private int engAu;
Button btn_default_acc_whole;
The button click:
final Button btn_default_acc_whole = (Button) findViewById(R.id.btn_default_acc_whole);
btn_default_acc_whole.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
if (wholeTextPlayer.isPlaying()) {
wholeTextPlayer.pause();
} else {
wholeTextPlayer.start();
startPlayProgressUpdater();
}
setEngAu(R.raw.l1r_en_l10); //this line doesn't want to fit anywhere
}
});
The setter:
public void setEngAu(int engAu) {
this.engAu = engAu;
}
Of course they are separately placed in the activity, I just copied and pasted the relevant bits from it.
Thanks guys.
Here is the whole code:
'public class Lesson1Grammar extends Activity {
private SeekBar seekBar;
MediaPlayer wholeTextPlayer;
private int engAu;
private final Handler handler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lesson1grammar);
WholeDefAccPlayer();
final RelativeLayout playerScreen = (RelativeLayout)findViewById(R.id.playerScreen);
final ImageButton btn_player_screen = (ImageButton) findViewById(R.id.btn_player_screen);
btn_player_screen.setOnClickListener(new View.OnClickListener() {
//this hides/unhides the part of the layout in which the player is
#Override
public void onClick(View arg0) {
if (playerScreen.isShown()) {
playerScreen.setVisibility(View.GONE);
} else {
playerScreen.setVisibility(View.VISIBLE);
}
}
});
final Button btn_default_acc_whole = (Button) findViewById(R.id.btn_default_acc_whole);
btn_default_acc_whole.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
if (wholeTextPlayer.isPlaying()) {
wholeTextPlayer.pause();
} else {
setEngAu(R.raw.default_acc_audio);
wholeTextPlayer.start();
startPlayProgressUpdater();
}
}
});
}
public void setEngAu(int engAu) {
this.engAu = engAu;
}
private void WholeDefAccPlayer() {
wholeTextPlayer = MediaPlayer.create(Lesson1Grammar.this, engAu);
((TextView) findViewById(R.id.getTitleOfAccent)).setText(R.string.btn_lesson1reading);
seekBar = (SeekBar) findViewById(R.id.seekBar);
seekBar.setMax(wholeTextPlayer.getDuration());
seekBar.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
seekChange(v);
return false;
}
});
}
public void startPlayProgressUpdater() {
seekBar.setProgress(wholeTextPlayer.getCurrentPosition());
if (wholeTextPlayer.isPlaying()) {
Runnable notification = new Runnable() {
public void run() {
startPlayProgressUpdater();
}
};
handler.postDelayed(notification, 1000);
}
else wholeTextPlayer.pause();
}
// This is event handler thumb moving event
private void seekChange(View v){
if(wholeTextPlayer.isPlaying()){
SeekBar sb = (SeekBar)v;
wholeTextPlayer.seekTo(sb.getProgress());
}
}
}
'
if your plan is to make the method setEngAu() is the controller as you mentioned in the comment. then you you need to use that method like this
public void setEngAu(int enAu)
{
this.EngAu = enAu;
wholeTextPlayer.setDataSource(engAu);
wholeTextPlayer.prepare();
}
you need to implement onPrepared listener from the media player
I do not know your classes but I assume where you say something like;
wholeTextPlayer = new MediaPlayer();
wholeTextPlayer.setOnPreparedListener(this);
here you start the player after it became prepared
public void onPrepared(MediaPlayer player)
{
player.start();
}
Remember to you will need to call wholeTextPlayer.release() if you do not want the player to hold on that resource anymore( think of it as memory issues - recommended if you check the documentation)
EDIT :
I adjusted your code a little, please take a look and let me know.
private SeekBar seekBar;
MediaPlayer wholeTextPlayer;
private int engAu;
final Handler handler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.lesson1grammar);
WholeDefAccPlayer();
final RelativeLayout playerScreen = (RelativeLayout) findViewById(R.id.playerScreen);
final ImageButton btn_player_screen = (ImageButton) findViewById(R.id.btn_player_screen);
btn_player_screen.setOnClickListener(new View.OnClickListener()
{
//this hides/unhides the part of the layout in which the player is
#Override
public void onClick(View arg0)
{
if(playerScreen.isShown())
{
playerScreen.setVisibility(View.GONE);
}
else
{
playerScreen.setVisibility(View.VISIBLE);
}
}
});
final Button btn_default_acc_whole = (Button) findViewById(R.id.btn_default_acc_whole);
btn_default_acc_whole.setOnClickListener(new View.OnClickListener()
{
public void onClick(View arg0)
{//problem here is
if(playerState == PlayerState_Playing)
{
wholeTextPlayer.pause();
setPlayerState(PlayerState_Paused);
}
else if(playerState == PlayerState_Paused)
{
wholeTextPlayer.start();
setPlayerState(PlayerState_Playing);
}
else
{
setEngAu(R.raw.default_acc_audio);
wholeTextPlayer.start();
startPlayProgressUpdater();
setPlayerState(PlayerState_Playing);
}
}
});
}
public void setEngAu(int engAu)
{
this.engAu = engAu;
if(wholeTextPlayer !=null)
{//just in case you call this method and player was not initialized yet
wholeTextPlayer.release();
}
setPlayerState(PlayerState_Preparing);
wholeTextPlayer = MediaPlayer.create(this, engAu);
}
private void WholeDefAccPlayer()
{
//this line probably will fail because engAu is not really initialized yet, unless you have default value for it
wholeTextPlayer = MediaPlayer.create(this, engAu);
((TextView) findViewById(R.id.getTitleOfAccent)).setText(R.string.btn_lesson1reading);
seekBar = (SeekBar) findViewById(R.id.seekBar);
//you can not call getDuration unless the player is prepared, so this might crash you
// seekBar.setMax(wholeTextPlayer.getDuration());
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b)
{
if(playerState != PlayerState_Preparing)
{//if player state is preparing it means we can not seek yet, player.start() must be called first
wholeTextPlayer.seekTo(i);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar)
{
}
#Override
public void onStopTrackingTouch(SeekBar seekBar)
{
}
});
}
public void startPlayProgressUpdater()
{
if(seekBar.getMax() != wholeTextPlayer.getDuration())
{//in case you change track later, this will check if the seek bar max value with track duration.
// if they are not the same, then it will adjust it for you
seekBar.setMax(wholeTextPlayer.getDuration());
}
seekBar.setProgress(wholeTextPlayer.getCurrentPosition());
if(wholeTextPlayer.isPlaying())
{
Runnable notification = new Runnable()
{
public void run()
{
startPlayProgressUpdater();
}
};
handler.postDelayed(notification, 1000);
}
else wholeTextPlayer.pause();
}
// This is event handler thumb moving event
private void seekChange(View v)
{
if(wholeTextPlayer.isPlaying())
{
SeekBar sb = (SeekBar) v;
wholeTextPlayer.seekTo(sb.getProgress());
}
}
private final int PlayerState_Preparing = 0;
private final int PlayerState_Playing = 1;
private final int PlayerState_Paused = 2;
private int playerState;
private void setPlayerState(int state)
{//this is used to track the player state, because wholeTextPlayer.isPlaying() can return false in many conditions ( too general )
//you can check in the media player documentation to know more details about this
playerState = state;
}
I've done a little with android in the past, but this is the first time I've touched it in over a year and I've been stuck on this problem since yesterday.
I'm working on a project with someone and I need to play a sound a certain number of times at set intervals. (For example, play once after one minute, twice after two minutes, three times after three minutes, and on and on). I can get the sound to play at whatever interval, that's not an issue, but I can't figure out how to get it to play the correct number of times at each interval. It either ends up looping infinitely, playing once each time the interval is up or playing once and stopping.
Tried TimerTask, switched to Handler/Runnable, tried using a for loop and using an if statement with counter. After two evenings of multiple attempts, hours of research and my limited experience, this is the one problem I've run into that I haven't been able to figure out.
Here's the code I've currently got in for this particular feature. I'm having issues with the Runnable tenMinChime and OnCompletionListener chimeCompletion. Any guidance at all is very appreciated.
public class MainActivity extends AppCompatActivity {
TextView chimeOn, chimeOff;
Handler chimeHandler = new Handler();
MediaPlayer.OnCompletionListener chimeCompletion;
MediaPlayer cp;
int chimeCount = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (screen == 1) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
setContentView(R.layout.activity_main);
chimeOn = (TextView) findViewById(R.id.chimeOn);
chimeOff = (TextView) findViewById(R.id.chimeOff);
chimeOn.setTextColor(0xFFbebebe);
chimeOff.setTextColor(0xFF000000);
cp = MediaPlayer.create(this, R.raw.placeholder_chime);
chimeOn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (chime == 0) {
chimeOn.setTextColor(0xFF000000);
chimeOff.setTextColor(0xFFbebebe);
handler2.postDelayed(tenMinChime, 5000);
chime = 1;
}
}
});
chimeOff.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (chime == 1) {
chimeOff.setTextColor(0xFF000000);
chimeOn.setTextColor(0xFFbebebe);
handler2.removeCallbacks(tenMinChime);
chime = 0;
}
}
});
chimeCompletion = new MediaPlayer.OnCompletionListener() {
int count = 0;
int maxCount = chimeCount;
#Override
public void onCompletion(MediaPlayer mp) {
if(count < maxCount) {
count++;
cp.seekTo(0);
cp.start();
cp.setOnCompletionListener(chimeCompletion);
}
}
};
public Runnable tenMinChime = new Runnable() {
public void run() {
chimeCount+=1;
cp.start();
cp.setOnCompletionListener(chimeCompletion);
}
};
Maybe this solves your issue ?
public class MainActivity extends AppCompatActivity {
TextView chimeOn, chimeOff;
Handler handler2 = new Handler();
MediaPlayer.OnCompletionListener chimeCompletion;
MediaPlayer cp;
int chimeCount = 0;
int mPlayCount=0;
int mMaxPlayCount=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (screen == 1) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
setContentView(R.layout.activity_main);
chimeOn = (TextView) findViewById(R.id.chimeOn);
chimeOff = (TextView) findViewById(R.id.chimeOff);
chimeOn.setTextColor(0xFFbebebe);
chimeOff.setTextColor(0xFF000000);
cp = MediaPlayer.create(this, R.raw.placeholder_chime);
chimeOn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (chime == 0) {
chimeOn.setTextColor(0xFF000000);
chimeOff.setTextColor(0xFFbebebe);
handler2.postDelayed(tenMinChime, 5000);
chime = 1;
}
}
});
chimeOff.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (chime == 1) {
chimeOff.setTextColor(0xFF000000);
chimeOn.setTextColor(0xFFbebebe);
handler2.removeCallbacks(tenMinChime);
cp.setOnCompletionListener(null);
chime = 0;
mMaxPlayCount=0;
mPlayCount=0;
}
}
});
chimeCompletion = new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
if(mPlayCount < mMaxPlayCount) {
mPlayCount++;
cp.seekTo(0);
cp.start();
}
}
};
public Runnable tenMinChime = new Runnable() {
public void run() {
mPlayCount=0;
mMaxPlayCount= 3;
cp.setOnCompletionListener(chimeCompletion);
cp.start();
}
};
friends I am developing an application which is playing small mp3 soundtracks (podcasts). Now my code which I am showing below is working on Android 3.2 as it should. But on Android 4.1.2 the SeekBar is not being updated by the handler instance. I have read about a bug in the SeekBar causing this issue but it should be fixed since Android 3.2. Any help or advice would be appreciated. Here is my code:
public class PodcastDetailFragment extends BaseFragment {
private MediaPlayer mediaPlayer = null;
private Button playPauseButton = null;
private SeekBar seekBar = null;
private TextView timeView = null;
private int totalDuration = 0;
private Bundle data;
private Handler handler=new Handler();
private Runnable runnable = new Runnable() {
public void run() {
int progress = mediaPlayer.getCurrentPosition();
seekBar.setProgress(progress);
int hours = ((progress/1000)/60)/60;
int minutes = ((progress/1000)/60)%60;
int seconds = ((progress/1000)%60)%60;
String hoursString = (hours<10)?"0":"";
String minutesString = (minutes<10)?"0":"";
String secondsString = (seconds<10)?"0":"";
timeView.setText(hoursString+hours+":"+minutesString+minutes+":"+secondsString+seconds);
handler.postDelayed(this, 100);
}
};
public static PodcastDetailFragment newInstance(Bundle bundle) {
PodcastDetailFragment f = new PodcastDetailFragment();
f.setArguments(bundle);
return f;
}
/**
* When creating, retrieve this instance's number from its arguments.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
data = getArguments();
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
getView().findViewById(R.id.preparing_track_progress_bar).setVisibility(View.VISIBLE);
super.onActivityCreated(savedInstanceState);
}
#Override
public void onPause() {
super.onPause();
if (mediaPlayer != null) {
LogUtils.d("Podcast MediaPlayer", "stop() inside the onPause() was called");
mediaPlayer.stop();
}
}
#Override
public void onDestroy() {
LogUtils.d("Podcast MediaPlayer", "release() was called");
mediaPlayer.release();
super.onDestroy();
}
/**
* The Fragment's UI is just a simple text view showing its instance number.
*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.podcasts_details, container, false);
TextView dv = (TextView) v.findViewById(R.id.durationView);
dv.setText(data.getString("duration"));
timeView = (TextView) v.findViewById(R.id.timeView);
timeView.setText("00:00:00");
playPauseButton = (Button) v.findViewById(R.id.playPauseButtonView);
playPauseButton.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
playPauseButton.setText(getResources().getString(
R.string.play));
} else {
mediaPlayer.start();
playPauseButton.setText(getResources().getString(
R.string.pause));
}
}
});
seekBar = (SeekBar) v.findViewById(R.id.seekBarView);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public void onStopTrackingTouch(SeekBar seekBar) {
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if (fromUser) {
mediaPlayer.seekTo(progress);
}
}
});
mediaPlayer =new MediaPlayer();
mediaPlayer
.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
totalDuration = mp.getDuration();
seekBar.setMax(totalDuration);
playPauseButton.setEnabled(true);
try{
getView().findViewById(R.id.preparing_track_progress_bar).setVisibility(View.INVISIBLE);
}catch(Exception ex){
ex.printStackTrace();
}
handler.postDelayed(runnable, 100);
}
});
mediaPlayer.setDataSource(Uri.parse(data.getString("podcast_url")).toString());
playPauseButton.setEnabled(false);
mediaPlayer.prepareAsync();
return v;
}
}
You should either use an AsyncTask or a Service (in case the music will play in background) instead of a Worker Thread with a Handler. The AsyncTask is extremely useful with it's onProgressUpdate method, you can use it to update the Bar based on the progress of the audio file.
Here's a basic example of an AsyncTask and how you should use it:
private class TestAsyncTask extends AsyncTask<Void, Integer, Void> {
#Override
protected Void doInBackground(Void... arg0) {
for(int i=0; i<songDuration; i++){
doSomething();
publishProgress(i);
}
return null;
}
#Override
protected void onProgressUpdate(Integer... progress) {
//UPDATE BAR
}
#Override
protected void onPostExecute(Void result) {
//DO SOMETHING WHEN FINISHED PLAYING
}
}
Anyway, here's the official doc: http://developer.android.com/reference/android/os/AsyncTask.html
I have solved this problem. The SeekBar was ok. It was just the issue that the lenght of a track is only given when you download the whole track. So to show the progress on a SeekBar properly you need to know the length of a track. So you take the length of a track and then call seekBar.setMax(lenghtOfTrack) and the progress is updated as it should by the method setProgress(progress).