I have set up a button with an onClick method called ButtonRoll which randomly generates a number from 1-100 then display the output below the button in a text view. This works fine but what I would like to move onto is to be able to cycle through 20 numbers being generated. I have tried the following the but it will only display the last number being generated. I am guessing this is because the UI isn't being updated untill the last number is generated.
public void ButtonRoll(View view) {
int n;
Random rand = new Random();
TextView textRoll = (TextView) findViewById(R.id.textview_roll);
for (int i=0; i<20; i++){
try {
Thread.sleep(200);
n = rand.nextInt(100) + 1;
String roll = String.valueOf(n);
textRoll.setText("Random number is " + roll);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Would I have to use a Handler at all? Or is there a simpler solution?
Thanks for your time.
Give this a try.
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<Button android:id="#+id/button_roll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:text="Roll"/>
<TextView android:id="#+id/textview_roll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/button_roll" />
</RelativeLayout>
MainActivity.java
public class MainActivity extends Activity implements OnClickListener
{
private class Roller implements Runnable
{
private int numTimes;
private long delayMillis;
public Roller(int numTimes, long delayMillis)
{
this.numTimes = numTimes;
this.delayMillis = delayMillis;
}
#Override
public void run()
{
if (textRoll != null)
{
int n = rand.nextInt(100) + 1;
String roll = String.valueOf(n);
textRoll.setText("Random number is " + roll);
numTimes--;
if (numTimes > 0)
{
textRoll.postDelayed(this, delayMillis);
}
}
}
}
private TextView textRoll;
private Random rand = new Random();
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button_roll).setOnClickListener(this);
textRoll = (TextView)findViewById(R.id.textview_roll);
}
#Override
public void onDestroy()
{
findViewById(R.id.button_roll).setOnClickListener(null);
textRoll = null;
super.onDestroy();
}
#Override
public void onClick(View v)
{
int id = v.getId();
if (id == R.id.button_roll)
{
findViewById(R.id.textview_roll).post(new Roller(20, 100));
}
}
}
you can use handler concept:
There are several ways to update your UI and modify a View such as a TextView from outside of the UI Thread. A Handler is just one method.
Here is an example that allows a single Handler respond to various types of requests.
private final static int DO_UPDATE_TEXT = 0;
private final static int DO_THAT = 1;
private final Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
final int what = msg.what;
switch(what) {
case DO_UPDATE_TEXT: doUpdate(); break;
case DO_THAT: doThat(); break;
}
}
};
Update the UI in one of your functions, which is now on the UI Thread:
private void doUpdate() {
myTextView.setText("updating..");
}
in your asynchronous task, send a message to the Handler. There are several ways to do it. This may be the simplest:
myHandler.sendEmptyMessage(DO_UPDATE_TEXT);
After noticing the .post method as mentioned beforehand, I had a play and came up with this version which does the same. Can you see any reason why is would unadvisable to run it this way?
public void ButtonRoll(View view) {
new Thread(new Runnable() {
#Override
public void run() {
for(int i = 0; i<50;i++) {
try {
Thread.sleep(50);
final TextView textRoll = (TextView) findViewById(R.id.textview_roll);
int n;
Random rand = new Random();
n = rand.nextInt(100) + 1;
final String roll = String.valueOf(n);
textRoll.post(new Runnable() {
#Override
public void run() {
textRoll.setText("Random number is " + roll);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
Related
From this thread: How to Customize a Progress Bar In Android
I made my own progress bar using ClipDrawAble animation and it works perfecty, and the code is here:
public class MainActivity extends AppCompatActivity {
private EditText etPercent;
private ClipDrawable mImageDrawable;
private Button fly_to_50;
// a field in your class
private int mLevel = 0;
private int fromLevel = 0;
private int toLevel = 0;
//public static final int MAX_LEVEL = 10000;
public static final int MAX_LEVEL = 10000;
public static final int LEVEL_DIFF = 100;
public static final int DELAY = 0;
public static final int START_AT_50 = 50;
private Handler mUpHandler = new Handler();
private Runnable animateUpImage = new Runnable() {
#Override
public void run() {
doTheUpAnimation(fromLevel, toLevel);
}
};
private Handler mDownHandler = new Handler();
private Runnable animateDownImage = new Runnable() {
#Override
public void run() {
doTheDownAnimation(fromLevel, toLevel);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etPercent = (EditText) findViewById(R.id.etPercent);
ImageView img = (ImageView) findViewById(R.id.imageView1);
mImageDrawable = (ClipDrawable) img.getDrawable();
mImageDrawable.setLevel(0);
}
private void doTheUpAnimation(int fromLevel, int toLevel) {
mLevel += LEVEL_DIFF;
mImageDrawable.setLevel(mLevel);
if (mLevel <= toLevel) {
mUpHandler.postDelayed(animateUpImage, DELAY);
} else {
mUpHandler.removeCallbacks(animateUpImage);
MainActivity.this.fromLevel = toLevel;
}
}
private void doTheDownAnimation(int fromLevel, int toLevel) {
mLevel -= LEVEL_DIFF;
mImageDrawable.setLevel(mLevel);
if (mLevel >= toLevel) {
mDownHandler.postDelayed(animateDownImage, DELAY);
} else {
mDownHandler.removeCallbacks(animateDownImage);
MainActivity.this.fromLevel = toLevel;
}
}
public void onClick50(View v){
mImageDrawable.setLevel(START_AT_50);
}
public void onClickOk(View v) {
//int temp_level = ((Integer.parseInt(etPercent.getText().toString())) * MAX_LEVEL) / 100;
int temp_level = ((Integer.parseInt(etPercent.getText().toString())) * MAX_LEVEL) / 100;
if (toLevel == temp_level || temp_level > MAX_LEVEL) {
return;
}
toLevel = (temp_level <= MAX_LEVEL) ? temp_level : toLevel;
if (toLevel > fromLevel) {
// cancel previous process first
mDownHandler.removeCallbacks(animateDownImage);
MainActivity.this.fromLevel = toLevel;
mUpHandler.post(animateUpImage);
} else {
// cancel previous process first
mUpHandler.removeCallbacks(animateUpImage);
MainActivity.this.fromLevel = toLevel;
mDownHandler.post(animateDownImage);
}
}
}
I set my "DELAY" variable to be 0, which increased the speed a little bit, however, I am not completely satisfied with the speed and would love to increase the speed more. Is this somehow possible? And if not, is there a chance that I can create a normal progress(would work here for sure), but using my own custom edited images?
Appreciate all answers!
Thank you.
SOLVED:
I changed this line:
mDownHandler.postDelayed(animateDownImage, DELAY);
with this:
mDownHandler.postAtTime(animateDownImage,DELAY);
I'm working on a tank-game and I have a TextView which represents the shot. Now I want to display the TextView at the specific point and remove it after a second that it looks like the shot goes further step by step. But when I add a countdown or a Thread.sleep the program stops for a second but the TextView doesn't disappear. i want to move the TextView over the screen and after every iteration of my for loop i want to wait a second and then rearrange it again?
Here is the code :
public void shot(float power, float winkel, Button button) {
if(winkel>90) {
winkel = winkel - 10;
}else if(winkel<90){
winkel = winkel +10;
}
for (double i = 0; i<100;i = i+ 1) {
final TextView textView = new TextView(context);
textView.setText(".");
double x = tanks.get(currentTank).getxPos()+(i*power*Math.cos(winkel *(Math.PI/180)));
double y = tanks.get(currentTank).getyPos()+(-1*(i*power*Math.sin(winkel *(Math.PI/180))));
double gravity = (-1*((9.81/2)*Math.pow(i,2)));
y = (y-gravity);
textView.setX((float) x);
textView.setY((float) y);
layout.addView(textView);
for (int j = 0;j<tanks.size();j++){
if(textView.getX()>tanks.get(j).getxPos()&&textView.getX()<tanks.get(j).getxPos()+100){
if(textView.getY()>tanks.get(j).getyPos()&&textView.getY()<tanks.get(j).getyPos()+100){
float k = tanks.get(j).getxPos()-textView.getX();
if(k<0){
k = k*-1;
}
makeDamage(k,tanks.get(j));
}
}
}
new CountDownTimer(2000,1000){
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
layout.removeView(textView);
}
}.start();
}
newTurn();
}
I want to pause the program after adding the TextView for one second and the remove it. The program stops but the TextView doesn't disappear till the for-loop finished. Then all TextViews disappear.
Problem solved:
i've added all positions in a array and then this
public void drawShot(final Button firework, final ArrayList<TextView> toDraw){
final int[] i = {0};
final Handler mHandler = new Handler();
firework.setOnClickListener(new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onClick(View v) {
firework(firework,toDraw.get(i[0]).getX(),toDraw.get(i[0]).getY());
}
});
Runnable runnable = new Runnable() {
#Override
public void run() {
layout.addView(toDraw.get(i[0]));
if(!check(toDraw.get(i[0]))) {
mHandler.postDelayed(this, (long) 1);
}
i[0]++;
}
};
// start it with:
mHandler.post(runnable);
}
probably need to run the remove command on main thread
Handler mainHandler = new Handler(context.getMainLooper());
Runnable myRunnable = new Runnable() {
#Override
public void run() {
layout.removeView(textView);
}
};
mainHandler.post(myRunnable);
I want make a Dice game, i have use a github project (https://github.com/dylanmtaylor/Simple-Dice).
The MainActivity is available here : https://github.com/dylanmtaylor/Simple-Dice/blob/master/src/com/dylantaylor/simpledice/RollDice.java
I want to get the value of the dice
Exemple :
If the first dice is 1 and the second is 6 we have a total of 7 i want make an action.
I have make a button who change a textview, this button try to get the number of the dices.
TextView hwTextView = (TextView)findViewById(R.id.textView8);
hwTextView.setText(String.valueOf(diceSum));
I have try to get the value "diceSum", "diceImages", "dice", "dice[roll[0]", "dice[roll[1]" but that didn't show a number.
How can i do try to get the value of the dice ?
My MainActivity
public class dices extends AppCompatActivity {
Button button;
private final int rollAnimations = 50;
private final int delayTime = 15;
private Resources res;
private final int[] diceImages = new int[] { R.drawable.d1, R.drawable.d2, R.drawable.d3, R.drawable.d4, R.drawable.d5, R.drawable.d6 };
private Drawable dice[] = new Drawable[6];
private final Random randomGen = new Random();
#SuppressWarnings("unused")
private int diceSum;
private int roll[] = new int[] { 6, 6 };
private ImageView die1;
private ImageView die2;
private LinearLayout diceContainer;
private SensorManager sensorMgr;
private Handler animationHandler;
private long lastUpdate = -1;
private float x, y, z;
private float last_x, last_y, last_z;
private boolean paused = false;
private static final int UPDATE_DELAY = 50;
private static final int SHAKE_THRESHOLD = 800;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
paused = false;
setContentView(R.layout.activity_dixit);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.setStatusBarColor(Color.parseColor("#2c3e50"));
}
View view = this.getWindow().getDecorView();
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
button=(Button)findViewById(R.id.button_roll);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rollDice();
TextView hwTextView = (TextView)findViewById(R.id.textView8);
hwTextView.setText(String.valueOf(diceSum));
}
});
res = getResources();
for (int i = 0; i < 6; i++) {
dice[i] = res.getDrawable(diceImages[i]);
}
die1 = (ImageView) findViewById(R.id.die1);
die2 = (ImageView) findViewById(R.id.die2);
animationHandler = new Handler() {
public void handleMessage(Message msg) {
die1.setImageDrawable(dice[roll[0]]);
die2.setImageDrawable(dice[roll[1]]);
}
};
}
private void rollDice() {
if (paused) return;
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < rollAnimations; i++) {
doRoll();
}
}
}).start();
MediaPlayer mp = MediaPlayer.create(this, R.raw.roll);
try {
mp.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mp.start();
}
private void doRoll() { // only does a single roll
roll[0] = randomGen.nextInt(6);
roll[1] = randomGen.nextInt(6);
diceSum = roll[0] + roll[1] + 2; // 2 is added because the values of the rolls start with 0 not 1
synchronized (getLayoutInflater()) {
animationHandler.sendEmptyMessage(0);
}
try { // delay to alloy for smooth animation
Thread.sleep(delayTime);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
public void onResume() {
super.onResume();
paused = false;
}
public void onPause() {
super.onPause();
paused = true;
}
}
I didn't understand why your code didn't work. I myself making a very small games based on "Scarne's dice game(pig)" and myself facing the challenge of retrieving the value of dice rolled. Mind, I am just using one die. This is what I did:
int userScore;
private int[] diceArray = {R.drawable.d1, R.drawable.d2, R.drawable.d3,
R.drawable.d4,R.drawable.d5,R.drawable.d6};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onRollBtnClicked() {
ImageView diceFace = (ImageView) findViewById(R.id.diceFaceImageView);
userScore = randomIntegerGenerator(1,6); // this is what you need
diceFace.setImageResource(diceArray[userScore]);
}
// function to return random integer from min to max
public int randomIntegerGenerator(int min, int max) {
return random.nextInt((max - min) + 1) + min;
}
I am storing my rolled die value in userScore. You can use the similar approach.
I am new to Android programming, but I'm quite familiar with Java and so...
In this app, I need to create something like a Death/Birth counter and a Total Population Counter, so I need the String at the Activity to be updated each second, but I can't seen to find any solution.
This is my Main Activity :
public class MainActivity extends ActionBarActivity {
static int nasc;
static int mortes;
static int popTotal;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
nasc = 0;
mortes = 0;
popTotal = 0;
setContentView(R.layout.activity_main);
final TextView view = new TextView(this);
Boolean menu = false;
Handler handler = new Handler();
while (menu == false) {
handler.postDelayed(new Runnable() {
public void run() {
view.setText("Births : " + getNasc() + ".");
view.append("\n");
view.append("Deaths : " + getMortes() + ".");
view.append("\n");
view.append("Total Population : " + getPopTotal() + ".");
setContentView(view);
}
}, 1000);
}
}
private int getPopTotal() {
popTotal = nasc - mortes;
return popTotal;
}
private int getMortes() {
mortes = (int) (mortes + 1.7);
return mortes;
}
private int getNasc() {
nasc = nasc + 3;
return nasc;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.textView) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
What have I been doing wrong?
What you need to do is remove the while loop, and just re-run the Runnable if menu == false each second after updating the UI with the new totals.
I just got this implementation working by making the Runnable a member variable instead of it being an anonymous class, using a StringBuilder to build up the text for the TextView, and re-running the Runnable if menu is still false at the completion of each run.
public class MainActivity extends ActionBarActivity {
static int nasc;
static int mortes;
static int popTotal;
TextView view;
Handler handler;
Boolean menu;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nasc = 0;
mortes = 0;
popTotal = 0;
view = (TextView) findViewById(R.id.text);
menu = false;
handler = new Handler();
handler.postDelayed(updateText, 1000);
}
public Runnable updateText = new Runnable() {
#Override
public void run() {
StringBuilder sb = new StringBuilder();
sb.append("Births : " + getNasc() + ".");
sb.append("\n");
sb.append("Deaths : " + getMortes() + ".");
sb.append("\n");
sb.append("Total Population : " + getPopTotal() + ".");
view.setText(sb.toString());
if (menu == false){
handler.postDelayed(this, 1000);
}
}
};
//.................
activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<TextView android:id="#+id/text" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
Try this :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
nasc = 0;
mortes = 0;
popTotal = 0;
setContentView(R.layout.activity_main);
final TextView view = (TextView)findViewById(R.id.textView_id);
String allText="";
Boolean menu = false;
Handler handler = new Handler();
while (menu == false) {
handler.postDelayed(new Runnable() {
public void run() {
allText+="Births : " + getNasc() + ".";
allText+="\n";
allText+="Deaths : " + getMortes() + ".";
allText+="\n";
allTExt+="Total Population : " + getPopTotal() + ".";
view.setText(allText);
allText="";//reset the string
}
}, 1000);
}
}`
In your activity_main.xml inside yout TextView declaration add
<TextView ...
... <!--other params that you have set-->
android:id="#+id/textview_id"
... />
try this way me this help u
public class test extends Activity {
private TextView textView;
private int i = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
textView = (TextView)findViewById(R.id.text);
set();
}
private void set(){
final String text ="A n d r o i d P r o g r a m m i n g";
final String[] words = text.toString().split(" ");
final Handler handler = new Handler();
handler.post(new Runnable(){
#Override
public void run() {
textView.setText(""+words[i]);
i++;
if(i < words.length) {
handler.postDelayed(this, 1000);
}
}
});
}}
import this :
//
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
//
and use this for every one minute :
ScheduledExecutorService scheduleTaskExecut = Executors.newScheduledThreadPool(5);
// This run every one minute
scheduleTaskExecut.scheduleAtFixedRate(new Runnable() {
public void run() {
//in this Methos Update Your Text as You Need
UpdateYourText();
}
}, 0, 1, TimeUnit.MINUTES);
i'm new to android programming. I have the following code happening on a button click
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button button = (Button) findViewById(R.id.morse_btn);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
loopCode();
}
});
}
which calls this:
public void loopCode()
{
String code = "Hello There";
TextView view = (TextView) findViewById(R.id.code_txt);
String s = "";
for(int i = 0; i < code.length(); i++)
{
s+=code.charAt(i);
view.setText(s);
try {
TimeUnit.SECONDS.sleep(1);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
but when i run it on my phone, the text does not get appended until after the for loop has gone through, i.e i press the button, and after a few seconds, the whole string "Hello There" appears.
How can I make it write the text one character at a time, like a typewriter style.
Thanks
You need to use view.append("") which will append new text to the existing one.
Try this code:
int i = 0; //declare this globally
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if(i != 10) {
text.append(" " + i);
i++;
handler.postDelayed(this, 1000);
}
}
}, 1000);
}
This code will append a new number to the TextView every one second until it has reached the count 10. You can apply the same logic.
I had provided this solution to a question here -
[EDIT]
Try this:
String code = "Hello There"; //declare variable globally
int i = 0; //declare globally
TextView view; //declare globally
public void loopCode()
{
view = (TextView) findViewById(R.id.code_txt);
//String s = "";
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if(i != code.length()) {
view.append(" " + code.charAt(i));
i++;
handler.postDelayed(this, 1000);
}
}
}, 1000);
}
}
Don't forget to declare int i = 0 and String code = "Hello There" globally.
Exist 2 different method setText in TextView.
public final void setText (int resid)
public final void setText (CharSequence text)
when you put variable int in setText, the android try find String in classe R variable in same code.
To resolve this you then cast int to string using String.valueOF(...)
see more in;
http://developer.android.com/reference/android/widget/TextView.html#setText(java.lang.CharSequence)
http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#valueOf(int)
try
public void loopCode()
{
String code = "Hello There";
TextView view = (TextView) findViewById(R.id.code_txt);
String s = "";
for(int i = 0; i < code.length(); i++)
{
view.setText(String.valueOf(i));
try {
TimeUnit.SECONDS.sleep(1);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}