1 Востаннє редагувалося shabaranskij (10.01.2016 04:41:16)

Тема: Секундомір

Писав секундомір різними способами але  завжди виникає не точність підрахунку часу. Цей після 2 хвилин роботи відстає на 0.8 секунди.

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public class MainActivity extends AppCompatActivity {


Button start,stop;
    TextView timenow, textView;
    int min=0, activ=0, sec=0, sn=0, mn=0, hn=0, g=1;
   String secs, mins,mss, sns,mns,hns;
long time0=0, time=0,ms=0,reserv=0;

public Handler tmn=new Handler();

    public Runnable TmnUp=new Runnable()
    {

        @Override
        public void run()
        {
           Calendar cal=new GregorianCalendar();
            hn=cal.get(Calendar.HOUR);
            mn=cal.get(Calendar.MINUTE);
            sn=cal.get(Calendar.SECOND);
            if (hn<10) hns="0"+Integer.toString(hn); else
                hns=Integer.toString(hn);
            if (mn<10) mns="0"+Integer.toString(mn); else
                mns=Integer.toString(mn);
            if (sn<10) sns="0"+Integer.toString(sn); else
                sns=Integer.toString(sn);
         timenow.setText(hns + ":" + mns + ":" + sns);


            tmn.postDelayed(TmnUp,50);
        }
    };


    protected void onPause()
    {
        mh.removeCallbacks(TimeUpdater);
        start.setText("Старт");
    super.onPause();
    }


    private Handler mh=new Handler();
    private Runnable TimeUpdater=new Runnable()
    {
        @SuppressLint("SetTextI18n")
        @Override
        public void run() {

                     Date d=new Date();
                     time=d.getTime();
                     ms=time-time0;
if (ms>=1000)
{
ms=0;
time0=time;
sec++;
}
if (sec==60)
{
    sec=0;
min++;
}

if (ms<10)  mss="00"+String.valueOf(ms);  else  mss=String.valueOf(ms);
if ((ms<100) && (ms>10))  mss="0"+String.valueOf(ms);  else  mss=String.valueOf(ms);
if ((ms<1000) && (ms>100))  mss=String.valueOf(ms);

if (sec<10) secs="0"+String.valueOf(sec); else  secs=String.valueOf(sec);
if (min<10) mins="0"+String.valueOf(min); else  mins=String.valueOf(min);


textView.setText(mins+":"+secs+"."+mss);

                     mh.postDelayed(this, g);
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        start=(Button) findViewById(R.id.start);
        stop=(Button)findViewById(R.id.stop);
        textView=(TextView) findViewById(R.id.textView);
        timenow=(TextView) findViewById(R.id.timenow);
        tmn.removeCallbacks(TmnUp);
        tmn.postDelayed(TmnUp,1);


        stop.setOnClickListener(new View.OnClickListener() {

            @SuppressLint("SetTextI18n")
            @Override
            public void onClick(View v) {
                onPause();
                textView.setText("00:00.000");
                min = 0;
                sec = 0;
                ms=0;
                time0=0;
                time=0;
                reserv=0;
                start.setText("СТАРТ");
                activ = 0;
            }
        });


        start.setOnClickListener(new View.OnClickListener() {


            @Override
            public void onClick(View v) {
                if (activ == 0) {
                    Date date=new Date();
                    time0=date.getTime()-reserv;
                    mh.removeCallbacks(TimeUpdater);
                    mh.postDelayed(TimeUpdater, g);
                    start.setText("Пауза");
                    activ = 1;
                } else if (activ == 1) {
                    onPause();
                    reserv=ms;
                    activ = 0;
                }
            }
        });
    }
}

https://pp.сайт-злодій/c633319/v633319567/bc77/RKNg8_s9CqM.jpg

Подякували: leofun011

2 Востаннє редагувалося leofun01 (10.01.2016 05:13:35)

Re: Секундомір

І допомогти хочеться і трохи страшно код виглядає.
Як мінімум 8 if'ів там зайві.
Для виводу нулів використовуйте String.format
http://developer.android.com/reference/ … atter.html
http://docs.oracle.com/javase/tutorial/ … ormat.html
або ще краще Time.format, чи DateFormat
http://developer.android.com/reference/ … ormat.html
http://developer.android.com/reference/ … ormat.html
http://docs.oracle.com/javase/7/docs/ap … ormat.html
Причину відставання секундоміра ще не виявив ...

Подякували: shabaranskij1

3

Re: Секундомір

Дякую за підказку. *THUMBSUP*

4

Re: Секундомір

Delay і аналоги в багатозадачних системах гарантують довжину паузи щонайменше в свій параметр, а не точно. Відповідно, таймер має не додавати одиничку, а запитувати поточний час і віднімати від нього час початку відліку.

Подякували: leofun01, shabaranskij2

5

Re: Секундомір

koala написав:

Delay і аналоги в багатозадачних системах гарантують довжину паузи щонайменше в свій параметр, а не точно. Відповідно, таймер має не додавати одиничку, а запитувати поточний час і віднімати від нього час початку відліку.

В мене так і є. 

   private Handler mh=new Handler();
    private Runnable TimeUpdater=new Runnable()
    {
        @SuppressLint("SetTextI18n")
        @Override
        public void run() {
 
                     Date d=new Date();
                     time=d.getTime();
                     ms=time-time0;
if (ms>=1000)
{
ms=0;
time0=time;
sec++;
}
if (sec==60)
{
    sec=0;
min++;
}
 
if (ms<10)  mss="00"+String.valueOf(ms);  else  mss=String.valueOf(ms);
if ((ms<100) && (ms>10))  mss="0"+String.valueOf(ms);  else  mss=String.valueOf(ms);
if ((ms<1000) && (ms>100))  mss=String.valueOf(ms);
 
if (sec<10) secs="0"+String.valueOf(sec); else  secs=String.valueOf(sec);
if (min<10) mins="0"+String.valueOf(min); else  mins=String.valueOf(min);
 
 
textView.setText(mins+":"+secs+"."+mss);
 
                     mh.postDelayed(this, g);
        }
    };

g=1

6

Re: Секундомір

Ова... у вас все ще гірше. Ви чекаєте, доки не мине щонайменше 1000 мс, і плюсуєте 1 секунду. Тобто минуло 1030мс - ви плюсуєте 1с, минуло 1020мс - а для вас це 1с... а ці 20мс+30мс накопичуються.

Подякували: leofun011

7 Востаннє редагувалося shabaranskij (10.01.2016 17:05:05)

Re: Секундомір

leofun01 написав:

І допомогти хочеться і трохи страшно код виглядає.
Як мінімум 8 if'ів там зайві.
Для виводу нулів використовуйте String.format
http://developer.android.com/reference/ … atter.html
http://docs.oracle.com/javase/tutorial/ … ormat.html
або ще краще Time.format, чи DateFormat
http://developer.android.com/reference/ … ormat.html
http://developer.android.com/reference/ … ormat.html
http://docs.oracle.com/javase/7/docs/ap … ormat.html
Причину відставання секундоміра ще не виявив ...

Ще раз дякую за підказку. Виправив і все працює.

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.util.Date;

public class MainActivity extends AppCompatActivity {

Button start,stop;
    TextView timenow, textView;

    int min=0, activ=0, sec=0, g=1;
   String secs, mins,mss, sns,mns,hns;
long time0=0, time=0,ms=0,reserv=0;

    Date timeTimer=new Date();

public Handler tmn=new Handler();

    public Runnable TmnUp=new Runnable()
    {

        @Override
        public void run()
        {
         Date now=new Date();
            hns=String.format("%tH",now);
            mns=String.format("%tM",now);
            sns=String.format("%tS",now);
         timenow.setText(hns + ":" + mns + ":" + sns);

            tmn.postDelayed(TmnUp,200);
        }
    };


    protected void onPause()
    {
        mh.removeCallbacks(TimeUpdater);
        start.setText("Старт");
    super.onPause();
    }


    private Handler mh=new Handler();
    private Runnable TimeUpdater=new Runnable()
    {
        @SuppressLint("SetTextI18n")
        @Override
        public void run() {

                     Date d=new Date();
                     time=d.getTime();
                     ms=time-time0;
            timeTimer.setTime(ms);

mss=String.format("%tL",timeTimer.getTime());
secs=String.format("%tS",timeTimer.getTime());
            mins=String.format("%tM",timeTimer.getTime());

textView.setText(mins + ":" + secs + "." + mss);
                     mh.postDelayed(this, g);
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        start=(Button) findViewById(R.id.start);
        stop=(Button)findViewById(R.id.stop);
        textView=(TextView) findViewById(R.id.textView);
        timenow=(TextView) findViewById(R.id.timenow);
        tmn.removeCallbacks(TmnUp);
        tmn.postDelayed(TmnUp,1);


        stop.setOnClickListener(new View.OnClickListener() {

            @SuppressLint("SetTextI18n")
            @Override
            public void onClick(View v) {
                onPause();
                textView.setText("00:00.000");
                min = 0;
                sec = 0;
                ms=0;
                time0=0;
                time=0;
                reserv=0;
                start.setText("СТАРТ");
                activ = 0;
            }
        });


        start.setOnClickListener(new View.OnClickListener() {


            @Override
            public void onClick(View v) {
                if (activ == 0) {
                    Date date=new Date();
                    time0=date.getTime()-reserv;
                    mh.removeCallbacks(TimeUpdater);
                    mh.postDelayed(TimeUpdater, g);
                    start.setText("Пауза");
                    activ = 1;
                } else if (activ == 1) {
                    onPause();
                    reserv=ms;
                    activ = 0;
                }
            }
        });
    }
}

https://pp.сайт-злодій/c633319/v633319567/bc77/RKNg8_s9CqM.jpg
Частина коду яка опрацьовує вивід часу таймера.

 private Handler mh=new Handler();
    private Runnable TimeUpdater=new Runnable()
    {
        @SuppressLint("SetTextI18n")
        @Override
        public void run() {

                     Date d=new Date();
                     time=d.getTime();
                     ms=time-time0;
            timeTimer.setTime(ms);

mss=String.format("%tL",timeTimer.getTime());
secs=String.format("%tS",timeTimer.getTime());
            mins=String.format("%tM",timeTimer.getTime());

textView.setText(mins + ":" + secs + "." + mss);
                     mh.postDelayed(this, g);
        }
    };

Подивіться може ще щось можна виправити

Подякували: leofun011

8 Востаннє редагувалося leofun01 (10.01.2016 19:57:44)

Re: Секундомір

Рядки такого типу:

hns=String.format("%tH",now);
mns=String.format("%tM",now);
sns=String.format("%tS",now);
timenow.setText(hns + ":" + mns + ":" + sns);

Краще замінити на щось таке:

simpDate = new SimpleDateFormat("kk:mm:ss"); 
timenow.setText(simpDate.format(now));

(Джерело)
І до порад koala теж прислухайтесь.

Подякували: shabaranskij1

9

Re: Секундомір

leofun01 написав:

Рядки такого типу:

hns=String.format("%tH",now);
mns=String.format("%tM",now);
sns=String.format("%tS",now);
timenow.setText(hns + ":" + mns + ":" + sns);

Краще замінити на щось таке:

simpDate = new SimpleDateFormat("kk:mm:ss"); 
timenow.setText(simpDate.format(now));

(Джерело)
І до порад koala теж прислухайтесь.

*THUMBSUP*  *OK*

Подякували: koala1

10

Re: Секундомір

Взагалі в Android в плані точності часу сумно, похибка на рівні однієї-трьох мілісекунд - норма. Будемо сподіватись, що з приходом OpenJDK і появою Java 8 проблема вирішиться (там похибка вже на рівні декількох наносекунд).

11 Востаннє редагувалося shabaranskij (17.01.2016 03:19:31)

Re: Секундомір

Посилання на повний код секундоміра
Він блокує перехід в режим сну під час виконання відліку.
І вимикає блокування після зупинки відліку.

Подякували: leofun011

12 Востаннє редагувалося rainboww1988 (07.11.2016 18:13:59)

Re: Секундомір

Мені здається, що я бачив цей секундомір в одній з книжок по Андроїд розробці, якщо помиляюсь то нічого.
Питання у тому що він працює не зовсів вірно..а ви працюєте з мілісекундами? по потрібно так..і можливо десь помилка щодо життєвого циклу активності, в якомусь з методів.
Книжка назівається Head First Android Development, здається так. Подивіться там варіант секундоміра є. Думаю знайдете відповідь на своє питання.