I have an array of strings that displays a random text result in a TextView after a button is pressed and after 5000 milliseconds. What I am trying to achieve is to have an array of images instead of text and so would like a random image showing in an ImageView after the 5000 milliseconds.
public class MainActivity extends AppCompatActivity {
private ImageView thumbPrint;
private TextView result;
private AnimationDrawable thumbAnimation;
private String[] moodResults;
private Runnable mRunnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.activity_main);
moodResults = new String[]{
"result a",
"result b",
"result c",
"result d",
"result e",
"result f"
};
thumbPrint = (ImageView)findViewById(R.id.thumbPrint);
thumbPrint.setBackgroundResource(R.drawable.thumb_animation);
thumbAnimation = (AnimationDrawable)thumbPrint.getBackground();
result = (TextView)findViewById(R.id.resultText);
thumbPrint.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
thumbAnimation.start();
showResult();
return true;
}
});
}
public void showResult(){
mRunnable = new Runnable() {
#Override
public void run() {
int rand = (int)(Math.random()* moodResults.length);
result.setText(moodResults[rand]);
//stop animation
thumbAnimation.stop();
}
};
Handler mHandler = new Handler();
mHandler.postDelayed(mRunnable, 5000);
}
}
Implement it this way:
These variables are declared in MainActivity. They can be seperately initialized inside onCreate()
final int[] imageIds= {
R.drawable.image1, R.drawable.image2, ...}; // This is your array with resource id of each image
Random r = new Random();
Handler mHandler = new Handler();
This is the refactored code for showResult():
public void showResult(){
mRunnable = new Runnable() {
#Override
public void run() {
int rand = (int)(Math.random()* moodResults.length);
result.setText(moodResults[rand]);
int randomInt = r.nextInt(imageIds.length);
thumbprint.setBackgroundResource(imageIds[randomInt]); //thumbprint is your Imageview
//stop animation
thumbAnimation.stop();
mHandler.postDelayed(mRunnable, 5000);//This causes hanlder to called again in 5 seconds
}
};
mHandler.postDelayed(mRunnable, 5000); //Here handler is called the first time; the code in mRunnable will execute after 5 seconds
}
I would create an array of strings with images paths and choose a random path and show that image.
Related
I wanted to have a textview that will show the money of the player. But
myMoneyTextView.setText(String.valueOf(acc.getMoney))
doesn't update it I need to reopen the intent to see those changes. I want to change it when the player spend or gain money.
EDIT.
private SubsamplingScaleImageView imageView;
private CustomButton up, down, menu, employ, sales, social, schedule, chart, states, mail;
private TextView comMon, comName;
private DataBase db;
Handler handler = new Handler(Looper.getMainLooper());
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game_screen);
officeRender();
updateGame();
butThread thread = new butThread();
new Thread(thread).start();
comName = findViewById(R.id.companyname);
comMon = findViewById(R.id.money);
}
public void updateGame() {
handler.post(new Runnable() {
#Override
public void run() {
db = new DataBase(GameScreen.this);
Account acc = db.getAcc();
comName.setText(acc.getName() + " Ent.");
String mon = String.valueOf(acc.getMoney());
if (acc.getMoney() < 100000) {
comMon.setText(mon);
}
else if (acc.getMoney() >= 100000) {
comMon.setText(mon.substring(0, 3) + "k");
}
else if (acc.getMoney() >= 1000000) {
comMon.setText(mon.substring(0, 3) + "m");
}
}
});
"How do I make a CountDown show at the same moment my Button gets enabled ?"
Additional info regarding the button: the Buttons Job is it to click 5 times through a stringarray displayed in a Textview to then get disabled for 5 seconds to do the same task again.
so ..I would like a CountDown to visually show those 5 seconds(the time the button is enabled) count down for the User to see.
sadly I dont have an idea how to connect my Button with an CountDown to let it know its supposed to count down at that particular time the Button is enabled.
Also I would like for the CountDown to start everytime the Button gets enabled.
I looked into https://developer.android.com/reference/android/os/CountDownTimer
but it doesnt seem to have a solution for that particular case.
thats my Code for the Button as of now :
next_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (currentnumber == list.length) {
currentnumber = 0;
}
if (Curclicks == mod - 1) {
next_button.setEnabled(false);
display.setText(list[currentnumber]);
currentnumber++;
handler.postDelayed(new Runnable() {
#Override
public void run() {
//the button will unlock after the delay specified
next_button.setEnabled(true);
Curclicks = 0;
}
}, delay);
} else {
display.setText(list[currentnumber]);
currentnumber++;
}
Curclicks++;
}
});
UI Thread code can solve that ? :
private void runThread() {
new Thread() {
public void run() {
while (delay == 5000) { //delay = 5000 ( 5 secs)
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
timer.setText("" + delay);//timer=TxtView
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
Here is an example of how you can use the postDelayed() method of the Handler to create a count down. I have purposefully left the code a bit verbose so you can go through it step-by-step in order to see what is happening.
Create a few class variables and constants.
private static final long COUNT_DOWN_TICKS = 100l;
private static final long COUNT_DOWN_FINISH = 5000l;
private long countdownElapsed = 0l;
private Handler mCountDownHandler = new Handler();
COUNT_DOWN_FINISH is set to 5000 --> 5 sec. But can be changed to anything you need. Also I use COUNT_DOWN_TICKS set to 100 --> 0.1 sec, just in case you want to display a more precise count down.
From your OnClick() method just call startCountDown() to get the count down started.
private void startCountDown() {
try {
countdownElapsed = 0l;
next_button.setEnabled(false);
displayCountDown();
mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private Runnable mCountDownRunnable = new Runnable() {
#Override
public void run() {
countdownElapsed = countdownElapsed + COUNT_DOWN_TICKS;
if(countdownElapsed >= COUNT_DOWN_FINISH){
releaseCountDownHandler();
next_button.setEnabled(true);
}
else{
mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
}
long secFull = countdownElapsed % 1000;
if(secFull == 0){
runOnUiThread(new Runnable() {
#Override
public void run() {
displayCountDown();
}
});
}
}
};
private void releaseCountDownHandler() {
try {
if(mCountDownRunnable != null) {
mCountDownHandler.removeCallbacks(mCountDownRunnable);
}
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private void displayCountDown(){
long t = (COUNT_DOWN_FINISH - countdownElapsed)/1000;
String myTime = String.valueOf(t);
timer.setText(myTime);
}
In order to dispose of the Runnable properly you will want to call releaseCountDownHandler() from the onPause() method. This is just a short running Thread, but it should still not be ignored.
I prefer the Handler with the postDelay() method to the Thread.sleep() method--something about putting any thread to sleep is disconcerting. Also note that it is a good idea to get accustom to checking the elapsed time condition with ">=" RATHER than "==" depending on the implementation (e.g. you use SystemClock.elapsedRealtime() instead) the condition just might miss the exact value!
EDIT
Somewhere under the definition of your Activity class (for this example I will call it MainActivity) you will need to declare a few variables. Since they are being defined inside the class and NOT inside a method the are referred to as "class variables" and they have a scope of entire class when defined "private".
public class MainActivity extends AppCompatActivity {
//class variables
private static final long COUNT_DOWN_TICKS = 100l;
private static final long COUNT_DOWN_FINISH = 5000l;
private long countdownElapsed = 0l;
private Handler mCountDownHandler = new Handler();
private Button next_button;
private TextView timer;
....
}
You probably have declared the onClick() method inside the onCreate() method of the MainActivity class. So just add the following code:
next_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startCountDown();
}
Everything else I provide are method inside the MainActivity class...NOT inside any other method. So below the onCreate() method add all methods that I previously posted.
It will look something like this:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
//class variables
private static final long COUNT_DOWN_TICKS = 100l;
private static final long COUNT_DOWN_FINISH = 5000l;
private long countdownElapsed = 0l;
private Handler mCountDownHandler = new Handler();
private Button next_button;
private TextView timer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// you must compensate for the actual layout for your activity
setContentView(R.layout.activity_main);
// you must compensate for the actual id of the TextView
timer = findViewById(R.id.tvTimer);
// you must compensate for the actual id of the Button
next_button = findViewById(R.id.btnNext);
next_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startCountDown();
}
});
}
private void startCountDown() {
try {
countdownElapsed = 0l;
next_button.setEnabled(false);
displayCountDown();
mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private Runnable mCountDownRunnable = new Runnable() {
#Override
public void run() {
countdownElapsed = countdownElapsed + COUNT_DOWN_TICKS;
if(countdownElapsed >= COUNT_DOWN_FINISH){
releaseCountDownHandler();
next_button.setEnabled(true);
}
else{
mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
}
long secFull = countdownElapsed % 1000;
if(secFull == 0){
runOnUiThread(new Runnable() {
#Override
public void run() {
displayCountDown();
}
});
}
}
};
private void releaseCountDownHandler() {
try {
if(mCountDownRunnable != null) {
mCountDownHandler.removeCallbacks(mCountDownRunnable);
}
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private void displayCountDown(){
long t = (COUNT_DOWN_FINISH - countdownElapsed)/1000;
String myTime = String.valueOf(t);
timer.setText(myTime);
}
}
This function should do what you want, just call it into OnClickListener
public void countDown(Button yourBtn) {
new Thread() {
public void run() {
try {
int second = 10;
for (int i = second; i >= 1; i--) {
int finalI = i;
yourBtn.post(new Runnable() {
#Override
public void run() {
yourBtn.setText(String.valueOf(finalI))
}
});
Thread.sleep(1000); // Change text every 1s
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
This code is like my code above except this code introduces a "click counter". I have introduced a new class variable to keep track of how many times the button is clicked. I have also introduced a new constant called "NUMBER_OF_BUTTON_CLICKS" which servers as the upper limit of clicks.
The user can now click on the button (in this case) 5 times. On the fifth click the condition to trigger the startCountDown method is met and the button is disabled for 5 seconds.
public class MainActivity extends AppCompatActivity {
//Constant values
private static final String TAG = MainActivity.class.getSimpleName();
private static final int NUMBER_OF_BUTTON_CLICKS = 5;
private static final long COUNT_DOWN_TICKS = 100l;
private static final long COUNT_DOWN_FINISH = 5000l;
//class variables
private int howManyClicks = 0;
private long countdownElapsed = 0l;
private Handler mCountDownHandler = new Handler();
private Button next_button;
private TextView timer;
private TextView clicks;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// you must compensate for the actual layout for your activity
setContentView(R.layout.activity_main);
// you must compensate for the actual id of the TextView
timer = findViewById(R.id.tvTimer);
// Use this only if you want to display the number of clicks
// you might need to add this TextView if you want to display the number of clicks
clicks = findViewById(R.id.tvClicks);
// you must compensate for the actual id of the Button
next_button = findViewById(R.id.btnNext);
next_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
howManyClicks++;
if(howManyClicks >= NUMBER_OF_BUTTON_CLICKS){
startCountDown();
}
//Add this only if you want to see how many clicks were made
String myClicks = String.valueOf(howManyClicks);
clicks.setText(myClicks)
}
});
}
private void startCountDown() {
try {
countdownElapsed = 0l;
next_button.setEnabled(false);
displayCountDown();
mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private Runnable mCountDownRunnable = new Runnable() {
#Override
public void run() {
countdownElapsed = countdownElapsed + COUNT_DOWN_TICKS;
if(countdownElapsed >= COUNT_DOWN_FINISH){
releaseCountDownHandler();
next_button.setEnabled(true);
// reset the clicks counter
howManyClicks = 0;
}
else{
mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
}
long secFull = countdownElapsed % 1000;
if(secFull == 0){
runOnUiThread(new Runnable() {
#Override
public void run() {
displayCountDown();
}
});
}
}
};
private void releaseCountDownHandler() {
try {
if(mCountDownRunnable != null) {
mCountDownHandler.removeCallbacks(mCountDownRunnable);
}
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private void displayCountDown(){
long t = (COUNT_DOWN_FINISH - countdownElapsed)/1000;
String myTime = String.valueOf(t);
timer.setText(myTime);
//Add this only if you want to see how many clicks were made
String myClicks = String.valueOf(howManyClicks);
clicks.setText(myClicks)
}
}
I am practising on a simple Android Game where a round button is randomly placed on the screen when the user taps on it..
it works fine but i want to speedify the process of placing the button so that the game gets harder for user...
here is the Code I'm using -
public class GameWindow extends Activity implements View.OnClickListener {
static int score;
private Timer t;
private int TimeCounter = 29;
private boolean canMove = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
////Remove title screen for activty.
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_game_window);
moveButton();
endonTimeOver();
}
public void endonTimeOver(){
////Activity timer for 60 seconds.
final TextView timer = (TextView) findViewById(R.id.seconds);
t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
////Set string to timer.
#Override
public void run() {
// TODO Auto-generated method stub
runOnUiThread(new Runnable() {
public void run() {
timer.setText(String.valueOf(TimeCounter)); // you can set it to a textView to show it to the user to see the time passing while he is writing.
TimeCounter = TimeCounter - 1;
}
});
}
}, 1000, 1000); // 1000 means start from 1 sec, and the second 1000 is do the loop each 1 sec.
new Timer().schedule(new TimerTask(){
public void run() {
GameWindow.this.runOnUiThread(new Runnable() {
public void run() {
startActivity(new Intent(GameWindow.this, Finished.class));
}
});
}
}, 30000);
}
////Move button.
private void moveButton()
{
if(!canMove){ return; }
runOnUiThread(
new Runnable()
{
#Override
public void run()
{
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Button button = (Button)findViewById(R.id.button);
Random r = new Random();
int startX = width/2;
int startY = height/2;
if(score==0){
button.setX(startX);
button.setY(startY);
}
else {
int x = r.nextInt(width - 210);
int y = r.nextInt(height - 200);
button.setX(x);
button.setY(y);
}
}
}
);
}
////Display score
public void displayScore(int score) {
TextView scoreView = (TextView) findViewById(R.id.score);
scoreView.setText(String.valueOf(score));
}
#Override
public void onClick(View v) {
MediaPlayer mp = MediaPlayer.create(this, R.raw.buttonsound);
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
mp.release();
}
});
mp.start();
score = score + 1;
displayScore(score);
switch (v.getId()) {
case (R.id.button): {
moveButton();
}
}
}
public static int getScore(){
return score;
}}
Use global variables for values that don't change:
findViewById is slow
Creating new Random every time is not necessary
getting the window parameter every time is not necessary either
You seem to be starting a new thread and telling it to runonui , this might be slowing you down , try this :
private void moveButton()
{
if(!canMove){ return; }
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Button button = (Button)findViewById(R.id.button);
Random r = new Random();
int startX = width/2;
int startY = height/2;
if(score==0){
button.setX(startX);
button.setY(startY);
}
else {
int x = r.nextInt(width - 210);
int y = r.nextInt(height - 200);
button.setX(x);
button.setY(y);
}
}
the computation itself doesn't seem to heavy so no need for another thread , you can do it on the main thread , if you're calling from oncreate that means you're already on main thread , this might give you the answer if i understood the question , try it
This question already has answers here:
Android "Only the original thread that created a view hierarchy can touch its views."
(33 answers)
Closed 6 years ago.
I want to change the image dynamically with its link in a thread.
public class MainActivity extends AppCompatActivity {
public static final Integer[] images =
{
R.drawable.vr_final_icon,
R.drawable.playnew
};
public static final String[] Links =
{
"http://stackoverflow.com/questions/541487/implements-runnable-vs-extends-thread",
"http://www.facebook.com",
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable()
{
#Override
public void run()
{
try
{
Random r = new Random();
int Low = 0;
int High = images.length;
final int Result = r.nextInt(High - Low) + Low;
INCP(Result);
Thread.sleep(6000);
run();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void INCP(final int incp)
{
Drawable res = getResources().getDrawable(images[incp]);
ImageView INCPimage = (ImageView) findViewById(R.id.INCP);
INCPimage.setImageDrawable(res);
INCPimage.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(Links[incp]));
startActivity(intent);
}
});
}
}).start();
}
}
But it gives me error that
Only the original thread that created a view hierarchy can touch its views.
How can i solve it !
I want image to change dynamically with its link on run time.
Only main thread can touch views. Change code like this;
Random r = new Random();
int Low = 0;
int High = images.length;
final int Result = r.nextInt(High - Low) + Low;
runOnUiThread(new Runnable() {
#Override
public void run() {
INCP(Result);
}
});
Thread.sleep(6000);
run();
I'm newbie in java. So the program should take the user entered text and if there is "a" it gonna play a-sound, if there is "b" it gonna play b-sound.And it must play this sounds one by one even if there are multiple "a" or "b". Here is my code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button bStart = (Button) findViewById(R.id.bStart);
final EditText etStart = (EditText) findViewById(R.id.etStart);
final EditText etFinish = (EditText) findViewById(R.id.etFinish);
final char[] arr = etStart.getText().toString().toCharArray();
final MediaPlayer as = MediaPlayer.create(R2d2Activity.this, R.raw.as);
final MediaPlayer bs = MediaPlayer.create(R2d2Activity.this, R.raw.bs);
final SoundPool sp;
final int a;
final int b;
final int t;
sp = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
a = sp.load(this, R.raw.as, 1);
b = sp.load(this, R.raw.bs, 1);
final String value = etStart.getText().toString();
final Thread timer = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1300);
// Do some stuff
} catch (Exception e) {
e.getLocalizedMessage();
}
}
});
bStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int n = 0;
String value;
String first;
value = etStart.getText().toString();
// TODO Auto-generated method stub
//actual code
for (int i=0; i<value.length(); i++){
first = etStart.getText().toString().substring(i, i+1);
if(first.contentEquals("a")){
as.start();
as.setOnCompletionListener(new OnCompletionListener(){
public void onCompletion(MediaPlayer arg0) {
//when finished
}
});
}else{
}
if(first.contentEquals("b")){
bs.start();
}else{
}
}
}
});
The problem is that it starts playing audio files all at one time. I tried to add some OnCompletionListener, but I don't know what to do with it. Help me please.
What you can do is
//define a variable to be used as index.
int audioindex = 0;
//Extract the files id into an array
int[] audioFileIds=new int[]{R.raw.as,R.raw.bs};
Then in your MediaPlayer onCompletionListener put something like following.
then in your OnCompletionListener.
mp.setOnCompletionListener(new OnCompletionListener(){
// #Override
public void onCompletion(MediaPlayer player) {
// File has ended, play the next one.
FunctionPlayFile(audioFileIds[audioindex]);
audioindex+=1; //increment the index to get the next audiofile
}
});