I'm solving an exercise for my university and there is this code in my pdf that my supposed to use to delay the change of the colour of the text on a button, i don't understand how it exactly works so please can someone explain it
HandlerThread handlerThread = new HandlerThread("showText");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
Runnable runnable = new Runnable() {
int i = 0;
#Override
public void run() {
i++;
handler.postDelayed(this, 1000);
if (i > 1)
button.setTextColor(getResources().getColor(android.R.color.transparent));
}
};
handler.post(runnable);
This code is in obscure way causing that Runnable to be called with the delay of 1s (every second) because it reschedules itself each time. The int i is guarding button.setTextColor from executing the first the.
This code is however very messy, the way it should be done is as follows:
Runnable runnable = new Runnable() {
#Override
public void run() {
button.setTextColor(getResources().getColor(android.R.color.transparent));
}
};
handler.postDelayed(runnable, 1000);
or with lambda expression just as following:
handler.postDelayed(() -> button.setTextColor(getResources().getColor(android.R.color.transparent)), 1000);
Related
In my android app I'm trying to show a sequence of button presses (one after another) to remember and to repeat by user. To do this I'm using runnables with postDelay methods to change UI. Currently all buttons in sequence are showing at the same moment and all are hiding at the same moment. Could somebody help me to synchronize runnables to show one after another not together? Code is given below.
for(int i = 0; i < generatedSequenceToPlay.size(); i++){
final int position = i;
_handler.postDelayed(new Runnable() {
#Override
public synchronized void run() {
findButtonById(_defuseButtonHandler.getKeyByValue(generatedSequenceToPlay.get(position).toString())).setPressed(true);
}
}, 500);
_handler.postDelayed(new Runnable() {
#Override
public synchronized void run() {
findButtonById(_defuseButtonHandler.getKeyByValue(generatedSequenceToPlay.get(position).toString())).setPressed(false);
}
}, 500);
}
Check the method explanation of postDelayed on this page.
Causes the Runnable r to be added to the message queue, to be run
after the specified amount of time elapses. The runnable will be run
on the thread to which this handler is attached.
When the specified time elapses, the runnable task will be got from message queue and attached to thread for running. All runnable tasks will be run almost at the same time after 500 milliseconds since each task isn't time-consuming. So as #pskink suggested, give each runnable task a different timer will do you the favour.
For example, you can modify code like below.
for(int i = 0; i < generatedSequenceToPlay.size(); i++){
final int position = i;
_handler.postDelayed(new Runnable() {
#Override
public synchronized void run() {
findButtonById(_defuseButtonHandler.getKeyByValue(generatedSequenceToPlay.get(position).toString())).setPressed(true);
}
}, 500 + i * 100);
_handler.postDelayed(new Runnable() {
#Override
public synchronized void run() {
findButtonById(_defuseButtonHandler.getKeyByValue(generatedSequenceToPlay.get(position).toString())).setPressed(false);
}
}, 500 + i * 100);
}
I have a list of hex colors with a duration in milliseconds for each one. I would like to fill the screen with each color for its duration, then move on to the next color.
I tried to iterate over the colors to do the following:
myView.setBackgroundColor(Color.parseColor( theColor ));
SystemClock.sleep( theDuration );
myView.setBackgroundColor(Color.parseColor( nextColor ));
SystemClock.sleep( nextDuration );
etc...
which seemed obvious to me but doesn't do anything to the view when it's running, at least in my AVD. I'm learning that it's because Android only draws at predefined times. (I tried calling "Invalidate()" as well with no luck.)
What is the best way to display all the colors consecutively?
(I realize I shouldn't be calling sleep() either, so any suggestions for that would also be appreciated.)
Thanks.
new Thread() {
#Override
public void run() {
YourActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
myView.setBackgroundColor(Color.parseColor( theColor ));
}
Thread.sleep( theDuration);
YourActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
myView.setBackgroundColor(Color.parseColor( nextColor ));
}
Thread.sleep( nextDuration );
}
}.start();
Put this in a method and call it.
There are many ways to achieve what you want. One could be to use Handler and Runnable. Assuming you know how to get current color and duration, you could do:
declare Runnable as class variable
private Runnable runnable = null;
inside onCreate(), after you set initial view, initialise Handler
final Handler handler = new Handler();
initialise runnable and change the background in run() method
runnable = new Runnable() {
#Override
public void run() {
//change the color
myView.setBackgroundColor(currentColor);
//run it again in nextDuration miliseconds
handler.postDelayed(toggle, nextDuration);
}
};
//start runnable in theDuration miliseconds
handler.postDelayed(toggle, theDuration);
You could have arrays of colors and durations and cycle through them with index variable. This is assuming that myView is a valid view.
EDIT:
To those who downvoted, read the documentation for Handler:
When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it...
In other words, you are creating a handler in onCreate() of your activity, so it will be able to update your view.
This blogpost from adroid-developers website uses very similar construct as proposed above.
The Handler runs the update code as a part of your main thread, avoiding the overhead of a second thread and also making for easy access to the View hierarchy used for the user interface.
See here and here answered by CommonsWare and here - answered by Laith Alnagem.
I ended up creating a Runnable inside the my button click event handler. Everything (looping through the colors and durations plus "sleeping" based on the durations) is done in the Runnable run() method.
public void playOnClick(View v) {
Runnable runnable = new Runnable() {
public void run() {
...
}
Then I created a handler inside my UI Activity class that just changes the color of the background.
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle b = msg.getData();
String theColor = b.getString("color");
myView = (View) findViewById(R.id.bigView);
myView.setBackgroundColor(Color.parseColor(theColor));
}
};
Inside the run() method, he Runnable sends a message to the handler containing the background color using Bundle/Message objects:
b = new Bundle();
b.putString("color", theColor);
msg = new Message();
msg.setData(b);
handler.sendMessage(msg);
I have two AsyncTasks doing network operations. I want to call them periodically (like after one min.). How do I do that? I dont think I can do it on the UI thread. Do i need to create a new thread? Is it possible to implemet this without AlarmManager/Service?
Basically I want to exectue these two statements periodically after one min.
new UploadAsyncTask().execute();
new DownloadAsyncTask().execute();
Thank you
Just use a timer.
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
new UploadAsyncTask().execute();
new DownloadAsyncTask().execute();
}
});
}
};
timer.schedule(task, 0, 1000); //it executes this every 1000ms
In my method, I want to call another method that will run 1 second later. This is what I have.
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
MyMethod();
Log.w("General", "This has been called one second later");
timer.cancel();
}
}, 1000);
Is this how it's supposed to be done?
Are there other ways to do it since I'm on Android?
Can it be repeated without any problems?
There are several alternatives. But here is Android specific one.
If you thread is using Looper (and Normally all Activity's, BroadcastRecevier's and Service's methods onCreate, onReceive, onDestroy, etc. are called from such a thread), then you can use Handler. Here is an example:
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run()
{
myMethod();
}
}, 1000);
Note that you do not have to cancel anything here. This will be run only once on the same thread your Handler was created.
Instead of a Timer, I'd recommend using a ScheduledExecutorService
final ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
exec.schedule(new Runnable(){
#Override
public void run(){
MyMethod();
}
}, 1, TimeUnit.SECONDS);
If you are not in UI thread, consider adding a very simple:
try
{
Thread.sleep( 1000 );
}//try
catch( Exception ex)
{ ex.printStackTrace(); }//catch
//call your method
ScheduledExecutorService or AsyncTask for UI related.
Note that if you are to update UI, that code should be posted to UI thread. as in Processes and Threads Guide
final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(bitmap);
}
});
There is also nice postDelayed method in View
mImageView.postDelayed(new Runnable(){
#Override
public void run() {
mImageView.setImageResource(R.drawable.ic_inactive);
}
}, 1000);
that will update UI after 1 sec.
So I'm trying to make a "live feed" essentially, and my code is shown below. Basically, I got "The Application Has Stopped Unexpectedly" error, so I debugged. When I debugged, it said "Timer.class not in android.jar". I know my refreshFeed() static method works perfectly fine (tested it without the timer), so it can't be that. Is there something I'm missing here? Any help is greatly appreciated!
Timer time = new Timer();
TimerTask refresh = new TimerTask(){
public void run(){
feedEntry.refreshFeed();
}
};
time.scheduleAtFixedRate(refresh, 0, 10000);
Both Timer and TimerTask present in java.util package.
What you need to is do is use handler.
Read about handler if you are new to android.
http://developer.android.com/reference/android/os/Handler.html
Handler handler = new Handler();
t = new Timer();
timeTask = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
feedEntry.refreshFeed();
}
});
}};
t.scheduleAtFixedRate(timeTask, 0, 1000);