I need progress bar witch position depends on two timestamp values in millis, so it depends on future timestamp, past timestamp and current timestamp.
For example, I have timestamp of 08:46:11 30.06.2019 and 10:46:11 30.06.2019. But current time is 09:46:11 30.06.2019, so now progressbar should be filled on 50% and going up to 100 until 10:46:11 30.06.2019
I have tried the next code but now I have understood that using CountDownTimer is useless and it is not for my task which described above:
private void progressBar(){
prBar.setProgress(i);
mCountDownTimer=new CountDownTimer(ltimestampStop * 1000,ltimestampStart * 1000) {
#Override
public void onTick(long millisUntilFinished) {
Log.v("Log_tag", "Tick of Progress"+ i+ millisUntilFinished);
i++;
int Start = ltimestampStart.intValue();
int Stop = ltimestampStop.intValue();
prBar.setProgress((int)i*100/(Stop/Start));
}
#Override
public void onFinish() {
//Do what you want
i++;
prBar.setProgress(100);
}
};
mCountDownTimer.start();
}
So what should I done for creating progressbar on certain position which depends on future time, past time and present time?
You can try to following:
long startTimeInMillis = ...; // 08:46:11 30.06.2019
long stopTimeInMillis = ...; // 10:46:11 30.06.2019
long currentTimeInMillis = ...; // 09:46:11 30.06.2019
long totalTimeInMilis = stopTimeInMillis - startTimeInMillis;
// Standart logic
long remainingTimeInMillis = stopTimeInMillis - currentTimeInMillis;
// But this line assures remaining time is not greater than total time
long remainingTimeInMillis = currentTimeInMillis < startTimeInMillis ?
totalTimeInMilis : stopTimeInMillis - currentTimeInMillis;
// Update every second
long countDownIntervalInMillis = 1000;
// Alternatively you can adjust interval such that it is called only in integer percent changes
int remainingSteps = (int) (((double) remainingTimeInMillis / totalTimeInMilis) * 100);
long countDownIntervalInMillis = remainingTimeInMillis / remainingSteps;
mCountDownTimer = new CountDownTimer(remainingTimeInMillis, countDownIntervalInMillis) {
#Override
public void onTick(long millisUntilFinished) {
int completedPercent = (int) ((1 - (double) millisUntilFinished / totalTimeInMilis) * 100);
prBar.setProgress(completedPercent);
}
#Override
public void onFinish() {
// Do what you want
prBar.setProgress(100);
}
};
mCountDownTimer.start();
Related
I have coded an android app using android download manager, and I try to show downloading progress using below code.
myTimer.schedule(new TimerTask() {
public void run() {
try {
DownloadManager.Query q;
q = new DownloadManager.Query();
q.setFilterById(preferenceManager.getLong(strPref_Download_ID, 0));
cursorTimer = downloadManager.query(q);
cursorTimer.moveToFirst();
int bytes_downloaded = cursorTimer.getInt(cursorTimer.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
bytes_total = cursorTimer.getInt(cursorTimer.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
final int dl_progress = (int) ((double) bytes_downloaded * 100f / (double) bytes_total);
mProgressDialog.setProgress((int) dl_progress);
} catch (Exception e) {
} finally {
}
}
}, 0, 10);
Everthing is working fine, but progress dialog is not showing smooth pregress that means I wish to show 1,2,3,4,5,6,.....100.
It's show initially 0, and suddenly change to 12% then 31% etc 100%.
My file Total size is 26246026 bytes, at the time of 0% my downloaded file size is 6668 bytes,
at the time of 12% my downloaded file size is 3197660 bytes, and etc...
First of all don't query too frequent it may hang your UI and use ValueAnimator for changing progress smoothly.
myTimer.schedule(new TimerTask() {
public void run() {
try {
DownloadManager.Query q;
q = new DownloadManager.Query();
q.setFilterById(preferenceManager.getLong(strPref_Download_ID, 0));
cursorTimer = downloadManager.query(q);
cursorTimer.moveToFirst();
int bytes_downloaded = cursorTimer.getInt(cursorTimer.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
bytes_total = cursorTimer.getInt(cursorTimer.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
final int dl_progress = (int) ((double) bytes_downloaded * 100f / (double) bytes_total);
changeProgressSmoothly((int) dl_progress);
} catch (Exception e) {
} finally {
}
}
}, 0, 5000);
private void changeProgressSmoothly(int progress) {
ValueAnimator va = ValueAnimator.ofInt(mProgressDialog.getProgress(), progress);
int mDuration = 2000; //in millis
va.setDuration(mDuration);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
mProgressDialog.setProgress((int) animation.getAnimatedValue());
}
});
va.start();
}
From documentation,
public void schedule (TimerTask task, long delay, long period)
Schedule a task for repeated fixed-delay execution
after a specific delay.
Parameters
task - the task to schedule.
delay - amount of time in milliseconds before first execution.
period - amount of time in milliseconds between subsequent executions.
Here, you have a period of 10 millis in your code. That might be the problem. Try 1 millis instead.
myTimer.schedule(new TimerTask() {
}, 0, 1);
I´m using a Chronometer in my Android App. I can start it, stop it and continue counting after pushing the start button again:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_projektbeschreibung, container, false);
if (savedInstanceState != null){
stoppedmillis = savedInstanceState.getLong(STATE_TIME);
hh = savedInstanceState.getString(STATE_HH);
mm = savedInstanceState.getString(STATE_MM);
ss = savedInstanceState.getString(STATE_SS);
}
mChronometer = (Chronometer) rootView.findViewById(R.id.chronometer2);
mChronometer.setText(hh + ":" + mm + ":" + ss);
mChronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
#Override
public void onChronometerTick(Chronometer cArg) {
long time = SystemClock.elapsedRealtime() - cArg.getBase() ;
int h = (int) (time / 3600000);
int m = (int) (time - h * 3600000) / 60000;
int s = (int) (time - h * 3600000 - m * 60000) / 1000;
hh = h < 10 ? "0" + h : h + "";
mm = m < 10 ? "0" + m : m + "";
ss = s < 10 ? "0" + s : s + "";
cArg.setText(hh + ":" + mm + ":" + ss);
}
});
((Button) rootView.findViewById(R.id.startbutton)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//if first start
if(stoppedmillis == 0) {
mChronometer.setBase(SystemClock.elapsedRealtime());
} else {//Point A
long pausetime = (SystemClock.elapsedRealtime() - stoppedmillis);
mChronometer.setBase(mChronometer.getBase() + pausetime);
}
mChronometer.start();
}
});
((Button) rootView.findViewById(R.id.stopbutton)).setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
mChronometer.stop();
stoppedmillis = SystemClock.elapsedRealtime();
}
});
After a screen rotation (so the Activity restarts) the chronometer starts counting from the point of 00:00:00 again. My first try was to save the stoppedmillis with a onSaveInstanceState method like the following:
public void onSaveInstanceState(Bundle savedInstanceState){
savedInstanceState.putLong(STATE_TIME, stoppedmillis);
savedInstanceState.putString(STATE_HH, hh);
savedInstanceState.putString(STATE_MM, mm);
savedInstanceState.putString(STATE_SS,ss);
super.onSaveInstanceState(savedInstanceState);
}
Now, I can get the value of the stoppedmillis after a restart, but I don't know how to set the Base for the Chronometer with the help of the stoppedmillis. At Point A in the Code you can see how it works with stopping the Chronometer with a button but this part of code does not working after a screen rotation.
I know that this is old. Although, I have created a simple application using a chronometer and done the following and it has kept counting across screen rotation. It is spot on with Andrew's original answer. Here is how I outlined it:
Chronometer mChronometer; // this is a global variable
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mChronometer = (Chronometer)findViewById(R.id.chronometer);
if(savedInstanceState != null){
mChronometer.setBase(savedInstanceState.getLong("ChronoTime"));
mChronometer.start();
}
}
Now set up onSaveInstanceState:
#Override
public void onSaveInstanceState (Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putLong("ChronoTime", mChronometer.getBase());
}
Fast solution, using this class:
https://github.com/ahmedrizwan/ChronometerPersist/blob/master/chronometerpersist/src/main/java/library/minimize/com/chronometerpersist/ChronometerPersist.java
ChronometerPersist chronometerPersist = ChronometerPersist.getInstance(chronometer, sharedPreferences);
//Starting the chronometer
startChronometer();
//Stoping the chronometer
stopChronometer();
//Pausing the chronometer
pauseChronometer();
I have lost much time trying to restore the current time with the android chronometer widget.
This is how i solved saving the state of the Chronometer.
private static final int TIME_MULTIPLIER = 60;
Step 1: Convert time to Seconds:
NOTE: If you don't like my method of converting time to second you could do your ways.
private static int convertTimeToSeconds(Long... time) {
int seconds = 0;
if (time.length == 2) {
seconds += time[0] * TIME_MULTIPLIER + time[1];
} else if (time.length == 3) {
seconds += (time[0] * TIME_MULTIPLIER) + (time[1] * TIME_MULTIPLIER) + (time[2]);
}
return seconds;
}
Step 2: Setting and starting time of Chronometer
NOTE: I'm saving the data in a custom object persist that object with any database / SharedPreference / your wish.
public static void setAndStartTime(final Chronometer chronometer) {
long second = 0;
// i have multiple time saved into map. You could save just 1 time and reuse that time.
for (DailyData data : DailyData.DailyDataHolder.getDailyDataMap().values()) {
second += data.getDailyTimeSpent();
}
chronometer.setBase(SystemClock.elapsedRealtime() - (second * 1000));
chronometer.start();
}
Step 3: Saving Time:
public static void saveTime(String timeText) {
String[] timeParts = timeText.split("[:]");
long savedTime = 0;
if (timeParts.length == 2) {
savedTime = convertTimeToSeconds(Long.parseLong(timeParts[0]), Long.parseLong(timeParts[1]));
} else if (timeParts.length == 3) {
savedTime = convertTimeToSeconds(Long.parseLong(timeParts[0]), Long.parseLong(timeParts[1]), Long.parseLong(timeParts[2]));
}
DailyData.DailyDataHolder.getDailyData().setDailyTimeSpent(savedTime);
}
Calling the saved method:
ChronoHelper.saveTime(chronometer.getText().toString());
COMPLETE CLASS:
public class ChronoHelper {
private static final int TIME_MULTIPLIER = 60;
public static void setAndStartTime(final Chronometer chronometer) {
long second = 0;
for (DailyData data : DailyData.DailyDataHolder.getDailyDataMap().values()) {
second += data.getDailyTimeSpent();
}
chronometer.setBase(SystemClock.elapsedRealtime() - (second * 1000));
chronometer.start();
}
public static void saveTime(String timeText) {
String[] timeParts = timeText.split("[:]");
long savedTime = 0;
if (timeParts.length == 2) {
savedTime = convertTimeToSeconds(Long.parseLong(timeParts[0]), Long.parseLong(timeParts[1]));
} else if (timeParts.length == 3) {
savedTime = convertTimeToSeconds(Long.parseLong(timeParts[0]), Long.parseLong(timeParts[1]), Long.parseLong(timeParts[2]));
}
DailyData.DailyDataHolder.getDailyData().setDailyTimeSpent(savedTime);
}
private static int convertTimeToSeconds(Long... time) {
int seconds = 0;
if (time.length == 2) {
seconds += time[0] * TIME_MULTIPLIER + time[1];
} else if (time.length == 3) {
seconds += (time[0] * TIME_MULTIPLIER) + (time[1] * TIME_MULTIPLIER) + (time[2]);
}
return seconds;
}
public static String secondsToTimeText(DailyData dailyData) {
long savedSeconds = dailyData.getDailyTimeSpent();
long minutes = savedSeconds / TIME_MULTIPLIER;
long seconds = savedSeconds % TIME_MULTIPLIER;
long hours = minutes / TIME_MULTIPLIER;
return hours + ":" + minutes + ":" + seconds;
}
}
Save the base time of the chronometer in onSaveInstanceState and set it back in onRestoreInstanceState like this:
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putLong("ChronoTime", mChronometer.getBase());
super.onSaveInstanceState(savedInstanceState);
}
public void onRestoreInstanceState(Bundle savedInstanceState){
if((savedInstanceState !=null) && savedInstanceState.containsKey("ChronoTime"))
mChronometer.setBase(savedInstanceState.getLong("ChronoTime"));
super.onRestoreInstanceState(savedInstanceState);
}
My app loads two audio files from database and stores them in an array. User can play any of them by selecting one from radio button group. both are mp3. One is playing fine and it's elapsed and total duration is displaying correctly. But the same functions display 00:00 total duration for other. Seek bar also updates its progress to 100% in this case but the elapsed time is correctly displaying and audio is playing fine. Someone please tell what is the problem? Why this is happening.. and how can I resolve it??
audio_urdu's time is fine.. error is with audio_eng.
private void updateView(int i) throws JSONException
{
idx=0;
_imgBtnPlay.setClickable(false);
_imgBtnStop.setClickable(false);
JSONObject jObject=null;
jObject=Jarray.getJSONObject(i);
audioUrl_eng=jObject.getString("audio_eng");
audioUrl_urdu=jObject.getString("audio_urdu");
lbl_tDuration.setText("00:00");
lbl_cDuration.setText("00:00");
lbl_loading.setText("Loading audio files...");
loadAudio(audioUrl_eng);
}
// Loading audio files from URL
private void loadAudio(String url)
{
// TODO Auto-generated method stub
mMediaPlayer=new MediaPlayer();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try
{
mMediaPlayer.setDataSource(url);
mMediaPlayer.prepareAsync();
}
catch(IOException e)
{
e.printStackTrace();
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
catch (IllegalStateException e)
{
e.printStackTrace();
}
mMediaPlayer.setOnPreparedListener(this);
}
// Notify when audio is ready to be played
#Override
public void onPrepared(MediaPlayer mp)
{
// TODO Auto-generated method stub
audioPlayerList[idx]=mp;
idx++;
if (idx == 1)
{
audioPlayer = mp;
lbl_tDuration.setText(mSecToTimer(mp.getDuration()));
lbl_cDuration.setText(mSecToTimer(mp.getCurrentPosition()));
updateSeekBar();
loadAudio(audioUrl_eng);
}
if (idx == 2)
{
// Enabling the media control buttons
_imgBtnPlay.setClickable(true);
_imgBtnStop.setClickable(true);
rdGrp.setClickable(true);
lbl_loading.setText("");
idx = 0;
}
}
public void onClick(View v)
{
switch(v.getId())
{
// calling search function
case R.id.imgBtnSearch:
onSearchRequested();
break;
// when play/pause button is tapped
case R.id.imgBtnPlay:
if (audioPlayer.isPlaying())
{
audioPlayer.pause();
_imgBtnPlay.setImageResource(R.drawable.ic_action_play);
}
else if (audioPlayer!=null)
{
audioPlayer.start();
_imgBtnPlay.setImageResource(R.drawable.ic_action_pause);
durationHandler.postDelayed(updateSeekBarTime, 100);
}
break;
// when stop button is tapped
case R.id.imgBtnStop:
audioPlayer.pause();
_imgBtnPlay.setImageResource(R.drawable.ic_action_play);
resetProgress();
break;
default:
break;
}
// Updating the seek bar's time after every 100 milliseconds
public void updateSeekBar()
{
durationHandler.postDelayed(updateSeekBarTime, 100);
}
// Updating the progress of seek bar
private Runnable updateSeekBarTime = new Runnable()
{
public void run()
{
long tDuration = audioPlayer.getDuration();
long cDuration = audioPlayer.getCurrentPosition();
lbl_tDuration.setText(mSecToTimer(tDuration));
lbl_cDuration.setText(mSecToTimer(cDuration));
int progress = (int) getProgressPercentage(cDuration, tDuration);
_seekbar.setProgress(progress);
durationHandler.postDelayed(this, 100);
}
};
// Converting milliseconds into min:sec format
public String mSecToTimer(long ms)
{
String finalTimerString = "";
String secString = "";
String minString = "";
// Convert total duration into minutes and seconds
int min = (int)(ms % (1000*60*60)) / (1000*60);
int sec = (int) ((ms % (1000*60*60)) % (1000*60) / 1000);
// Prepending 0 to seconds if it is one digit
if(sec < 10)
secString = "0" + sec;
else
secString = "" + sec;
// Prepending 0 to minutes if it is one digit
if(min < 10)
minString = "0" + min;
else
minString = "" + min;
finalTimerString = minString + ":" + secString;
return finalTimerString;
}
// calculating the percentage progress of seek bar
public int getProgressPercentage(long cDuration, long tDuration)
{
Double percentage = (double) 0;
long cSeconds = (int) (cDuration / 1000);
long tSeconds = (int) (tDuration / 1000);
percentage =(((double)cSeconds)/tSeconds)*100;
return percentage.intValue();
}
// Converting progress of seek bar into time duration in milliseconds
public int progressToTimer(int progress, int tDuration)
{
int cDuration = 0;
tDuration = (int) (tDuration / 1000);
cDuration = (int) ((((double)progress) / 100) * tDuration);
return cDuration * 1000;
}
// Reseting the progress of seek bar when stop button is tapped
public void resetProgress()
{
audioPlayer.seekTo(0);
lbl_cDuration.setText(mSecToTimer(0));
_seekbar.setProgress(0);
}
I have one audio in English and one in Urdu language. both are in the array audioPlayerList. User can select different languages using radio buttons. and idx is variable which tells which audio file is to be played. audio_eng is on index 0 (idx = 0) and audio_urdu is on index 1 (idx = 1). Audio is selected as audioPlayer = audioPlayerList[idx]
code for Radio button selection is this:
rdGrp.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(RadioGroup group, int checkedId)
{
// Find which radio button is selected
if (audioPlayer!=null)
{
if(audioPlayer.isPlaying())
audioPlayer.pause();
_imgBtnPlay.setImageResource(R.drawable.ic_action_play);
resetProgress();
if (checkedId == R.id.rdEng)
audioPlayer = audioPlayerList[0];
else if (checkedId == R.id.rdUrdu)
audioPlayer = audioPlayerList[1];
}
}
});
Duration of your file 'audio_eng' might be less than 1 second. When calculating percentage you convert milliseconds to seconds that results in 0 total length. That's why you get progress bar set to 100% from the beginning (actually, an exception might be thrown in this case - did you check that?).
When calculatng percentage try not to convert xDurationinto xSeconds but divide durations themselves in method getProgressPercentage.
I couldn't find other reasons why you get such result
is this correct?
im modifying a source code from github : USB CHARGE COMMANDER
when battery goes down from 20 percent it will charge
when batter goes 80 it wont
and countdown timer is for it to do this every 5 mins
i set 20000 just for testing
boolean startcountdown=true;
do{
new CountDownTimer(20000, 1000) {
Intent intent = _context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
int percent = (level*100)/scale;
public void onTick(long millisUntilFinished) {}
public void onFinish() {
if(percent <= 20){
_iIsCharging = 1;
}
else if (percent >=80){
_iIsCharging = 0;
}
else{
_iIsCharging = 1;
}
}
}.start();
}while(startcountdown);
There is no way for this do/while loop to end, it's an infinite loop at the moment. The boolean "startcountdown" needs some way to eventually go to the value of FALSE. For example
if (_iIsCharging == 0) {
startcountdown = false;
}
I have developed a stopwatch in Android . The stopwatch has the feature of Lap calculation too.
I have started the stopwatch . I tested the stopwatch developed by me with multiple standard stopwatches . The problem is that after 1 minutes , the stopwatch developed keeps lagging behind the other stopwatches & the difference keeps on increasing. I got around 8-10 seconds lagging after the 3 minutes.
The following code I am using:
Two classes I am using , one for the Stopwatch implementation & the other for Stopwatch display
StopwatchImplementation.java
/** The timer used to implement the Stopwatch logic. */
private Timer mSWatch = null;
/**
* Starts the Stopwatch.
*/
public void watchStart() {
if (mSWatch != null)
mSWatch .cancel();
mSWatch = new Timer();
mSWatch .schedule(new TimerTask() {
#Override
public void run() {
mListener.updateUIThread();
}
}, 0, 100);
}
/** Runnable The Timer_ tick where the time is updated */
Runnable Timer_Tick = new Runnable() {
public void run() {
updateTime(); // Updates the time , calculates the lap duration
}
};
private int mHours = 0;
/** The mins. */
private int mMins = 0;
/** The secs. */
private int mSecs = 0;
/** The fraction of a sec. */
private int mFSec = 0;
/** The lap hours. */
private int mLapHours = 0;
/** The lap mins. */
private int mLapMins = 0;
/** The lap secs. */
private int mLapSecs = 0;
/** The lap fraction of sec.... 1/10th of a sec*/
private int mLapFSec = 0;
public void updateTime() {
try {
mLapFSec++;
if (mLapFSec >= 10) {
mLapFSec = 0;
mLapSecs++;
if (mLapSecs >= 60) {
mLapSecs = 0;
mLapMins++;
if (mLapMins >= 60) {
mLapMins = 0;
mLapHours++;
}
}
}
mFSec++;
if (mFSec >= 10) {
mFSec = 0;
mSecs++;
if (mSecs >= 60) {
mSecs = 0;
mMins++;
if (mMins >= 60) {
mMins = 0;
mHours++;
}
}
}
}
StopwatchScreen.java
StopwatchImplementation mStopWatch = new StopwatchImplementation(this);
/**
* Update ui thread.
*/
public void updateUIThread() {
StopWatchScreen.this.runOnUiThread(mStopWatch.Timer_Tick);
}
public void startPressed() {
mStopWatch.watchStart();
}
Kindly provide any inputs regarding where the calculation is going wrong.
Thanks in advance.
Warm Regards,
CB
You cannot rely on the scheduling of a TimerTask for precision timing. You have asked for the updateTime method to be called every 100 milliseconds, but the Android system will only adhere to this roughly - it might take 99 or 101 milliseconds before the next time updateTime is called. Because of this you should avoid timing mechanisms which rely on simply increasing a counter.
For this reason you should record the start time, then compare the current time to the start time to get the amount of time elapsed. For instance:
private long startTime;
public void watchStart() {
startTime = SystemClock.elapsedRealtime();
...
}
public void updateTime() {
final long currentTime = SystemClock.elapsedRealtime();
final long elapsedTime = currentTime - startTime;
// convert elapsedTime in seconds, minutes etc
final int seconds = (elapsedTime/1000)%60;
final int minutes = (elapsedTime/(1000*60))%60;
final int hours = (elapsedTime/(100*60*60))%24;
...
}