I know the title is somewhat confusing, my problem is this: I want to "pause" my program multiple times (via a loop) using sleep(ms) and make changes to several buttons that the user has pressed. I understand that changes to the UI can only be made in the main thread, so I am wondering how to convert this code into an Async task. I also remember reading somewhere that Async task can only be called once? If this is so, what other solutions could I look into?
View.OnClickListener SimulateButtonHandler = new View.OnClickListener() {
#Override
public void onClick(View v) {
for(int j=0;j<169;j++) //169 buttons to click
{
if(ClickedPoints[j]!=null) //how I keep track of which buttons has clicked
{ //clear button color
Drawable d2 = ClickedPoints[j].getBackground();
ClickedPoints[j].invalidateDrawable(d2);
d2.clearColorFilter();
}
}
Timer timer = new Timer();
for(int i=0;i<169;i++)
{
if(ClickedPoints[i]!=null)
{ //change the color after some time
Simulate(timer, i);
//clear color again
Drawable d2 = ClickedPoints[i].getBackground();
ClickedPoints[i].invalidateDrawable(d2);
d2.clearColorFilter();
}
}
}
};
public void Simulate(Timer timer, final int index)
{
timer.schedule(new TimerTask()
{
public void run() {
Sim(index);
}
}, 1000); //delay for some amount of time, then rehighlight the button
}
private void Sim(int i)
{
Drawable d1 = ClickedPoints[i].getBackground();
PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_ATOP);
d1.setColorFilter(filter);
}
You'd be better off using a Thread to run your background work (and pausing) and a Handler to access the UI thread.
Here's a good tutorial on using handlers with threads.
Related
I am writing here because I have a very annoying problem in Android Studio.
My "application" is extremely simple, one page with 13 button; All I want is simple: update the first twelve buttons one by one when I click the 13th button.
I would like to see buttons updating with a little interval between each of them, but I can't understand how to do it.
I tried many tricks inside the "onClick" method but I can not figure out how to solve it; what I obtain is that after some time (the time obtained adding up the various "sleep" I put in the function) all the buttons become colored at the same time.
I put my last attempt, but if you have any other way to do that I am willing to change the way to proceed.
int[] buttonIDs = new int[] {R.id.button1, R.id.button2, R.id.button3, R.id.button4, R.id.button5, R.id.button6, R.id.button7,
R.id.button8, R.id.button9, R.id.button10, R.id.button11, R.id.button12 };
int currentI = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button goButton = (Button) findViewById(R.id.button13);
goButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (currentI < buttonIDs.length) {
Button b = (Button) findViewById(buttonIDs[currentI]);
b.setBackgroundColor(Color.parseColor("#FF22FF"));
currentI++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread t = new Thread() {
public void run() {
goButton.performClick();
}
};
t.start();
}
}
});
}
The result of this attempt is that the first button become colored and then I get "Application has stopped" error on the Android Emulator.
Thanks in advance
Use this
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 1000ms
}
}, 1000);
The basic idea here is that you need to create a new thread which signals the UI thread to update each button. In between each update, the new thread needs to wait until the UI has a chance to perform the update. I'm not very experienced with this kind of thing. You can most likely do this with a Handler. There might be more high-level tools you can use instead, but I'm not sure.
You definitely do not want to sleep the UI thread. This will only cause the UI to become unresponsive.
I have this code:
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!clicked){
clicked = true;
fab.setImageResource(R.drawable.ic_media_stop);
char[] userInput = et.getText().toString().toLowerCase().toCharArray();
compareToMap(userInput);
}else{
clicked = false;
fab.setImageResource(R.drawable.ic_media_play);
}
}
});
When the floating action button is clicked, I want it to change to a stop symbol and then execute the function afterwards. What is happening is that the code is being executed before the image on the button changes. The image only changes once all of the code has been executed from the compareToMap function even though it is placed before it in the code. Is there a way to make sure that the image changes before the compareToMap function executes?
Note: The compareToMap function contains Thread.sleep methods which is causing the UI to block (I think), but shouldn't the image change before that function is executed?
At this moment the UI didn't load yet. If you want to do some work after the UI is loaded you can use the class Handler.
long postDelay = 100; //The delay (in milliseconds) until the Runnable will be executed
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Code that you want to execute after the UI is loaded
compareToMap(userInput);
}
}, postDelay);
Note: You can't use Thread.sleep on the UI main thread. You can learn more here. https://developer.android.com/guide/components/processes-and-threads.html.
You can use AsyncTask to execute the compareToMap(userInput) method, this will run the compareToMap method in a separated thread and the UI will not be blocked; something like this :
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fab.setImageResource(!clicked ? R.drawable.ic_media_stop : R.drawable.ic_media_play);
if (!clicked) {
// Cancel the executing AsyncTask if there's one already running
if (mAsyncTask != null) {
mAsyncTask.cancel(true);
}
mAsyncTask = new AsyncTask<String, Void, Void>() {
#Override
protected Void doInBackground(String... params) {
compareToMap(userInput);
return null;
}
};
mAsyncTask.execute();
}
clicked != clicked;
}
});
More info about AsyncTasks here or you can check this tutorial.
I want to change the image of an Image view using a for loop, a String array and the png images in drawable folder.One Image should rest for 5 seconds then the next should appear.Here is the code I used.And it's not working properly.The images are not changing.It waits 5 seconds per each loop but the images are not changing.At last the last image is loaded.Please someone help me...
private String [] array1 = {"card2c","card2d","card2h","card2s",
"card3c","card3d","card3h","card3s",
"card4c","card4d","card4h","card4s",
"card5c","card5d","card5h","card5s",
"card6c","card6d","card6h","card6s",
"card7c","card7d","card7h","card7s",
"card8c","card8d","card8h","card8s",
"card9c","card9d","card9h","card9s",
"card10c","card10d","card10h","card10s",
"cardjc","cardjd","cardjh","cardjs",
"cardqc","cardqd","cardqh","cardqs",
"cardkc","cardkd","cardkh","cardks",
"cardac","cardad","cardah","cardas",};
for(int j=0;j<52;j++)
{
int resID_temp1 = getResources().getIdentifier(array1[j] , "drawable", getPackageName());
Drawable image_temp1 = getResources().getDrawable(resID_temp1);
Player1.setImageDrawable(image_temp1); // Player1 is the ImageView
try {
Thread.sleep(5000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
Tried the Timer
(for(int j=0;j<52;j++)
{
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//switch image here
int resID_temp1 = getResources().getIdentifier(array1[j] , "drawable", getPackageName());
Drawable image_temp1 = getResources().getDrawable(resID_temp1);
Player1.setImageDrawable(image_temp1);
}
}, 0, 5000);
Based on your code example, you're changing the image resource, but then immediately sleeping the same thread that changed the image resource which will block it and prevent the image from visibly changing (particularly bad if this is the UI thread as this will lock up your app).
You should do as JohnyTex suggests and use a TimerTask to change the image every 5 seconds which does not require sleeping and so will not block the current thread.
Try using timers instead:
//Declare final variable here
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
//Switch (declared final) image variable here
}
});
}
}, 0, 5000);
Something like that... I am not by my computer though.
Concepts: runOnUithread and final variables might also be of interest to read about. final is because otherwise the variable cant be manipulated on another thread (actually Its only another scope really here). RunOnUiThread is because graphical components must only be manipulated on the main UI thread, although the TimerTask is run on another separate thread.
I have a TextView. I want to update its text (append a "1") after 1 second of a button click.
public class HaikuDisplay extends Activity {
Method m;
Timer t;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
t = new Timer();
m = HaikuDisplay.class.getMethod("change");
}
//Event handler of the button
public void onRefresh(View view)
{
//To have the reference of this inside the TimerTask
final HaikuDisplay hd = this;
TimerTask task1 = new TimerTask(){
public void run(){
/*
* I tried to update the text here but since this is not the UI thread, it does not allow to do so.
*/
//Calls change() method
m.invoke(hd, (Object[])null);
}
};
t.schedule(task1, 1000);
}
public void change()
{
//Appends a "1" to the TextView
TextView t = (TextView)findViewById(R.id.textView1);
t.setText(t.getText() + "1");
}
//Event handler of another button which updates the text directly by appending "2".
//This works fine unless I click the first button.
public void onRefresh1(View view)
{
TextView t = (TextView)findViewById(R.id.textView1);
t.setText(t.getText() + "2");
}
}
Consider all Exceptions be handled.
On first click, m.invoke gives InvocationTargetException. But it calls the method change() on successive invokes without any Exceptions(verified by logging). But it does not update the text. Where am I wrong?
Also, I see in the debugger that it creates a new Thread every time I click the button. That is fine. But why isn't it removing the previous Threads though their execution has been completed?
Do something like this
public void onRefresh1(View v) {
// You can have this in a field not to find it every time
final EditText t = (EditText) findViewById(R.id.textView1);
t.postDelayed(new Runnable() {
#Override
public void run() {
t.append("1");
}
}, 1000);
}
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// Update UI
}
}, 1000);
implement this on button click
UPDATE:
There are some other answers. dtmilano suggested another solution which is almost same to mine except he is calling the postDelayed method of View class and In my answer I used postDelayed method of handler class.
from the api reference of android the postDelayed method of Handler says
The runnable will be run on the thread to which this handler is
attached.
and the postDelayed method of View says
The runnable will be run on the user interface thread.
This is the only difference between these two solution. in my answer instead of creating new Handler every time you can use any other handler instance. Then the runnable will be run on that thread where that specific handler is declared. And if the postDelayed of EditText is used the the runnable method will be run on the user Interface Thread.
Now the performance issue, both has the same performance (If anybody can prove me wrong with reference I will be happy)
That's looking awful convoluted - have you considered using CountDownTimer instead?
new CountDownTimer(1000, 1000) {
public void onTick(long millisUntilFinished) {
// no-op
}
public void onFinish() {
change();
}
}.start();
This should call change (and hence change the text) on the UI thread, avoiding reflection and threading errors.
Hi Use the following code for that. Hope this will help you .
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
// your code here
}
},
1000
);
Have a look of this question also.
display data after every 10 seconds in Android
You can try with this also.
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
public void run() {
doStuff();
/*
* Now register it for running next time
*/
handler.postDelayed(this, 1000);
}
};
**EDIT 3**
Try with this once you are need to enable once (i mean if you put your code in yourmethod()== this will get automatically call 1 seconds once.
private Timer timer;
TimerTask refresher;
// Initialization code in onCreate or similar:
timer = new Timer();
refresher = new TimerTask() {
public void run() {
yourmethod();
};
};
// first event immediately, following after 1 seconds each
timer.scheduleAtFixedRate(refresher, 0,100);
I have an array of drawables, that I would like to change by my own timer to a imageview.
(i tried the other option with xml and setBackgroundResource, but does not work for me as I have hundret of pics and always got memory problem as it looks android assign already the whole memory for all pics at once. (just in this demo i shorted it to 4 images)
Ok, so first i make my array
private static int[] draws = {
R.drawable.frankiearmevor_0001,
R.drawable.frankiearmevor_0002,
R.drawable.frankiearmevor_0003,
R.drawable.frankiearmevor_0002
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imgView = (ImageView) findViewById(R.id.fredi);
// create timer
Timer updateProgressTimer = new Timer();
updateProgressTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
myloop();
}
}, 0, 150);
}
int mycounter;
public void myloop()
{
mycounter++;
if (mycounter > 4) mycounter = 1;
imgView.setImageResource(draws[mycounter-1]);
String hallo; hallo = "now: "+mycounter;
Log.d("1",hallo);
}
when I assign only a fixed image: imgView.setImageResource(draws[2]);
it shows that fine and I see also my thread is logged fine, but when I exchange the
fixed resource draws[2] into a dynamic draws[mycounter-1] .. i just get a black screen, no error, nothing.
what to do, so i will show the images :)
thx
chris
EDIT: 22. August:
I tried now with the comment I got, it compiles fine, but somehow there is an error i guess.. it crash:
imgView = (ImageView) findViewById(R.id.fredi);
Timer updateProgressTimer = new Timer();
updateProgressTimer.scheduleAtFixedRate(new TimerTask()
{
#Override
public void run()
{
//myloop();
imgView.post (new Runnable()
{
public void run()
{
mycounter++;
if (mycounter > 10) mycounter = 1;
imgView.setImageResource(draws[1]);
//imgView.invalidate();
String hallo; hallo = "now: "+mycounter;
Log.d("1",hallo);
}
});
}
}, 0, 150);
The ImageView update should happen on the UI Thread...
Refer this answer. The TimerTask runs on a different thread, so you've to use the imgView.post() to update the UI Component.
Are you sure you need to update the Component every 150ms? That's very expensive.
Good Luck.