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();
Related
I'm trying to make an app that displays images continuosly (4 or 5 times per second) so i need to update an image held inside a ImageView object, it works if i trigger the functions from a button press, every time i press the button the next image gets displayed:
int i = 0;
public void buttonPressed(View view) {
ImageView image = (ImageView) findViewById(R.id.imageView5);
String path = String.format("/storage/emulated/0/Download/%d.bmp", i);
File imgFile = new File(path);
bMap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
image.setImageBitmap(bMap);
i++;
}
But if i try to call the same functions more than once in the same parent function or i try to run them in a loop the first images are not loaded at all and only the last is finally displayed after loopFunc() completed:
public void loopFunc() {
ImageView image = (ImageView) findViewById(R.id.imageView5);
for (i = 1; i < 3; i++) {
String path = String.format("/storage/emulated/0/Download/%d.bmp", i);
File imgFile = new File(path);
bMap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
image.setImageBitmap(bMap);
//wait some time or do other things...
}
}
In few words i need to be able to execute image.setImageBitmap(bMap); from code and not from buttons anyone knows how? thanks
The problem lies in the time you used to compute other things. Is there some kind of delay function code you wrote in it.
Try this. Just make a function and call it onCreate method with some Thread or Handler.
public void imgViwer()
{
Thread thread=new Thread(new Runnable() {
#Override
public void run() {
try {
for (i = 1; i < 3; i++) {
String path = String.format("/storage/emulated/0/Download/%d.bmp", i);
File imgFile = new File(path);
bMap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
image.setImageBitmap(bMap);
}
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
After every 200ms your loop works.
Root cause
Because the loop is run too quickly in a short time, that why you see the first image is not displayed at all, and only the last is finally displayed after loopFunc() completed.
Solution
To display a sequence of images continuously per second, then you should use Handler.
public void loopFunc() {
Handler mainHandler = new Handler(Looper.getMainLooper());
int totalImage = 3;
for (int i = 1; i < totalImage; i++) {
int imageIndex = i;
mainHandler.postDelayed(new Runnable() {
#Override
public void run() {
String path = String.format("/storage/emulated/0/Download/%d.bmp", imageIndex);
File imgFile = new File(path);
bMap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
image.setImageBitmap(bMap);
}
}, 1000 / totalImage * imageIndex);
}
}
Below is a peice of code where on click the player will make their move by placing the X counter and then the computer will make their move by placing a O counter. The
only issue with this code currently is that when the player places their X counter, the O counter is placed as well at the same time. So it looks like both the player
and the computer has made their moves at the same time and that happens everytime the player makes their move.
What I want to ask, is it possible to include like a 2 second time delay so that the player will place their X and then after 2 seconds the computer will place their O?
Thanks in advance
#Override
public void onClick(View v) {
if (!((Button) v).getText().toString().equals("")) {
return;
}
if (playerOneMove) {
((Button) v).setText("X");
((Button) v).setTextColor(playerX);
computerMove();
}
}
private void computerMove() {
String[][] field = new String[3][3];
Random random = new Random(); //you may want to declare this as a class field
List<Button> emptyButtons = new ArrayList<>();
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
field[i][j] = buttons[i][j].getText().toString();
if (field[i][j].equals("")) {
emptyButtons.add(buttons[i][j]);
}
}
}
Button selectButton;
for (int i = 0; i < 3; i++) {
if (field[i][0].equals(field[i][1])
&& field[i][2].equals("")){
//prevent win/win on rows by selecting the correct button here
}
else if (field[i][0].equals(field[i][2])
&& field[i][1].equals("")){
//prevent win/win on rows by selecting the correct button here
}
else if (field[i][1].equals(field[i][2])
&& field[i][0].equals("")){
//prevent win/win on rows by selecting the correct button here
}
else {
selectButton = emptyButtons.get(random.nextInt(emptyButtons.size()));
}
selectButton.setText("O");
selectButton.setTextColor(playerO);
}
You could put computer logic inside handler or timer task: How to call a method after a delay in Android
but you also need some flag, that will block user placing X while you are waiting for computer to make it move.
i edited your onclick with the delay and i think you gonna need some sort of the flag wich blocks user until computer makes the move !
#Override
public void onClick(View v) {
if (!((Button) v).getText().toString().equals("")) {
return;
}
if (playerOneMove) {
((Button) v).setText("X");
((Button) v).setTextColor(playerX);
//2000 is your delay in mills format
v.postDelayed(new Runnable() {
#Override
public void run() {
computerMove();
}
},2000)
}
}
and i think it would be good idea to use some random number between 1sec to 3sec for delay and not the constant delay it creates better experience for user
You can check out the Handler and Runnable class in android. You can delayed the time of a method as required.
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 100ms
}
}, 100);
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.
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).
I want an app which changes background color when pressing a button. After 500 ms, I want to change background color to black for 2000ms. And then repeat whole process again, until user terminates that.
I have following code but its not working as I think it should.
private void set() {
rl.setBackgroundColor(Color.WHITE);
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
rl.setBackgroundColor(Color.BLACK);
set(); // can I do that?
}
});
}
}, 500);
}
Can someone point me to right direction how can I do that? So I want:
Execute some code
After X time passed by , I want to execute another code and it should stay that way for X amount of time
Repeat process until user cancels that.
Something like this should work I think
Handler handler = new Handler();
Runnable turnBlack = new Runnable(){
#Override
public void run() {
myView.setBackgroundColor(Color.BLACK);
goWhite();
}};
Runnable turnWhite = new Runnable(){
#Override
public void run() {
myView.setBackgroundColor(Color.White);
goBlack();
}};
public void goBlack() {
handler.postDelayed(turnBlack, 500);
}
public void goWhite() {
handler.postDelayed(turnWhite, 2000);
}
There is much easier way to do this using AnimationDrawable:
AnimationDrawable drawable = new AnimationDrawable();
ColorDrawable color1 = new ColorDrawable(Color.YELLOW);
ColorDrawable color2 = new ColorDrawable(Color.BLACK);
// First color yellow for 500 ms
drawable.addFrame(color1, 500);
// Second color black for 2000 ms
drawable.addFrame(color2, 2000);
// Set if animation should loop. In this case yes it will
drawable.setOneShot(false);
Button btn = (Button)findViewById(R.id.button1);
btn.setBackground(drawable);
findViewById(R.id.buttonLan).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// Start animation
((AnimationDrawable)v.getBackground()).start();
}
});