I want to develop a simple stop watch logic in android.
On clicking a list view the timer should start and on clicking the button the timer should stop. Can anyone
IntentService based, no non-SDK dependencies and on a single file:
import android.app.Activity;
import android.app.IntentService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
public class Main extends Activity {
static final String BROADCAST_ACTION = "com.cirosantilli.android_cheat.intent_service_text_view.BROADCAST";
static final String EXTENDED_DATA_STATUS = "com.cirosantilli.android_cheat.intent_service_text_view.BROADCAST";
static final String TAG = "com.cirosantilli";
private int i = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
final LinearLayout linearLayout = new LinearLayout(this);
Button button;
final Intent intent = new Intent(Main.this, MyService.class);
button = new Button(this);
button.setText("start service");
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d(TAG, "start button");
Main.this.startService(intent.putExtra(Main.EXTENDED_DATA_STATUS, Main.this.i));
}
});
linearLayout.addView(button);
button = new Button(this);
button.setText("stop service");
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d(TAG, "stop button");
Main.this.stopService(intent);
}
});
linearLayout.addView(button);
final TextView textView = new TextView(this);
textView.setText(Integer.toString(i));
linearLayout.addView(textView);
this.setContentView(linearLayout);
LocalBroadcastManager.getInstance(this).registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Main.this.i = intent.getIntExtra(Main.EXTENDED_DATA_STATUS, 0);
textView.setText(Integer.toString(Main.this.i));
}
}, new IntentFilter(Main.BROADCAST_ACTION)
);
}
public static class MyService extends IntentService {
private Handler mHandler;
private int i = 1;
private boolean done;
public MyService() {
super("MyService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent");
this.i = intent.getIntExtra(Main.EXTENDED_DATA_STATUS, 0);
this.done = false;
while(!done) {
Log.d(TAG, "while true");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
LocalBroadcastManager.getInstance(this).sendBroadcast(
new Intent(Main.BROADCAST_ACTION)
.putExtra(Main.EXTENDED_DATA_STATUS, MyService.this.i));
this.i++;
}
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
this.done = true;
super.onDestroy();
}
}
}
For low precision only. We could get increased precision by using System.currentTimeMillis
inside onHandleIntent
instead of using the integer value, and reducing the sleep time to reduce latency.
Tested on Android 22. Standard build boilerplate here.
Instead of using listview you simply use a text view for timer and 3 buttons for stop start and reset . Using these you can make the java code accordingly
Good example, just in case if someone wants that layout file to go with this (pretty simple though).
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<EditText
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView1"
android:layout_below="@+id/textView1"
android:layout_marginLeft="18dp"
android:layout_marginTop="49dp"
android:ems="10" >
<requestFocus />
</EditText>
<Button
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/TextView01"
android:layout_marginTop="42dp"
android:layout_toRightOf="@+id/textView1"
android:text="Start" />
<Button
android:id="@+id/Button02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/Button01"
android:layout_marginTop="14dp"
android:layout_toRightOf="@+id/textView1"
android:text="Stop" />
Use the Stopwatch Class (For higher precision use System.nanoTime()
)
Add a Start() event and Stop() event on Button Presses. You'll need to update the UI so use a Thread/Handler Combination.
This should get you started.
EDIT: Added Code. (Nice Exercise! :) )
Use the Refresh_Rate
to configure how often your UI is updated.
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class Main extends Activity implements OnClickListener{
final int MSG_START_TIMER = 0;
final int MSG_STOP_TIMER = 1;
final int MSG_UPDATE_TIMER = 2;
Stopwatch timer = new Stopwatch();
final int REFRESH_RATE = 100;
Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MSG_START_TIMER:
timer.start(); //start timer
mHandler.sendEmptyMessage(MSG_UPDATE_TIMER);
break;
case MSG_UPDATE_TIMER:
tvTextView.setText(""+ timer.getElapsedTime());
mHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIMER,REFRESH_RATE); //text view is updated every second,
break; //though the timer is still running
case MSG_STOP_TIMER:
mHandler.removeMessages(MSG_UPDATE_TIMER); // no more updates.
timer.stop();//stop timer
tvTextView.setText(""+ timer.getElapsedTime());
break;
default:
break;
}
}
};
TextView tvTextView;
Button btnStart,btnStop;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tvTextView = (TextView)findViewById(R.id.TextView01);
btnStart = (Button)findViewById(R.id.Button01);
btnStop= (Button)findViewById(R.id.Button02);
btnStart.setOnClickListener(this);
btnStop.setOnClickListener(this);
}
public void onClick(View v) {
if(btnStart == v)
{
mHandler.sendEmptyMessage(MSG_START_TIMER);
}else
if(btnStop == v){
mHandler.sendEmptyMessage(MSG_STOP_TIMER);
}
}
}
As st0le gave an excellent example by using Stopwatch class. I modified this class a little and add a few methods to it.
/*
Copyright (c) 2005, Corey Goldberg
StopWatch.java is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Modified: Bilal Rabbani bilalrabbani1@live.com (Nov 2013)
*/
package bilalrabbani1.at.live.com;
public class Stopwatch {
private long startTime = 0;
private boolean running = false;
private long currentTime = 0;
public void start() {
this.startTime = System.currentTimeMillis();
this.running = true;
}
public void stop() {
this.running = false;
}
public void pause() {
this.running = false;
currentTime = System.currentTimeMillis() - startTime;
}
public void resume() {
this.running = true;
this.startTime = System.currentTimeMillis() - currentTime;
}
//elaspsed time in milliseconds
public long getElapsedTimeMili() {
long elapsed = 0;
if (running) {
elapsed =((System.currentTimeMillis() - startTime)/100) % 1000 ;
}
return elapsed;
}
//elaspsed time in seconds
public long getElapsedTimeSecs() {
long elapsed = 0;
if (running) {
elapsed = ((System.currentTimeMillis() - startTime) / 1000) % 60;
}
return elapsed;
}
//elaspsed time in minutes
public long getElapsedTimeMin() {
long elapsed = 0;
if (running) {
elapsed = (((System.currentTimeMillis() - startTime) / 1000) / 60 ) % 60;
}
return elapsed;
}
//elaspsed time in hours
public long getElapsedTimeHour() {
long elapsed = 0;
if (running) {
elapsed = ((((System.currentTimeMillis() - startTime) / 1000) / 60 ) / 60);
}
return elapsed;
}
public String toString() {
return getElapsedTimeHour() + ":" + getElapsedTimeMin() + ":"
+ getElapsedTimeSecs() + "." + getElapsedTimeMili();
}
}
Regards