Fazer um relógio interno

Conhecem alguma forma de fazer um relógio interno perfeito?, eu tentei fazer da seguinte forma, peguei a data/hora exata do telefone em Milissegundos e comecei a contar essa hora adicionando a ela mais 1000(1sg) a cada segundo, mas parece que o ciclo não é o mesmo assim sempre depois de um tempo o meu horário sempre esta diferente, teoricamente o meu horário deveria estar igual ao do dispositivo, sabem de alguma alternativa?, a intenção é ter um relógio que sempre mostre a verdadeira hora, independente da hora do celular. Uso NTPUDPClient pedindo a hora para “time.nist.gov”, que me retorna a hora correta no momento, mas nem sempre terá internet quando eu quiser.

Estou fazendo um rastreador por celular que fica pegando as coordenadas de GPS a cada N tempo e guardando isso em LOG junto com a hora que ele pegou dessa localização, então precisaria de um relógio MEU, que estaria correto, já que do celular o usuário pode mudar.

Aki esta o serviço que criei,

public class CustomClock extends Service {

private final String TAG = this.getClass().getSimpleName();


private long timeCustomInMilliseconds = 0;
CountDownTimer countDownTimer = null;
public static final int SUCCESS_RESULT = 0;
public static final int FAILURE_RESULT = 1;

private boolean isNotGettingTime = true;

private final IBinder mBinder = new LocalBinder();


public CustomClock() {
}


@Override
public void onCreate() {
    Log.i(TAG, "Service CustomClock onCreate");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.i(TAG, "Service CustomClock started");
    return START_STICKY;
}

class LocalBinder extends Binder {
    CustomClock getService() {
        // Return this instance of LocalService so clients can call public methods
        return CustomClock.this;
    }
}

@Override
public IBinder onBind(Intent intent) {
    return  mBinder;
}

public void setCounter() {
    Log.i(TAG,"setCounter");

    if(countDownTimer != null){
        countDownTimer.cancel();
    }
    countDownTimer = new CountDownTimer(86400000 , 1000) {//24 horas, 1s
        public void onTick(long millisUntilFinished) {
            Calendar cal = Calendar.getInstance();
            long systemTime = System.currentTimeMillis();
            Log.i(TAG,"TIME_COUNTER CUSTOM: " + timeCustomInMilliseconds + " DEVICE: "
                    + systemTime
                    + " DIF: + " + (systemTime - timeCustomInMilliseconds ));

            timeCustomInMilliseconds += 1000;//adiciona 1s a contagem


        }
        public void onFinish() {
            countDownTimer.start();
        }
    }.start();

}

public long getTimeCustomInMilliseconds() {
    return timeCustomInMilliseconds;
}


public boolean isNotGettingTime(){
    return this.isNotGettingTime;
}

public void setTimeCustomInMilliseconds(long timeCustomInMilliseconds) {
    this.timeCustomInMilliseconds = timeCustomInMilliseconds;
    this.isNotGettingTime = true;
}

public void setTimeFromNet(){
    this.isNotGettingTime = false;

    final Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message message) {
            isNotGettingTime = false;
            if(getTimeCustomInMilliseconds() != 0 && getTimeCustomInMilliseconds() != -1){
                setCounter();
            }
        }
    };

    new Thread(new Runnable() {
        @Override
        public void run() {
            setTimeCustomInMilliseconds(getTimeInNet().time);
            Message message = mHandler.obtainMessage(0, 0);
            message.sendToTarget();
        }
    }).start();

}


private TimeResult getTimeInNet() {


    NTPUDPClient timeClient = new NTPUDPClient();
    InetAddress inetAddress;
    timeClient.setDefaultTimeout(10000);

    try {
        inetAddress = InetAddress.getByName(Constants.TIME_SERVERS[1]);// a.st1.ntp.br
    } catch (UnknownHostException e) {
        return new TimeResult(FAILURE_RESULT, -1, e.getMessage());
    }
    TimeInfo timeInfo;
    try {
        timeInfo = timeClient.getTime(inetAddress);
    } catch (IOException e) {
        return new TimeResult(FAILURE_RESULT, -1, e.getMessage());
    }

    long time = timeInfo.getMessage().getTransmitTimeStamp().getTime(); //data/hora em millisegundos do servidor
    long timeSystem= System.currentTimeMillis();//Busca hoario atual em millisegundos do telefone(fazer comparacao)
    Log.i(TAG,"GET_TIME_FROM_NET -> NET: " + time + " DEVICE: "
            + timeSystem
            + " DIF: + " + (timeSystem - time ));

    timeClient.close();

    return new TimeResult(SUCCESS_RESULT, time, "");
}

private class TimeResult {

    int resultCode;
    String failureMessage;
    long time;

    TimeResult(int resultCode, long time, String failureMessage) {

        this.resultCode = resultCode;
        this.time = time;
        this.failureMessage = failureMessage;
    }
}

@Override
public void onDestroy() {
    super.onDestroy();
    if(countDownTimer != null){
        countDownTimer.cancel();
    }
}

}

Para ativá-lo e usá-lo uso,

private CustomClock customClock; boolean isCustomClockBind = false;
@Override
protected void onStart() {
    super.onStart();
    initAndBindClock();
}

private void initAndBindClock(){
startService(new Intent(getBaseContext(), CustomClock.class));
Intent intent = new Intent(this, CustomClock.class);
bindService(intent, mConnection, 0);
}

/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {

    @Override
    public void onServiceConnected(ComponentName className,
                                   IBinder service) {
        // We've bound to LocalService, cast the IBinder and get LocalService instance
        CustomClock.LocalBinder binder = (CustomClock.LocalBinder) service;
        customClock = binder.getService();
        isCustomClockBind = true;

       if(customClock.isNotGettingTime()){
            customClock.setTimeFromNet();
      }
    }

    @Override
    public void onServiceDisconnected(ComponentName arg0) {
        isCustomClockBind = false;
    }
};

Mas a hora do celular não é correta?

O usuário pode mudar, e meu aplicativo necessita da hora correta para funcionar como esperado…

Se a hora do celular pode ser alterada, como vai garantir se a hora inicial que voce pegou está correta?

Melhor ter um serviço que retorne a data e hora do servidor.

Sim, eu uso NTPUDPClient pedindo a hora para “time.nist.gov”, que me retorna a hora correta no momento, mas nem sempre terá internet quando eu quiser.

Com que frequência ocorre esse atraso? qual é o atraso?

Sabendo isso vc consegue prever o atraso e corrigi-lo

Vai depender do aparelho, se ele estiver carregado(lento), pode atrasar a contagem, ou seja, nunca vai contar 1s exato, se executar o código que postei na pergunta desse tópico, observe que em
"DIF" ( diferença do horário virtual e do sistema) do log sempre sera variável(pra min é assim),
estou procurando alternativas ainda, não sei se existe uma função do android que crie algo que eu quero…

Isso não poderia acontecer, pois o tempo é contado em base de ciclos de clock, assim sendo a frequência do processador não se altera por este estar “carregado”

Por isso acredito que o erro esteja no fato de vc estar tentando contar os milissegundos no seu sistema, este sim enfrentara uma fila ao sistema estar “carregado” podendo resultar em um atraso, porém a contagem de clocks interna do sistema deve ser exata (caso não o aparelho está defeituoso)

Nesse sentido uma solução é vc obter a contagem de clocks no momento em que o relógio foi sincronizado com a API além da frequência do processador, ai no momento em que necessitar da hora exata, obtém a contagem de clocks no momento, e com essa diferença e a frequência vc consegue calcular o período decorrido

Haveriam alguns empecilhos, como o caso do aparelho ser desligado, nesse momento vc teria que guardar a contagem de ciclos e o horário do relógio, como com o aparelho desligado não tem como o usuário alterar o relógio, no momento que for ligado vc terá que capturar o horário do relógio novamente, a contagem de ciclos começará zerada novamente

No momento que precisar do horário, com a contagem de ciclos antes de desligar, mais o intervalo do relógio quando desligado, mais a contagem de ciclos após ligado, vc consegue calcular o intervalo

1 curtida

Yeeeh, vlw, achei uma solução com algo do que você falo buscando o clock e contar a partir dele, segue o exemplo:

private void StartTickPerSecond()
{
this.Handler=new Handler();
this.Ticker = new Runnable()
{
public void run()
{
Tick(1000);
long now = SystemClock.uptimeMillis();
long next = now + (1000 - now % 1000);
Handler.postAtTime(Ticker, next);
}
};
this.Ticker.run();

}

Encontrado em https://stackoverflow.com/questions/6527474/how-to-create-a-digital-clock-on-android

1 curtida