UI Hangs When While Loop is Placed Inside Runnable - android

I'm writing an app that will display the current download speed which will be updated every second. My Runnable class is able to update the UI with the value, but when I try to place it inside a loop so that it will continuously run and update the UI TextView every second, the app now hangs.
This is my MainActivity.java:
public class MainActivity extends Activity implements SpeedMeter.TaskRunnableSpeedMeterMethods{
private Thread mSpeedMeterThread;
private Handler mHandler;
private TextView downloadSpeedOutput;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
downloadSpeedOutput = (TextView) findViewById(R.id.speed);
mHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message inputMessage) {
SpeedMeter speedMeter = (SpeedMeter) inputMessage.obj;
downloadSpeedOutput.setText(Long.toString(speedMeter.getmDownloadSpeedKB()));
}
};
SpeedMeter speedMeter = new SpeedMeter(this);
speedMeter.run();
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, MainActivity.class);
}
#Override
public void setSpeedMeterThread(Thread currentThread) {
mSpeedMeterThread = currentThread;
}
#Override
public void setInternetSpeed(SpeedMeter speedMeter) {
Message completeMessage = mHandler.obtainMessage(1, speedMeter);
completeMessage.sendToTarget();
}
}
And here's the other SpeedMeter.java:
public class SpeedMeter implements Runnable {
final TaskRunnableSpeedMeterMethods mMainActivity;
private long mDownloadSpeedKB;
public SpeedMeter(TaskRunnableSpeedMeterMethods mainActivity) {
mMainActivity = mainActivity;
}
#Override
public void run() {
mMainActivity.setSpeedMeterThread(Thread.currentThread());
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
// while(true) {
long rxBytesPrevious = TrafficStats.getTotalRxBytes();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long rxBytesCurrent = TrafficStats.getTotalRxBytes();
long downloadSpeed = rxBytesCurrent - rxBytesPrevious;
setmDownloadSpeedKB(downloadSpeed/1000);
mMainActivity.setInternetSpeed(this);
// }
}
public long getmDownloadSpeedKB() {
return mDownloadSpeedKB;
}
public void setmDownloadSpeedKB(long mDownloadSpeedKB) {
this.mDownloadSpeedKB = mDownloadSpeedKB;
}
interface TaskRunnableSpeedMeterMethods {
void setSpeedMeterThread(Thread currentThread);
void setInternetSpeed(SpeedMeter speedMeter);
}
}
Any help will be appreciated!

You didnt start your runnable as a new thread instead you called the run function like a normal function (so u do the while loop on ur UI thread which blocks it)
replace
speedMeter.run();<br />
SpeedMeter speedMeter = new SpeedMeter(this);
with
new Thread(new SpeedMeter(this)).start();
see https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html for more infos on how to start a Runnable :)

The ideal way to do this would be to create an AsyncTask that would post a message to your UI thread, after it complete the task in the doInBackground() call.
Standards
also the interface structure you are following does not make sense and does not follow good standards. Usually an interface is used as a callback, which is basically what you are doing. But the standard is to say onSomethingChangedA() or onSomethingChangedB() from OnSomethingChangedListener interface.

I think your loop is always true so app hangs its better to create a boolean and use while(mboolean) and put this in your loop
if(something){
mboolean=false;
}
you can also use CountDownTimer.
for example:
new CountDownTimer(miliseconds,1000)
//if you have download speed and download size you can find miliseconds
#Override
public void onTick(long l) {
//something you want to do every seconds
}
#Override
public void onFinish() {
//something you want to do on finish
}

Related

Can I pause a program for a while? [duplicate]

I want to make a pause between two lines of code, Let me explain a bit:
-> the user clicks a button (a card in fact) and I show it by changing the background of this button:
thisbutton.setBackgroundResource(R.drawable.icon);
-> after let's say 1 second, I need to go back to the previous state of the button by changing back its background:
thisbutton.setBackgroundResource(R.drawable.defaultcard);
-> I've tried to pause the thread between these two lines of code with:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
However, this does not work. Maybe it's the process and not the Thread that I need to pause?
I've also tried (but it doesn't work):
new Reminder(5);
With this:
public class Reminder {
Timer timer;
public Reminder(int seconds) {
timer = new Timer();
timer.schedule(new RemindTask(), seconds*1000);
}
class RemindTask extends TimerTask {
public void run() {
System.out.format("Time's up!%n");
timer.cancel(); //Terminate the timer thread
}
}
}
How can I pause/sleep the thread or process?
One solution to this problem is to use the Handler.postDelayed() method. Some Google training materials suggest the same solution.
#Override
public void onClick(View v) {
my_button.setBackgroundResource(R.drawable.icon);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
my_button.setBackgroundResource(R.drawable.defaultcard);
}
}, 2000);
}
However, some have pointed out that the solution above causes a memory leak because it uses a non-static inner and anonymous class which implicitly holds a reference to its outer class, the activity. This is a problem when the activity context is garbage collected.
A more complex solution that avoids the memory leak subclasses the Handler and Runnable with static inner classes inside the activity since static inner classes do not hold an implicit reference to their outer class:
private static class MyHandler extends Handler {}
private final MyHandler mHandler = new MyHandler();
public static class MyRunnable implements Runnable {
private final WeakReference<Activity> mActivity;
public MyRunnable(Activity activity) {
mActivity = new WeakReference<>(activity);
}
#Override
public void run() {
Activity activity = mActivity.get();
if (activity != null) {
Button btn = (Button) activity.findViewById(R.id.button);
btn.setBackgroundResource(R.drawable.defaultcard);
}
}
}
private MyRunnable mRunnable = new MyRunnable(this);
public void onClick(View view) {
my_button.setBackgroundResource(R.drawable.icon);
// Execute the Runnable in 2 seconds
mHandler.postDelayed(mRunnable, 2000);
}
Note that the Runnable uses a WeakReference to the Activity, which is necessary in a static class that needs access to the UI.
You can try this one it is short
SystemClock.sleep(7000);
WARNING: Never, ever, do this on a UI thread.
Use this to sleep eg. background thread.
Full solution for your problem will be:
This is available API 1
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View button) {
button.setBackgroundResource(R.drawable.avatar_dead);
final long changeTime = 1000L;
button.postDelayed(new Runnable() {
#Override
public void run() {
button.setBackgroundResource(R.drawable.avatar_small);
}
}, changeTime);
}
});
Without creating tmp Handler. Also this solution is better than #tronman because we do not retain view by Handler.
Also we don't have problem with Handler created at bad thread ;)
Documentation
public static void sleep (long ms)
Added in API level 1
Waits a given number of milliseconds (of uptimeMillis) before returning. Similar to sleep(long), but does not throw InterruptedException; interrupt() events are deferred until the
next interruptible operation.
Does not return until at least the specified number of milliseconds has elapsed.
Parameters
ms to sleep before returning, in milliseconds of uptime.
Code for postDelayed from View class:
/**
* <p>Causes the Runnable to be added to the message queue, to be run
* after the specified amount of time elapses.
* The runnable will be run on the user interface thread.</p>
*
* #param action The Runnable that will be executed.
* #param delayMillis The delay (in milliseconds) until the Runnable
* will be executed.
*
* #return true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed --
* if the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*
* #see #post
* #see #removeCallbacks
*/
public boolean postDelayed(Runnable action, long delayMillis) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.postDelayed(action, delayMillis);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
return true;
}
I use this:
Thread closeActivity = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(3000);
// Do some stuff
} catch (Exception e) {
e.getLocalizedMessage();
}
}
});
I use CountDownTime
new CountDownTimer(5000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
// do something after 1s
}
#Override
public void onFinish() {
// do something end times 5s
}
}.start();
You probably don't want to do it that way. By putting an explicit sleep() in your button-clicked event handler, you would actually lock up the whole UI for a second. One alternative is to use some sort of single-shot Timer. Create a TimerTask to change the background color back to the default color, and schedule it on the Timer.
Another possibility is to use a Handler. There's a tutorial about somebody who switched from using a Timer to using a Handler.
Incidentally, you can't pause a process. A Java (or Android) process has at least 1 thread, and you can only sleep threads.
This is what I did at the end of the day - works fine now :
#Override
public void onClick(View v) {
my_button.setBackgroundResource(R.drawable.icon);
// SLEEP 2 SECONDS HERE ...
final Handler handler = new Handler();
Timer t = new Timer();
t.schedule(new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
my_button.setBackgroundResource(R.drawable.defaultcard);
}
});
}
}, 2000);
}
In addition to Mr. Yankowsky's answers, you could also use postDelayed(). This is available on any View (e.g., your card) and takes a Runnable and a delay period. It executes the Runnable after that delay.
This is my example
Create a Java Utils
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
public class Utils {
public static void showDummyWaitingDialog(final Context context, final Intent startingIntent) {
// ...
final ProgressDialog progressDialog = ProgressDialog.show(context, "Please wait...", "Loading data ...", true);
new Thread() {
public void run() {
try{
// Do some work here
sleep(5000);
} catch (Exception e) {
}
// start next intent
new Thread() {
public void run() {
// Dismiss the Dialog
progressDialog.dismiss();
// start selected activity
if ( startingIntent != null) context.startActivity(startingIntent);
}
}.start();
}
}.start();
}
}
Or you could use:
android.os.SystemClock.sleep(checkEvery)
which has the advantage of not requiring a wrapping try ... catch.
If you use Kotlin and coroutines, you can simply do
GlobalScope.launch {
delay(3000) // In ms
//Code after sleep
}
And if you need to update UI
GlobalScope.launch {
delay(3000)
GlobalScope.launch(Dispatchers.Main) {
//Action on UI thread
}
}
I know this is an old thread, but in the Android documentation I found a solution that worked very well for me...
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
https://developer.android.com/reference/android/os/CountDownTimer.html
Hope this helps someone...
class MyActivity{
private final Handler handler = new Handler();
private Runnable yourRunnable;
protected void onCreate(#Nullable Bundle savedInstanceState) {
// ....
this.yourRunnable = new Runnable() {
#Override
public void run() {
//code
}
};
this.handler.postDelayed(this.yourRunnable, 2000);
}
#Override
protected void onDestroy() {
// to avoid memory leaks
this.handler.removeCallbacks(this.yourRunnable);
}
}
And to be double sure you can be combined it with the "static class" method as described in the tronman answer

How do we use runOnUiThread in Android?

I'm trying to use the UI-Thread, so I've written a simple test activity. But I think I've misunderstood something, because on clicking the button - the app does not respond anymore
public class TestActivity extends Activity {
Button btn;
int i = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
runThread();
}
});
}
private void runThread(){
runOnUiThread (new Thread(new Runnable() {
public void run() {
while(i++ < 1000){
btn.setText("#"+i);
try {
Thread.sleep(300);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}));
}
}
Below is corrected Snippet of runThread Function.
private void runThread() {
new Thread() {
public void run() {
while (i++ < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setText("#" + i);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
Just wrap it as a function, then call this function from your background thread.
public void debugMsg(String msg) {
final String str = msg;
runOnUiThread(new Runnable() {
#Override
public void run() {
mInfo.setText(str);
}
});
}
You have it back-to-front. Your button click results in a call to runOnUiThread(), but this isn't needed, since the click handler is already running on the UI thread. Then, your code in runOnUiThread() is launching a new background thread, where you try to do UI operations, which then fail.
Instead, just launch the background thread directly from your click handler. Then, wrap the calls to btn.setText() inside a call to runOnUiThread().
runOnUiThread(new Runnable() {
public void run() {
//Do something on UiThread
}
});
There are several techniques using of runOnUiThread(), lets see all
This is my main thread (UI thread) called AndroidBasicThreadActivity and I'm going to update it from a worker thread in various ways -
public class AndroidBasicThreadActivity extends AppCompatActivity
{
public static TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_android_basic_thread);
textView = (TextView) findViewById(R.id.textview);
MyAndroidThread myTask = new MyAndroidThread(AndroidBasicThreadActivity.this);
Thread t1 = new Thread(myTask, "Bajrang");
t1.start();
}
}
1.) By passing Activity's instance as an argument on worker thread
class MyAndroidThread implements Runnable
{
Activity activity;
public MyAndroidThread(Activity activity)
{
this.activity = activity;
}
#Override
public void run()
{
//perform heavy task here and finally update the UI with result this way -
activity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
}
});
}
}
2.) By using View's post(Runnable runnable) method in worker thread
class MyAndroidThread implements Runnable
{
Activity activity;
public MyAndroidThread(Activity activity)
{
this.activity = activity;
}
#Override
public void run()
{
//perform heavy task here and finally update the UI with result this way -
AndroidBasicThreadActivity.textView.post(new Runnable()
{
#Override
public void run()
{
AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
}
});
}
}
3.) By using Handler class from android.os package
If we don't have the context (this/ getApplicationContext()) or Activity's instance (AndroidBasicThreadActivity.this) then we have to use Handler class as below -
class MyAndroidThread implements Runnable
{
Activity activity;
public MyAndroidThread(Activity activity)
{
this.activity = activity;
}
#Override
public void run()
{
//perform heavy task here and finally update the UI with result this way -
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
}
});
}
}
If using in fragment then simply write
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
// Do something on UiThread
}
});
We use Worker Thread to make Apps smoother and avoid ANR's. We may need to update UI after the heavy process in worker Tread.
The UI can only be updated from UI Thread. In such cases, we use Handler or runOnUiThread both have a Runnable run method that executes in UI Thread.
The onClick method runs in UI thread so don't need to use runOnUiThread here.
Using Kotlin
While in Activity,
this.runOnUiThread {
// Do stuff
}
From Fragment,
activity?.runOnUiThread {
// Do stuff
}
Using Java,
this.runOnUiThread(new Runnable() {
void run() {
// Do stuff
}
});
For fragment use that:
requireActivity().runOnUiThread(() -> {
//your code logic
});
For activity use that:
runOnUiThread(() -> {
//your code logic
});
runOnUiThread is used in a way the UI can be updated with our background thread. For more: https://www.tutorialspoint.com/how-do-we-use-runonuithread-in-android
thy this:
#UiThread
public void logMsg(final String msg) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
}
You can use from this sample :
In the following example, we are going to use this facility to publish the result from a
synonym search that was processed by a background thread.
To accomplish the goal during the OnCreate activity callback, we will set up
onClickListener to run searchTask on a created thread.
When the user clicks on the Search button, we will create a Runnable anonymous
class that searches for the word typed in R.id.wordEt EditText and starts the
thread to execute Runnable.
When the search completes, we will create an instance of Runnable SetSynonymResult
to publish the result back on the synonym TextView over the UI thread.
This technique is sometime not the most convenient one, especially when we don't
have access to an Activity instance; therefore, in the following chapters, we are
going to discuss simpler and cleaner techniques to update the UI from a background
computing task.
public class MainActivity extends AppCompatActivity {
class SetSynonymResult implements Runnable {
String synonym;
SetSynonymResult(String synonym) {
this.synonym = synonym;
}
public void run() {
Log.d("AsyncAndroid", String.format("Sending synonym result %s on %d",
synonym, Thread.currentThread().getId()) + " !");
TextView tv = (TextView) findViewById(R.id.synonymTv);
tv.setText(this.synonym);
}
}
;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button search = (Button) findViewById(R.id.searchBut);
final EditText word = (EditText) findViewById(R.id.wordEt);
search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Runnable searchTask = new Runnable() {
#Override
public void run() {
String result = searchSynomim(word.getText().toString());
Log.d("AsyncAndroid", String.format("Searching for synonym for %s on %s",
word.getText(), Thread.currentThread().getName()));
runOnUiThread(new SetSynonymResult(result));
}
};
Thread thread = new Thread(searchTask);
thread.start();
}
});
}
static int i = 0;
String searchSynomim(String word) {
return ++i % 2 == 0 ? "fake" : "mock";
}
}
Source :
asynchronous android programming Helder Vasconcelos
This is how I use it:
runOnUiThread(new Runnable() {
#Override
public void run() {
//Do something on UiThread
}
});
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gifImageView = (GifImageView) findViewById(R.id.GifImageView);
gifImageView.setGifImageResource(R.drawable.success1);
new Thread(new Runnable() {
#Override
public void run() {
try {
//dummy delay for 2 second
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//update ui on UI thread
runOnUiThread(new Runnable() {
#Override
public void run() {
gifImageView.setGifImageResource(R.drawable.success);
}
});
}
}).start();
}
Try this: getActivity().runOnUiThread(new Runnable...
It's because:
1) the implicit this in your call to runOnUiThread is referring to AsyncTask, not your fragment.
2) Fragment doesn't have runOnUiThread.
However, Activity does.
Note that Activity just executes the Runnable if you're already on the main thread, otherwise it uses a Handler. You can implement a Handler in your fragment if you don't want to worry about the context of this, it's actually very easy:
// A class instance
private Handler mHandler = new Handler(Looper.getMainLooper());
// anywhere else in your code
mHandler.post(<your runnable>);
// ^ this will always be run on the next run loop on the main thread.

Android: Best way to automatic connect to a webservice, without user interaction

I am new in android development and I am doing an application that needs to auto-connect to a webservice every X amount of time. For example connect to retrieve data every 30 seconds, without the user's interaction.
I tried with android.os.Handler but the problem with this Object is that it is running in the ui thread, so when the connection takes to much time the UI freeze...
The only way that I found to do this is to use asynctast and in onPostexecute() call again to the same Asynctask Object, something like that:
public class ScheduledAsyncTask extends AsyncTasc {
doInBackground() {
Thread.sleep(30000); //30 seconds...
// connect to the server and retrieve data...
}
onPostExecute() {
// show new data to the user
ScheduledAsyncTask task = new ScheduledAsyncTask();
task.execute();
}
}
This works great but I assume is not the best way to do it. All suggestions are welcome.
Thanks in advance,
New Example from my side:
I think this is the best way to do what I want to do, check it please:
My Code:
public class MainScheduledTime extends Activity implements OnClickListener{
private int counter = 0;
private int counterTemp = 0;
private TextView label;
private Button button;
private Timer timer = new Timer();
private Handler counterHandler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
label = (TextView) findViewById(R.id.label);
button = (Button) findViewById(R.id.button1);
button.setOnClickListener(this);
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
try {
Thread.sleep(5000); // This emulates an expensive task. For Example: call a webservice and parse the data.
counterTemp++;
setCounter(counterTemp); // This methods needs to be synchronized
counterHandler.post(counterTask);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, 0, 10000);
}
private Runnable counterTask = new Runnable() {
public void run() {
label.setText(getCounter() + "");
}
};
public synchronized int getCounter() {
return this.counter;
}
public synchronized void setCounter(int count) {
this.counter = count;
}
#Override
public void onClick(View arg0) {
}
}
you should do your webservice calls in a Service. then you can schedule the service for execution with the AlarmManager
You can simply use a regular Thread.
AsyncTask is not made for infinite loops.

Looping AsyncTask

I have custom AsyncTask (ListDownloadTask) that download data and updates UI. I want to make it forever while activity opened. So after AsyncTask did the work it must be scheduled. There are delays between attempts.
I tried to use timer but the problem is new ListDownloadTask().execute(); must be invoked from UI thread.
Now i have timer that generates message for Handler. That seems ugly to me. What is best practice?
#Override
public void onCreate(Bundle savedInstanceState) {
// ...
new ListDownloadTask().execute();
}
private static final long DOWNLOAD_UPDATES_DELAY = 5 * 1000;
private final Timer mUpdatesDownloaderTimer = new Timer(true);
Handler mDownloadTrigger = new Handler(new Handler.Callback() {
public boolean handleMessage(Message message) {
new ListDownloadTask().execute();
return true;
}
});
private void scheduleUpdatesDownload() {
mUpdatesDownloaderTimer.schedule(new TimerTask() {
#Override
public void run() {
mDownloadTrigger.sendEmptyMessage(0);
}
}, DOWNLOAD_UPDATES_DELAY);
}
private class ListDownloadTask extends AsyncTask<Long, String, Integer> {
#Override
protected void onPostExecute(Integer result) {
//...
scheduleUpdatesDownload();
}
Check out this example that is kinda similar to what you want to do. It might be better to use a Local Service also though.
Try Handler.sendEmptyMessageDelayed or Handler.sendEmptyMessageAtTime.
Create a service and bind to it in your activity.

How to set a timer in android

What is the proper way to set a timer in android in order to kick off a task (a function that I create which does not change the UI)?
Use this the Java way:
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html
Or there is a better way in android (android's handler)?
yes java's timer can be used, but as the question asks for better way (for mobile). Which is explained Here.
For the sake of StackOverflow:
Since Timer creates a new thread it may be considered heavy,
if all you need is to get is a call back while the activity is running a Handler can be used in conjunction with a
Runnable:
private final int interval = 1000; // 1 Second
private Handler handler = new Handler();
private Runnable runnable = new Runnable(){
public void run() {
Toast.makeText(MyActivity.this, "C'Mom no hands!", Toast.LENGTH_SHORT).show();
}
};
...
handler.postAtTime(runnable, System.currentTimeMillis()+interval);
handler.postDelayed(runnable, interval);
or a Message
private final int EVENT1 = 1;
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Event1:
Toast.makeText(MyActivity.this, "Event 1", Toast.LENGTH_SHORT).show();
break;
default:
Toast.makeText(MyActivity.this, "Unhandled", Toast.LENGTH_SHORT).show();
break;
}
}
};
...
Message msg = handler.obtainMessage(EVENT1);
handler.sendMessageAtTime(msg, System.currentTimeMillis()+interval);
handler.sendMessageDelayed(msg, interval);
on a side note this approach can be used, if you want to run a piece of code in the UI thread from an another thread.
WARNING: Handler's timer (or whatever controls delays) gets paused whenever the CPU goes to deep-sleep, but will continue once CPU wakes up (from where it was paused).
if you need to get a call back even if your activity is not running then, you can use an AlarmManager.
Standard Java way to use timers via java.util.Timer and java.util.TimerTask works fine in Android, but you should be aware that this method creates a new thread.
You may consider using the very convenient Handler class (android.os.Handler) and send messages to the handler via sendMessageAtTime(android.os.Message, long) or sendMessageDelayed(android.os.Message, long). Once you receive a message, you can run desired tasks. Second option would be to create a Runnable object and schedule it via Handler's functions postAtTime(java.lang.Runnable, long) or postDelayed(java.lang.Runnable, long).
As I have seen it, java.util.Timer is the most used for implementing a timer.
For a repeating task:
new Timer().scheduleAtFixedRate(task, after, interval);
For a single run of a task:
new Timer().schedule(task, after);
task being the method to be executed
after the time to initial execution
(interval the time for repeating the execution)
I hope this one is helpful and may take less efforts to implement,
Android CountDownTimer class
e.g.
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
Probably Timerconcept
new CountDownTimer(40000, 1000) { //40000 milli seconds is total time, 1000 milli seconds is time interval
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
}
}.start();
or
Method 2 ::
Program the timer
Add a new variable of int named time. Set it to 0.
Add the following code to onCreate function in MainActivity.java.
//Declare the timer
Timer t = new Timer();
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//Called each time when 1000 milliseconds (1 second) (the period parameter)
}
},
//Set how long before to start calling the TimerTask (in milliseconds)
0,
//Set the amount of time between each execution (in milliseconds)
1000);
Go into the run method and add the following code.
//We must use this function in order to change the text view text
runOnUiThread(new Runnable() {
#Override
public void run() {
TextView tv = (TextView) findViewById(R.id.main_timer_text);
tv.setText(String.valueOf(time));
time += 1;
}
});
It is situational.
The Android documentation suggests that you should use AlarmManager to register an Intent that will fire at the specified time if your application may not be running.
Otherwise, you should use Handler.
Note: The Alarm Manager is intended
for cases where you want to have your
application code run at a specific
time, even if your application is not
currently running. For normal timing
operations (ticks, timeouts, etc) it
is easier and much more efficient to
use Handler.
Here we go.. We will need two classes. I am posting a code which changes mobile audio profile after each 5 seconds (5000 mili seconds) ...
Our 1st Class
public class ChangeProfileActivityMain extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Timer timer = new Timer();
TimerTask updateProfile = new CustomTimerTask(ChangeProfileActivityMain.this);
timer.scheduleAtFixedRate(updateProfile, 0, 5000);
}
}
Our 2nd Class
public class CustomTimerTask extends TimerTask {
private AudioManager audioManager;
private Context context;
private Handler mHandler = new Handler();
// Write Custom Constructor to pass Context
public CustomTimerTask(Context con) {
this.context = con;
}
#Override
public void run() {
// TODO Auto-generated method stub
// your code starts here.
// I have used Thread and Handler as we can not show Toast without starting new thread when we are inside a thread.
// As TimePicker has run() thread running., So We must show Toast through Handler.post in a new Thread. Thats how it works in Android..
new Thread(new Runnable() {
#Override
public void run() {
audioManager = (AudioManager) context.getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
mHandler.post(new Runnable() {
#Override
public void run() {
if(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
Toast.makeText(context, "Ringer Mode set to Normal", Toast.LENGTH_SHORT).show();
} else {
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
Toast.makeText(context, "Ringer Mode set to Silent", Toast.LENGTH_SHORT).show();
}
}
});
}
}).start();
}
}
I'm an Android newbie but here is the timer class I created based on the answers above. It works for my app but I welcome any suggestions.
Usage example:
...{
public Handler uiHandler = new Handler();
private Runnable runMethod = new Runnable()
{
public void run()
{
// do something
}
};
timer = new UITimer(handler, runMethod, timeoutSeconds*1000);
timer.start();
}...
public class UITimer
{
private Handler handler;
private Runnable runMethod;
private int intervalMs;
private boolean enabled = false;
private boolean oneTime = false;
public UITimer(Handler handler, Runnable runMethod, int intervalMs)
{
this.handler = handler;
this.runMethod = runMethod;
this.intervalMs = intervalMs;
}
public UITimer(Handler handler, Runnable runMethod, int intervalMs, boolean oneTime)
{
this(handler, runMethod, intervalMs);
this.oneTime = oneTime;
}
public void start()
{
if (enabled)
return;
if (intervalMs < 1)
{
Log.e("timer start", "Invalid interval:" + intervalMs);
return;
}
enabled = true;
handler.postDelayed(timer_tick, intervalMs);
}
public void stop()
{
if (!enabled)
return;
enabled = false;
handler.removeCallbacks(runMethod);
handler.removeCallbacks(timer_tick);
}
public boolean isEnabled()
{
return enabled;
}
private Runnable timer_tick = new Runnable()
{
public void run()
{
if (!enabled)
return;
handler.post(runMethod);
if (oneTime)
{
enabled = false;
return;
}
handler.postDelayed(timer_tick, intervalMs);
}
};
}
I am using a handler and runnable to create a timer. I wrapper this in an abstract class. Just derive/implement it and you are good to go:
public static abstract class SimpleTimer {
abstract void onTimer();
private Runnable runnableCode = null;
private Handler handler = new Handler();
void startDelayed(final int intervalMS, int delayMS) {
runnableCode = new Runnable() {
#Override
public void run() {
handler.postDelayed(runnableCode, intervalMS);
onTimer();
}
};
handler.postDelayed(runnableCode, delayMS);
}
void start(final int intervalMS) {
startDelayed(intervalMS, 0);
}
void stop() {
handler.removeCallbacks(runnableCode);
}
}
Note that the handler.postDelayed is called before the code to be executed - this will make the timer more closed timed as "expected". However in cases were the timer runs to frequently and the task (onTimer()) is long - there might be overlaps. If you want to start counting intervalMS after the task is done, move the onTimer() call a line above.
I believe the way to do this on the android is that you need a background service to be running. In that background application, create the timer. When the timer "ticks" (set the interval for how long you want to wait), launch your activity which you want to start.
http://developer.android.com/guide/topics/fundamentals.html (<-- this article explains the relationship between activities, services, intents and other core fundamentals of Android development)
I used to use (Timer, TimerTask) as well as Handler to kick off (time-consuming) tasks periodically. Now I've switched the whole to RxJava. RxJava provides Observable.timer which is simpler, less error-prone, hassle-free to use.
public class BetterTimerFragment extends Fragment {
public static final String TAG = "BetterTimer";
private TextView timeView;
private Subscription timerSubscription;
#Override
public View onCreateView(LayoutInflater inflater,
#Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_timer, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
timeView = (TextView) view.findViewById(R.id.timeView);
}
#Override
public void onResume() {
super.onResume();
// Right after the app is visible to users, delay 2 seconds
// then kick off a (heavy) task every 10 seconds.
timerSubscription = Observable.timer(2, 10, TimeUnit.SECONDS)
.map(new Func1<Long, String>() {
#Override
public String call(Long unused) {
// TODO: Probably do time-consuming work here.
// This runs on a different thread than the main thread.
return "Time: " + System.currentTimeMillis();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<String>() {
#Override
public void call(String timeText) {
// The result will then be propagated back to the main thread.
timeView.setText(timeText);
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
Log.e(TAG, throwable.getMessage(), throwable);
}
});
}
#Override
public void onPause() {
super.onPause();
// Don't kick off tasks when the app gets invisible.
timerSubscription.unsubscribe();
}
}
For timing operation you should use Handler.
If you need to run a background service the AlarmManager is the way to go.
this example start the timer unitl destroyed in Kotlin
private lateinit var timerTask: TimerTask
timerTask = object : TimerTask() {
override fun run() {
Log.d("KTZ", "$minutes:$seconds");
timeRecordingLiveData.postValue("$minutes:$seconds")
seconds += 1;
if (seconds == 60) {
Log.d("KTZ", "$minutes:$seconds");
timeRecordingLiveData.postValue("$minutes:$seconds")
seconds = 0;
minutes += 1;
}
}
}
Cancel the timertask in onDestroy()
timerTask.cancel()

Categories

Resources