SeekBar is jerky during playback - java

Basically i'm using seek bar to show to user how audio playback is going, my visual update is presented in Thread and looks like this :
#Override
public void run() {
while(mUpdating) {
if(mSeekBar != null) {
mSeekBar.setProgress(mAudioPlaybackManager.getCurrentPosition());
}
//Other stuff is updating
}
}
So, for exqample if user plays audio that's 2500 ms in length, this SeekBar max value will be 2500 and it will be updating every ms
This same code working much slower in runOnUiThread, so i'm guessing when progress is changed something like postInvalidate is called
So basically every ms, the seekbar value should be changed. I guess that's the problem here. On my device Samsung J7 it's working smoothly but on Samsung Galaxy S5 it's just stopping and jumping all the time, like if i put this code in runOnUIThread, it would be really slow.
What could i do to make it smoother? Is there another View that i can use for this pirpose?
The things that current SeekBar is doing:
Showing progress of audio basically in while(updating)
When user changes the position of SeekBar audio is starting from that point.

The thread is a worker thread and not UI's thread, you're manipulating UI component within the thread thus blocking the UI's thread.
If you want to update the seekbar, update it in UI's thread. It can be done with UI's thread handler.
For example
private Runnable updateSeekBarTime = new Runnable() {
public void run() {
//get current position
timeElapsed = mediaPlayer.getCurrentPosition();
//set seekbar progress
seekbar.setProgress((int) timeElapsed);
//repeat yourself again in 100 miliseconds
durationHandler.postDelayed(this, 100);
}
};
Executed in
public void play(View view) {
mediaPlayer.start();
while(mUpdating) {
if(mSeekBar != null) {
// post the Runnable (updateSeekBarTime)
durationHandler.postDelayed(updateSeekBarTime, 100);
}
}
}
Also updating component can't simply be done every millisecond, from user perspective, giving a bit pause won't be noticed.

Related

How to add a sleep timer to my Android app

My project is a radio app and I want to add a sleep timer so that the user can set it to close the app after a specified time.
Please use startTimer(long ms) to start countdown timer and cancel timer to stop. And use wakelock to continue timer after screen off.
CountDownTimer cTimer = null;
void startTimer(long time) {
if(!wakeLock.isHeld()) {
PowerManager mgr = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SonaHeartLock");
wakeLock.acquire();
}
cTimer = new CountDownTimer(time, 1000) {
public void onTick(long millisUntilFinished) {
timerSync = millisUntilFinished;
}
public void onFinish() {
timerSync = 0;
System.exit(0);
}
};
cTimer.start();
}
//cancel timer
void cancelTimer() {
if (cTimer != null) {
timerSync = 0;
cTimer.cancel();
cTimer=null;
if(wakeLock!=null && wakeLock.isHeld())
wakeLock.release();
}
}
Thread.sleep(2000);
will pause for 2 seconds (i.e 2000 ms). In an Android app I wrote several years ago I actually had:
Thread.currentThread().sleep(2000);
but I'm pretty sure the .currentThread() was not needed. I was just learning Java at the time.
See Oracle's doc.
In more detail, what I actually had was a separate task:
class TimerUpdater extends AsyncTask<String, String, Void>{
}
That periodically checked the time (pausing using Thread.sleep()) and displayed a countdown, and at zero set a flag that the main task periodically checked and ended the game when it saw it was set.
My app was terrible code, but I was learning both Java and Android at the same time as fast as I could, to make an app to help my kid in math class.
Android has changed a lot since then, though.
You can get the time from user and after that you can create one background process which count time everytime and check with user time. If both will match then immediately close your app

CountDownTimer freezes UI when trying to reproduce sound

I'm trying to reproduce the beep.wav sound each second from 3 to 1 , for example, reproduce 3 , 2, and 1 the beep sound, and then when finish reproduce the beependsound.
For some reason only the beependsound is playing but when reaching second 3 it seems the ui freezes for a sec and then the numbers decrease fast to 0
private void stopPlaying(){
if(mp!=null){
try {
mp.reset();
mp.prepareAsync();
mp.stop();
mp.release();
mp=null;
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
private void startCountDown() {
aCounter = new CountDownTimer(10000, 100) {
public void onTick(long millisUntilFinished) {
if (Math.round((float) millisUntilFinished / 1000.0f) != secondsLeft) {
countDownTxt.setTextColor(getResources().getColor(R.color.white));
secondsLeft = Math.round((float) millisUntilFinished / 1000.0f);
countDownTxt.setText(String.valueOf(secondsLeft));
}
if (secondsLeft <= 3) {
countDownTxt.setTextColor(getResources().getColor(R.color.colorAccent));
stopPlaying();
mp = MediaPlayer.create(MainActivity.this, R.raw.beep);
mp.start();
}
}
public void onFinish() {
secondsLeft = 0;
stopPlaying();
mp = MediaPlayer.create(MainActivity.this, R.raw.beepend);
mp.start();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
aCounter.cancel();
startCountDown();
}
}, 1000);
}
};
aCounter.start();
}
I spect this to work as described above, any hint ?
MediaPlayer.create() can be a fairly expensive call. Consider what happens if it takes approximately 100ms (or even more):
The timer calls onTick().
onTick() blocks for about 100ms inside MediaPlayer.create().
mp starts playing, and onTick() returns. (So far, so good!)
Immediately, the timer realizes another onTick() call is due! The last one started over 100ms ago!
onTick() is called again, almost immediately. Very quickly, it reaches the stopPlaying() call. But you only started playing about 1ms ago!
This leads to a situation where your timer spends all its time in MediaPlayer.create(), and almost no time actually playing the sound.
Note that, with the code as written, it will attempt to play the sound approximately 30 times in the last 3 seconds of the countdown (since the ticks are ideally 100ms apart). If your intent was to play the sound only 3 times, you may want to move your second if block to inside the first. That way, you only attempt play when secondsLeft actually changes. This will actually ameliorate the original problem, and you may not need any further changes.
But if you want to optimize further, note that you can prepare mp in advance -- say, when the app starts up -- and simply reuse it: Instead of release()-ing it each time, just stop() it, and prepare() it (and don't reset() it). That'll leave it ready for the next play. You could even create a separate MediaPlayer just for beepend, and you could prepare them both during app initialization.

How to hide View after a given time of inactivity

Basically I have a volume button that shows a hidden SeekBar when clicked, how to make the SeekBar go hidden again after 2 or 3 seconds of inactivity?
I just wanna know how can I check for how much time been spent since the SeekBar became visible without changing its progress!?
You could create a Runnable that sets the visibility of the SeekBar to invisible:
private final Runnable hideSeekBarRunnable = new Runnable() {
#Override
public void run() {
seekBar.setVisibility(View.INVISIBLE);
}
};
When the volume button is clicked, show the SeekBar and post the Runnable with a 2-3 sec delay:
seekBar.setVisibility(View.VISIBLE);
seekBar.postDelayed(hideSeekBarRunnable, 3000);
And if the SeekBar is interacted with (its progress changes), remove the pending Runnable and re-post it to reset the counter:
seekBar.removeCallbacks(hideSeekBarRunnable);
seekBar.postDelayed(hideSeekBarRunnable, 3000);

Android Countdown Timer in Broadcast receiver doesn't update TextView

I am creating application which works with SMS service and FTP networking.
If user does not establish connectivity, it will try to reconnect again in 30 seconds.
I am using CountDownTimer with TextView to inform user about time left to reconnnect.
Either it will be successful or it will start counting again.
My problem is, that if counter restarts while activity is in background or the screen is locked, TextView keeps showing number "1" (it won't update) until the timer restarts again in foreground (but updating numbers without timer restart works fine in backround or lock, I am using wakelock in my foreground service).
After counter restarts again (so it won't stop counting) while application is in foreground, everything comes back to normal, TextView updates from freezed "1" to "30" and starts counting down to "1".
I think problem will be somewhere in communication between counter thread and background activity with UI, but I don't know nothing more about it.
I tried several things like:
creating setter and getter for miliseconds and update them in each
tick, then try to update textview from onReume(), didn't work.
create local variable for TextView inside timer, initialize it inside onTick() and
try to update text from there, also didn't work.
Thanks everyone for help, I will appriciate any advices.
Part of code relative to question:
private CountDownTimer cdt = null;
private final TextView getTextView_ActivityMainMenu_Timer(){
return (TextView) findViewById(R.id.ActivityMainMenu_TextView_Timer);
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getBooleanExtra("KEY_FAILED", false)){
cdt = new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
getTextView_ActivityMainMenu_Timer().setText("" + millisUntilFinished / 1000);
}
public void onFinish() {
;
}
}
.start();
}
else
{
if(cdt != null)
cdt.cancel();
}
}
};
Finally I found solution of this problem. I didn't realize that I am unregistering the receiver in onPause() method. So I had to change it and put registration of broadcast into onResume() and unregister it only in onDestroy() method.

Showing a progressdialog in android while a large method is executed

I have a long running method that is called during onCreate, this method populates textviews so interacts with the UI, and updates maybe 70 labels (about 3-20 seconds depending on device).
I want to display a progressdialog as this method executes.
Ideally I want to fire my method on the UI thread once the Activity has been displayed and the progress is displayed, this I cannot do, the Activity won't paint until the method has finished.
I hoped to find an event which was fired after the activity was displayed, and I found the one below, but it still leaves the screen black until the method has finished.
#Override
public void onPostCreate(Bundle savedInstanceState)
I am normally a WP7 developer, and in .NET you add an event handler for onLoadComplete which is fired after the ui is displayed, but before the user has a chance to interact withthe UI, how do I do this in Android JAVA?
Thanks
Put a ProgressBar in the View.
Then in the onCreate() or onResume() method do this:
new Thread() {
public void run() {
yourLargeMethod();
}
}.start();
Now you can do this inside your method to update the progressBar
public void yourLargeMethod() {
// doSomething
...
runOnUiThread(new Runnable() {
public void run() {
// update the progress from the thread
progressBar.setProgress(x); // x is your progress, 0 <= x <= progressBar.getMax()
}
});
}

Categories

Resources