Android remove runnable callbacks - android

I am designing a bonus runnable such that for each question, if the user can complete the question earlier, there is a bonus score for time remaining for each question.
Code:
private Runnable Run_bonus_countdownHandler = new Runnable()
{
#Override
public void run()
{
if (game_pause ==false)
{
bonus_time_remaining = Math.max((bonus_time_remaining - 10),0);
bonus_countdownHandler.postDelayed(this, 10);
tv_bonus.setText("" + bonus_time_remaining);
if (bonus_time_remaining == 0)
{
tv_bonus.setText("0");
bonus_countdownHandler.removeCallbacks(this);
}
}
else
{
}
}
};
Question:
If the user expires the bonus time period, ie the countdown reach 0, when the user starts another question, the bonus countdown can be run smoothly and at the end be removed. However, if the user can finish earlier for the question, for the next question the countdown would skip some numbers and quickly down to 0.
I would like to ask how could code be modified such that the runnable be properly removed before starting a new question?
Thanks a lot!

I enjoyed your question, and tried to answer and build on it... So I wrote some code to manage these timers in a separate thread, with a simple callback mechanism for notifications.
There is a QuestionTimer class with a simple interface that handles the timed questions in a thread-safe manner, and an activity (MainActivity) to demonstrate how to use it. The QuestionTimer provides its listener with the remaining time through a callback, so you can easily add this as a bonus or add more time to the next question.
You can find the code here: https://gist.github.com/anonymous/182c13a4961515781be6
Hope this helps!

Related

Toast inside thread during heavy workload task

I am updating a database (SQLite) with a lot of data, which takes several minutes. I am doing this on a Thread. At the same time I want to show the progression of the updates (25%, 50%, etc.) through a Toast. Since I am within a thread, I need to use the runOnUiThread() function to run the Toast. Like this:
getActivity().runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getActivity(),"Updating the database...", Toast.LENGTH_SHORT).show();
}
});
It was working fine when the workload was not to big. Now that it is, no toast is being displayed at all.
I have been looking for ways to set a very high priority to the toast's thread, without success. Maybe I can bypass using a thread for the toast in the first place?
Thank you for the insights!
EDIT: In fact, the toast is working, but is displayed after all the work has been done. I want to notify the percentage of the complete update to the user, so I need to have the toast displayed during the update and not after.
I tried removing the workload (no database update, only a Log.d inside the for loop of things to add to the database). And the toast are displayed after the loop is finished although the runOnUiThread() method is called inside the loop.
EDIT 2: I managed to do what I wanted after cleaning up the code and starting fresh. I posted the code I used as the answer below.
After having cleaned up the initial thread, I managed to have something working. I post the code here since it can be used as a template to do a specific task:
Run a initial thread that does tasks periodically for a given number of times (here collect some data). After this given number of times, the collected data is pushed to a database and the user is notified of the advancement of the process (which takes a long time).
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask(){
long t0 = System.currentTimeMillis();
#Override
public void run() {
if(System.currentTimeMillis() - t0 > EXPERIMENT_DURATION ){
processData(dataArrayList); // custom tasks - see below
cancel();
}else {
dataArrayList = collectData(); // custom tasks
}
}
}, 0, INTERVAL);
With:
void processData(Arraylist<Data> dataArrayList){
for(Data data : dataArrayList){
// show progression to the user
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
int percent = Math.round(((float)dataArrayList.indexOf(data))/((float)dataArrayList.size())*100)
Toast.makeText(getActivity(),"Update: " + Integer.toString(percent) + "%", Toast.LENGTH_LONG).show();
}
});
updateDataBase(data);
}
}
I highly recommend you use an AsyncTask.
AsyncTask performs in another working Thread, but it offers a method that is executed in the UI Thread, publishProgress(String ...). that you then customize by overwriting onProgressUpdate(String ...).
EDIT: As read in the comments, AsyncTask is not that good of an option because:
All AsyncTask share a Thread (they don't run on workers as I expected)
For long running Tasks, all other AsyncTasks (system's and your's) will be on hold
This includes AsyncTasks from libraries

Android: what are the pros and cons of using a CountDownTimer vs Thread.sleep()?

What I want to do:
I am wanting to use a worker-thread to regularly update a textfield in the UI Thread. Let's say, every 2 seconds for 30 seconds. I need the 30 second countdown to happen even if the app is not on the foreground. For now, I am evaluating the merits of two different approaches (both using worker-threads) in implementing this. I won't post the full code here to simplify things and also because I am not asking to find any problem in my code. Both solutions work fine.
Solution #1 - use Thread.sleep() inside a for loop
for (int i = 30; i > 0; i-=2) {
Message msg = mHandler.obtainMessage(MSG_ID, i, 0);
msg.sendToTarget();
try {
Thread.sleep(2000);
} catch(Throwable t) {
// catch error
}
}
Solution #2 - use CountDownTimer
Looper.prepare()
new CountDownTimer(30000, 2000) {
public void onTick(long millUntilFinish) {
int seconds = (int)(millUntilFinish);
Message msg = mHandler.obtainMessage(MSG_ID, seconds, 0);
msg.sendToTarget();
}
public void onFinish() {
// left blank for now
}
}.start();
Looper.loop();
My Question
While both work, I am wanting to know if there is a "better" or a "preferred" way to do it for whatever reason. I am thinking there may be areas particularly in battery life but also in performance, accuracy or code design where one solution is better than the other.
What I have done so far to answer this question
My own evaluation so far from reading this SO question and CountDownTimer's documentation are that since both are executed on the worker-thread, both have no ANR possibility. Both solutions will also gaurantee that one "update" will happen only after the previous update has finished. Unfortunately, this is all I have and hoping if anyone can help or guide me to an insightful and/or similar SO question I may have overlooked or was unsuccessful in finding.
I write this question a bit cautiously as I don't have a problematic code which requires debugging but I think this falls within SO's category of a "specific programming problem", which hasn't been answered, and not included in the list of off-topic answers.
1.Calling Thread.sleep pauses the thread execution for a while where as countdown timer actually uses callbacks to notify timer expiry events and is asynchronous in nature.
2.If the thread execution pauses, you will not be able to use that specific thread for any other operation until the sleep timeout hence it is not recommended to use Thread.sleep approach. Obviously there is a load on cpu if it has to resume the thread execution and pause it.Where as in the case of countdown timer the thread continue to be in execution/idle state and as when events occur it fires to the respective listeners.
call Thread.sleep() method is not good idea beacuse ii sleep the UI Thread and disadvantage of CountDownTimer is, It Will stop when ur screen is off hence instead of this two try Handler for that like this
Handler handler;
Runnable runnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run()
{
if (dataReceived)
{
cancelHandler();
}
}
};
handler.postDelayed(runnable, 100);
}
public void cancelHandler()
{
handler.removeCallbacks(runnable);
}

How to set up a timer for an android game ?

I want to programm a game for Android.
Play principle: The user should have a short time to choose the correct answer.
My problem is the combination between the input (choosing the answer) and the time (countdown). I tried to run a thread, but the thread isn't stoppable. So the user gives the answer, the next activity will be shown and after a while (when the "timer" becomes 0) the activity will be shown again.
How could I implement this in a correct way?
Should I use Thread, Handler, CountDownTimer ?
You can keep a running timer using this on init:
Timer updateTimer = new Timer("update");
updateTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
updateGUI();
}
}, 0, 1000);
long startTime = System.currentTimeMillis();
Then in a Thread:
//Clock update
currentTime = System.currentTimeMillis() - startTime;
SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
clock.setText(sdf.format(currentTime));
clock.invalidate();
You could stop the Thread with a boolean inside or outside as you please?
Okay, I don't know the specific libraries to use, and I haven't done any thread programming myself, but I would think of the program as a state machine. I hope it helps :/
Set up a boolean userHasAnswered = false.
Set up a specialized listener (e.g. touch listener for some button) for answers.
If the listener gets an appropriate response from the user, set userHasAnswered = true.
When question loads up, start the thread which counts down.
If user fails to give ans when the time reaches zero, just call loadNextQuestion().
In your thread, do periodic checks every few units of time to see if userHasAnswered == true, and if it is true, then call updateScore() and loadNextQuestion().
You may want to have a look at alarm manager

How can I keep UI elements responsive while my program is working?

The UI I am creating includes a button, which once pressed, is supposed to find and display values repetitively until the user presses the button again.
This is my button's initialization with the listener:
pollOn = false;
pollButton = (Button) findViewById( R.id.pollButton );
pollButton.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i( "POLL BUTTON", "onClick" );
if( !pollOn ) {
Log.i( "POLL BUTTON", "!pollOn" );
pollOn = true;
methodToReadAndDisplayData();
} else {
Log.i( "POLL BUTTON", "else pollOn" );
pollOn = false;
}
}
});
It is not shown here to make things easier to read, but the way I currently have it working is to call the methodToReadAndDisplayData() 5 times in a for loop and then stop.
So when I press the pollButton initially, the UI freezes and Log.i("POLL BUTTON", "onClick") is displayed at the top of LogCat. I then press the pollButton while it appears to be frozen, and after all of the work is done and the UI unfreezes, Log.i("POLL BUTTON", "onClick") is shown at the very end of my LogCat. The way I am interpretting this is that the button click is entered into a queue, and the onClick method is called after all 5 iterations of the for loop have been completed.
Another large part of this problem is that the work being done is mainly in a native library, and is called using the NDK. I am unsure if this has anything to do with the UI freezing, but it definitely increases the processing time needed.
If anything is unclear or confusing please let me know and I will try to clarify things.
Any information on this situation would be greatly appreciated.
Doing some stuff while keeping the UI responsive can achieved by many methods, two of them are very common. Async Task and threads.
AsyncTask:
It's a class which have a few methods which help you to do time consuming work while updating the UI at the same time. For Example: If you want to search a specific word in a big document, do the reading and searching stuff in doInBackground() (a method of AsyncTask class) and you can display a progress bar and notify the user with your progress with onProgressUpdate(). This gives your app more professional feel and at the same time helps you executing time consuming task in background.
Threads:
They are simple runnable threads. You can execute non UI stuff with these threads but you can't perform UI tasks in them (as UI is not thread safe). For dealing with UI in these threads, you will have to use Handlers, which is quite cumbersome for beginners to get a grip and understanding of them.
So depending on your needs and app you can choose the one best suits you.
Because you're running on the main thread the system UI freezes, you'd be better off running in a new thread which would leave your UI running as normal. Below is an example of how to run your method in a new thread.
new Thread(new Runnable() {
#Override
public void run() {
methodToReadAndDisplayData();
}
}).start();
Note that if your method interacts with the UI in any way, you need to do it via the following:
When you want to update your UI:
Handler threadHandler = new Handler();
threadHandler.post(updateRunnable);
Update your UI here:
Runnable updateRunnable = new Runnable() {
public void run() {
example.setText(newValue);
}
};
Try that and see if there's any improvement. I've not worked with the NDK, just the standard SDK so there may be difference I'm unaware of.
Do it on another thread. Use an AsyncTask to call methodToReadAndDisplayData.

How do I use Android's CountDownTimer?

How do I use the Android's CountDownTimer?
I basically want to have the following scenario:
boolean 3_s_passed = false;
// setup counter to change 3_s_passed=true when it finishes
counter.start();
while(true){
if(3_s_passed || user_is_Done) break;
// do some stuff which may set user_is_Done to true
}
So either 3 seconds passed or the user finishes and I'm out of the loop.
Will the while-loop code run before the counter finishes? Is my understanding of the CountDownTimer correct?
Thanks for your help
You could use a handler for this. Make a Runnable with the task to complete after 3 seconds or when the user does the task. Post it for 3 seconds and remove callbacks if the user does whatever. The code same below shows how to properly use the Handler but isn't looping to allow the user to make the action you'll have to figure that out on your own :)
Runnable action = new Runnable(){
public void run(){
//...
}
};
mHandler.postDelayed(action, 3000);
if(userDone){
mHandler.removeCallbacks(action);
mHandler.post(action);
}
Don't use this class it contains a race in cancel method.
https://code.google.com/p/android/issues/detail?id=58668
cancel don't work in case of race between onTick and cancel.
It's better to implement it from scratch without races.
In other case you will have a problem until official fix.

Categories

Resources