I have an activity with 8 buttons in it. I want the backgrounds for all the buttons to randomly change between each other every second that the activity is running. To do this I use the following code:
public class CoinFrenzy extends Activity {
private int draw1 = R.drawable.buttonshape1;
private int draw2 = R.drawable.buttonshape2;
private int draw3 = R.drawable.buttonshape3;
private int draw4 = R.drawable.buttonshape4;
private int draw5 = R.drawable.buttonshape5;
private int draw6 = R.drawable.buttonshape6;
private int draw7 = R.drawable.buttonshape7;
private int draw8 = R.drawable.buttonshape8;
private ArrayList<Integer> selector = new ArrayList<>();
private ArrayList<Button> buttonlist = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_coin_frenzy);
Button btn1 = (Button) findViewById(R.id.angry_btn);
Button btn2 = (Button) findViewById(R.id.angry_btn2);
Button btn3 = (Button) findViewById(R.id.angry_btn3);
Button btn4 = (Button) findViewById(R.id.angry_btn4);
Button btn5 = (Button) findViewById(R.id.angry_btn5);
Button btn6 = (Button) findViewById(R.id.angry_btn6);
Button btn7 = (Button) findViewById(R.id.angry_btn7);
Button btn8 = (Button) findViewById(R.id.angry_btn8);
buttonlist.add(btn1);
buttonlist.add(btn2);
buttonlist.add(btn3);
buttonlist.add(btn4);
buttonlist.add(btn5);
buttonlist.add(btn6);
buttonlist.add(btn7);
buttonlist.add(btn8);
selector.add(draw1);
selector.add(draw2);
selector.add(draw3);
selector.add(draw4);
selector.add(draw5);
selector.add(draw6);
selector.add(draw7);
selector.add(draw8);
h.postDelayed(myRunnable, 1000);
}
public static int randInt(int min, int max) {
// NOTE: Usually this should be a field rather than a method
// variable so that it is not re-seeded every call.
Random rand = new Random();
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
private Handler h = new Handler(Looper.getMainLooper());
private Runnable myRunnable = new Runnable() {
public void run() {
for (Integer x : selector) {
int randomInt = randInt(0, 7);
int back = selector.get(randomInt);
Button currbtn = buttonlist.get(randomInt);
currbtn.setBackgroundResource(back);
}
//run again in one second
h.postDelayed(myRunnable, 1000);
}};
However, after one second passes my app crashes without any logcat errors.
First do these 2 things:
You have to remove change the background of the button code from thread. This is the main cause of crash.
Below you can find two methods on how can one run a code on the main/UI thread on android:
runOnUIThread Activity’s method
runOnUiThread(new Runnable() {
public void run() {
// change background color here
}
});
Handler
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
// UI code goes here
}
});
you might want to use one of the two methods whenever you want to update the UI like updating colors on views or other UI related stuff. Otherwise, the application might crash because the UI classes on Android are not thread safe.
This will help you!!
Replace your
private Handler h = new Handler();
to
private Handler h = new Handler(Looper.getMainLooper());
otherwise your code will be run outside the UI thread
You have to pass dynamic index into
int randomInt = randInt(0, 7);
you are always passing same values for min is 0 and max is 7, so it doesn't change any background.
Use selector random ids replace 7 with dynamic loop value x.
private Runnable myRunnable = new Runnable() {
public void run() {
for (Integer x : selector) {
int randomInt = randInt(0, x);
int back = selector.get(randomInt);
Button currbtn = buttonlist.get(randomInt);
currbtn.setBackgroundResource(back);
}
//run again in one second
h.postDelayed(myRunnable, 1000);
}};
It would be helpful to you.
Related
I have some problem with my method.
I have 5 input fields on screen, and when this screen is created (onCreate method), i want that this element will appear with animation one after one and not all together.
Here is the method that I created.
private void setInputsAnimation() {
for (int i = 0; i < inputs.size(); i++) {
final int finalI = i;
handler.postDelayed(new Runnable() {
#Override
public void run() {
inputs.get(finalI).setVisibility(View.VISIBLE);
YoYo.with(Techniques.DropOut)
.duration(1000)
.repeat(0)
.playOn(inputs.get(finalI));
}
}, 500);
}
}
For some reason, when I run this method , the animation is working but for element together, and not one after one.
Here is the inputs array method:
private List<EditText> inputs = new ArrayList<>();
private List<EditText> inputs() {
inputs.add(et1);
inputs.add(et2);
inputs.add(et3);
inputs.add(et4);
inputs.add(et5);
return inputs;
}
With the following code,the thread is activated on button click in the controller class. Thing is, I want to be able to change the values in he Line array, to have to anchor pane erase old lines and add new lines.This is in the controller.java after main in launched.
static startVal = -1,endVal = -1;
Lines L;//this is supposed to store new lines after some methods are called
//this method is called on button click and I want it to start again every time the button is clicked
public void drawPath(){
Task task = new Task<Void>() {
#Override
public Void call() throws Exception {
while(true){
int i = 0;
while (i<5) {
final int finalI = i;
Platform.runLater(new Runnable() {
#Override
public void run() {
anchPane.getChildren().add(L[finalI]);
if(startVal == -1)
startVal = anchPane.getChildren.size()-1;
else
endVal = anchPane.getChildren().size()-1;
}
});
i++;
Thread.sleep(2000);
}
//removeLines();
anchPane.getChildren().remove(startVal,endVal);
}
}
};
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
}
I want to change the background of an ImageView programatically, but inside a for / while loop on a separate thread. In my example, I have 3560 ImageViews in an ArrayList called 'lights'. I want to change each one's background inside a loop after a short delay, i.e. one changes every second.
ArrayList<ImageView> lights = new ArrayList<>();
int numberOfLights = 3560;
I originally used this code, but there is the problem that 'i' must be declared final as it is being called from an inner class, impossible if i need it for the for loop ...
Handler h = new Handler();
for( int i = 0; i < numberOfLights; i++) {
h.postDelayed(new Runnable() {
#Override
public void run() {
lights.get(i).setBackgroundResource(R.drawable.light_white);
}
}, 1000);
}
Therefore I tried using a global variable:
Handler h = new Handler();
counter = 0;
for( ; counter < numberOfLights; counter++) {
h.postDelayed(new Runnable() {
#Override
public void run() {
lights.get(counter).setBackgroundResource(R.drawable.light_white);
}
}, 1000);
}
It is as though this counter is completely ignored, h.postDelayed runs even when the counter is more than numberOfLights, I've tried just normal Threads with a Thread.sleep call, resulting in 'Only the original thread that created a view hierarchy can touch its views' and also used the runOnUiThread method but having no luck.
Any help is much appreciated.
Use the for each loop. It's way more elegant than the traditional loop and in this case you can make the local variable final
for(final ImageView light: lights) {
h.postDelayed(new Runnable() {
#Override
public void run() {
light.setBackgroundResource(R.drawable.light_white);
}
}, 1000);
}
also, define handler as
Handler h = new Handler(Looper.getMainLooper());
in order to run the code on UI thread
Just make a new variable:
final int iCopy = i;
Then use that in your Runnable.
Handler h = new Handler();
for( int i = 0; i < numberOfLights; i++) {
final int iCopy = i;
h.postDelayed(new Runnable() {
#Override
public void run() {
lights.get(iCopy).setBackgroundResource(R.drawable.light_white);
}
}, 1000);
}
This however may not avoid the IndexOutOfBoundsException if lights is being modified in the mean time. In that case a range check or making a copy of the array or light would solve your issue.
I have to make an android memory game where a sequence of colors show up on the screen and you then have to click the colors that came up. To display the sequence of colors I'm just using an unclickable button that changes colors. I'm currently doing this using a thread with runOnUiThread but every time it will only change the button to the last color I want it to. Why wont it change to any previous color?
final ArrayList<Integer> colours = new ArrayList<Integer>();
Button buttonOne = (Button) findViewById(R.id.colourOne);
Button buttonTwo = (Button) findViewById(R.id.colourTwo);
Button buttonThree = (Button) findViewById(R.id.colourThree);
Button buttonFour = (Button) findViewById(R.id.colourFour);
ColorDrawable buttonOneColor = (ColorDrawable) buttonOne.getBackground();
ColorDrawable buttonTwoColor = (ColorDrawable) buttonTwo.getBackground();
ColorDrawable buttonThreeColor = (ColorDrawable) buttonThree.getBackground();
ColorDrawable buttonFourColor = (ColorDrawable) buttonFour.getBackground();
int one = buttonOneColor.getColor();
int two = buttonTwoColor.getColor();
int three = buttonThreeColor.getColor();
int four = buttonFourColor.getColor();
colours.add(one);
colours.add(two);
colours.add(three);
colours.add(four);
runOnUiThread(new Runnable() {
#Override
public void run() {
for(int x = 0; x < colours.size(); x++) {
try {
Button light = (Button) findViewById((R.id.light));
light.setBackgroundColor(colours.get(x));
Thread.sleep(1000);
} catch (Exception e) {
System.out.println(e);
}
}
}
});
The thread is sleeping after each setBackground color but the buttons color wont actually change until the loop reaches its last loop.
You have to create a new Thread and inside on the Thread call runOnUiThread and change the color. Also you have to initialize the button out of the Thread. You must declare variable x out of the onCreate method
new Thread(new Runnable() {
#Override
public void run() {
for(x = 0; x < colours.size(); x++) {
runOnUiThread(new Runnable() {
#Override
public void run() {
light.setBackgroundColor(colours.get(x));
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
I'm using a TeeChart library to display Candlesticks chart on Android.
Just for now I'm developing a simple SWT application to test some capabilities of the library.
I'm adding about 400 candles to my chart using
series.add(c.getOpen(), c.getHigh(), c.getLow(), c.getClose())
By the time when there're a lot of candles displayed they begin ovelap with each other.
What is the best way to avoid this?
My idea was to calculate the number of candles which can be displayed without overlapping using chart width, candle width and some spacing between candles:
private int getNumberOfCandlesVisible() {
final Candle candles = (Candle) series;
final int panelWidth = chart.getWidth();
final int candleWidth = candles.getCandleWidth();
return panelWidth / (candleWidth + CANDLE_SPACING);
}
Then I tried to display last N values if series.getCount > getNumberOfCandlesVisible() using zoom or setMinMax() an axis. Is it the right way?
I want to scroll the chart to display to most actual values as they apper, but it doesn't seem to be smooth... Maybe there's an option somewhere?
Very similar to this one, isn't it?
Then, I guess the major issue here is how to smooth the transition.
To do this you could use a TimerTask in Android. Ie:
public class MainActivity extends Activity {
Timer timer;
MyTimerTask myTimerTask;
int cycleCount;
class MyTimerTask extends TimerTask {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
cycleCount++;
if (cycleCount <= 60) {
double tmpIncr = (tChart1.getSeries(0).getXValues().getLast() - tChart1.getSeries(0).getXValues().getValue(tChart1.getSeries(0).getCount()-2)) / 60;
tChart1.getAxes().getBottom().setAutomaticMaximum(false);
tChart1.getAxes().getBottom().setMaximum(tChart1.getAxes().getBottom().getMaximum()+tmpIncr);
tChart1.refreshControl();
} else {
startStopTimer(false);
}
}
});
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout group = (LinearLayout) findViewById(R.id.chart_layout1);
createChart(group);
initializeChart();
}
private TChart tChart1;
private int timerInterval, testIndex;
private int chartPaintCtr;
private int pointsRefreshed, pointsPlotted;
private float myDensity;
private void createChart(LinearLayout group) {
tChart1 = new TChart(this);
group.addView(tChart1);
}
private void initializeChart() {
// apply theme
ThemesList.applyTheme(tChart1.getChart(), 1);
// multitouch drag zoom
tChart1.getZoom().setZoomStyle(ZoomStyle.INCHART_MULTI);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
myDensity = metrics.density;
tChart1.getAspect().setFontZoom(
tChart1.getAspect().getFontZoom() * myDensity);
// hide things for better speed
tChart1.getAspect().setView3D(false);
tChart1.getLegend().setVisible(false);
tChart1.getFooter().setVisible(false);
tChart1.getHeader().setVisible(false);
tChart1.getWalls().setVisible(false);
tChart1.getZoom().setAnimated(true);
tChart1.getZoom().setAnimatedSteps(15);
FastLine lineSeries1 = new FastLine(tChart1.getChart());
lineSeries1.fillSampleValues();
tChart1.getAxes().getTop().getGrid().setVisible(false);
tChart1.getAxes().getRight().getGrid().setVisible(false);
int sep = 150;
tChart1.getAxes().getTop().getLabels().setSeparation(sep);
tChart1.getAxes().getRight().getLabels().setSeparation(sep);
tChart1.getAxes().getBottom().getLabels().setSeparation(sep);
tChart1.getAxes().getLeft().getLabels().setSeparation(sep);
tChart1.getPanel().setMarginLeft(7);
final Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
tChart1.getZoom().setAnimated(false);
msgSet = false;
chartPaintCtr = 0;
cycleCount = 0;
Random generator = new Random();
int tmpRandom = generator.nextInt((int)tChart1.getSeries(0).getYValues().getRange()/10);
tChart1.setAutoRepaint(false);
tChart1.getSeries(0).add(50, tChart1.getSeries(0).getYValues().getLast()-(int)tChart1.getSeries(0).getYValues().getRange()/20+tmpRandom);
tChart1.setAutoRepaint(true);
startStopTimer(true);
}
});
}
public void startStopTimer(Boolean run) {
if (run) {
if (timer != null) {
timer.cancel();
}
// re-schedule timer here
// otherwise, IllegalStateException of
// "TimerTask is scheduled already"
// will be thrown
timer = new Timer();
myTimerTask = new MyTimerTask();
// delay to first xxms, repeat in xxms
timer.schedule(myTimerTask, 0, timerInterval);
} else {
if (timer != null) {
timer.cancel();
timer = null;
}
}
}
}
In the example above, we have a FastLine series populated with 25 values. Then, when we press the button, we add another point at a far position (50).