Android Studio: TimerTask - java

I am creating a simple click game that spawns enemies on screen and when the user clicks them, they get points and the enemies are destroyed. I do this with making imageboxs visible and invisible when the user clicks on them. They run on a timer and have a constant loop of spawning.
Currently I want to implement a way the user will start to loose health. So I would like to check if the enemy imagebox is visible, if it is, the player will slowly loose health.
I am confused with creating a timer task that can refresh the UI for this job. I want to be able to check the UI constantly if some images are visible or not. I have made a start on this from my own research but the game crashes when loaded if this is implemented.
Timer to refresh UI:
private Timer mTimer1;
private TimerTask mTt1;
private Handler mTimerHandler = new Handler();
public void onStart() {
mTimer1 = new Timer();
mTt1 = new TimerTask() {
public void run() {
mTimerHandler.post(new Runnable() {
public void run() {
//TODO
final TextView health = (TextView) findViewById(R.id.Health);
health.setText("Health: " + health2);
//Enemy ImageViews
final ImageView enemy1 = (ImageView) findViewById(R.id.enemy1);
final ImageView enemy2 = (ImageView) findViewById(R.id.enemy2);
final ImageView enemy3 = (ImageView) findViewById(R.id.enemy3);
final ImageView enemy4 = (ImageView) findViewById(R.id.enemy4);
//sets imageViews into array
final ImageView[] enemies = new ImageView[4];
enemies[0] = enemy1;
enemies[1] = enemy2;
enemies[2] = enemy3;
enemies[3] = enemy4;
boolean running = true;
while (running) {
if (enemy1.getVisibility() == View.VISIBLE) {
int damage = 1;
health2 = health2 - damage;
health.setText("Health:" + health2);
} else {
// Either gone or invisible
}
if (enemy2.getVisibility() == View.VISIBLE) {
int damage = 1;
health2 = health2 - damage;
health.setText("Health:" + health2);
} else {
// Either gone or invisible
}
if (enemy3.getVisibility() == View.VISIBLE) {
int damage = 1;
health2 = health2 - damage;
health.setText("Health:" + health2);
} else {
// Either gone or invisible
}
if (enemy4.getVisibility() == View.VISIBLE) {
int damage = 1;
health2 = health2 - damage;
health.setText("Health:" + health2);
} else {
// Either gone or invisible
}
}
}
});
}
};
mTimer1.schedule(mTt1, 1, 5000);
}
}
This is the timer task I have created. I would like some clarity to why this crashes my game and how to fix this issue. I have never used timer in this way before so if the problem is obvious that is why I have not noticed it.
I have a lot more code inside the onCreate method and can post if needed. Thank you for all the help and advice for this begineer.
Crash:

Based on the error message you need to call super.onStart()
so you need to add that here:
public void onStart() {
super.onStart();
//your code
}
I assume you know, but just in case super is class you extend, the parent. if you override it's onStart function the normal onStart procedure isn't done, if you don't call the super function.
EDIT: as for your other question, i (as a beginner with java, so i'm not claiming this is the best way to go) would be thinking along the lines of doing something like:
First create a handler and make runnables for the enemies:
Handler handler = new Handler();
Runnable[] eRunnables = new Runnable[enemies.length-1];
for(int i = 0; i < eRunnables.length; i++){
eRunnables[i] = new Runnable(){
public void run(){
if(enemies[i].getVisibility() == View.VISIBLE){
health2--;
health.setText("Health:" + health2);
handler.postDelayed(eRunnables[i], 1000);
}
}
};
}
And then where you initially make the enemies visible (besides setting them to visible) do something like
handler.postDelayed(eRunnable[enemyNr], 1000);
ofcourse replace the 1000 with however many milliseconds you want.
Again i'm not saying this is the best way, just what i thought up.

Related

Android - User input at specific point in method

I am programming a darts counter app and at the moment I am trying to get an user input (which field on the dart board they hit) by pressing on a specific button.
Each button press will return an int which will be used to update list values that are used by my adapter to then update the views.
The method that should happen in looks like this:
private void startRound(MatchActivityPlayerAdapter adapter) {
for (int playerIndex = 0; playerIndex < getMatchParticipants().size(); playerIndex++) {
for (int currentDart = 1; currentDart <= maximumDartsToThrow; currentDart++) {
// Here I want the activity to "wait" until the user presses a button
if (pointsButtonClicked) {
setDartValue(playerIndex, currentDart);
setDartsCombinedValues(playerIndex, currentDart);
setRemainingPointsValues(playerIndex, currentDart);
adapter.notifyDataSetChanged();
}
}
}
setCurrentRound(getCurrentRound() + 1);
}
Since I cant really stop the activity at the point mentioned above until user has made an input I'll propably have to include a while loop. But in order to do this I think I'll have to create a second thread and handle things differently. That actually overwhelmed me, even though I've been reading through this.
Can anyone please explain to me how I have to design my code in order to achieve what i want?
Edit: Actually pointsButtonClicked is a boolean.
I have over 20 buttons in the global OnClick method and whenever one of them is clicked pointsButtonClicked will be set to true.
Button button1 = findViewById(R.id.btn1);
button1.setOnClickListener(v -> {
outputInt = 1;
pointsButtonClicked = true;
});
Button button2 = findViewById(R.id.btn2);
button2.setOnClickListener(v -> {
outputInt = 2;
pointsButtonClicked = true;
});
// [...]
I think that there should be a better way to this without the while-wait loop.
First of all I suppose that you used an android.widget.Button to implement that pointsButtonClicked
Here's what I would do:
//Global in your activity
int playerIndex = 0;
int currentDart = 1;
Then
private void startRound(MatchActivityPlayerAdapter adapter)
{
pointsButtonClicked.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
setDartValue(playerIndex, currentDart);
setDartsCombinedValues(playerIndex, currentDart);
setRemainingPointsValues(playerIndex, currentDart);
adapter.notifyDataSetChanged();
nextThrow();
}
});
}
And finally
//Also in your activity
private void nextThrow()
{
if (currentDart == maximumDartsToThrow)
{
currentDart = 1;
if (playerIndex == getMatchParticipants().size()-1)
{
playerIndex = 0;
setCurrentRound(getCurrentRound() + 1);
}
else
{
++playerIndex;
}
}
else
{
++currentDart;
}
}
It can be better
You can use private variables and access them with getter and setter
Explained
Using this approach you do not create a thread that waits for every single button pressed. You simply create a button that listen for every click event that it receives and then you apply the logic to cycle the players and the darts for every players.
I hope this could be helpful.
[EDIT]
In this case I would apply the same OnClickListener to every button you use.
First of all I would create an inner class that implements OnClickListener and allows you to manage outputInt variable.
//Also in Activity (it is an inner class)
public class MyOnClickListener implements View.OnClickListener
{
private int myOutputInt;
public MyOnClickListener (int outputInt)
{
this.myOutputInt = outputInt;
}
#Override
public void onClick(View v)
{
pointsButtonClicked = true;
outputInt = myOutputInt;
setDartValue(playerIndex, currentDart);
setDartsCombinedValues(playerIndex, currentDart);
setRemainingPointsValues(playerIndex, currentDart);
nextThrow();
}
}
And then you create 20 MyOnClickListener passing only the int you want to assign. For example:
button1.setOnClickListener(new MyOnClickListener(1));
button2.setOnClickListener(new MyOnClickListener(2));
button3.setOnClickListener(new MyOnClickListener(3));
etc etc...

Why variable gets reset on button click(s) in Android?

Can someone help me to understand what is happening here? Have been trying to debug, but feel like stuck!
I am trying to animate some online images in my Android app using the following method.
private void animateImages() {
// URL loading
// int i = 1; (initialized earlier)
// ArrayList<String> myImages = new ArrayList<>(); (initialized earlier)
myImages.clear();
While (i < 11) {
// Adds ten images using web link
myImages.add("My_web_url");
i++;
}
AccelerateInterpolator adi = new AccelerateInterpolator();
try {
Field mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
mScroller.set(viewPager, new MyScroller(getApplicationContext(), adi, 1));
}
catch (NoSuchFieldException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
if (viewPager != null) {
viewPager.setAdapter(new MyPageAdapter(getApplicationContext(), myImages));
}
final Handler handler = new Handler();
final Runnable Update = new Runnable() {
// Printing variables for debugging
System.out.println("The page number is=" + currentPage);
System.out.println("The myImages size is=" + myImages.size());
public void run() {
if (currentPage == myImages.size() - 1) {
currentPage = 0;
}
viewPager.setCurrentItem(currentPage++, true);
}
};
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
handler.post(Update);
}
// delay and period can be initialized as desired
}, delay, period);
}
}
When I call this method in OnCreate, animation works fine. However, when I call this method in OnClickButton Listener, variable myImages size (before public void run()) become zero and due to this animation doesn't work.
In the above, MySCroller and MyPageAdapeter are java classes. But, most likely, the issue is related to button click, and I don't understand why it resets the myImages size which halts the animation!
This is how button click listener is called. What am I doing wrong?
MyButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
animateImages();
}
});
Edit 1:
Thanks to all the comments, I made a little progress.
I moved all these variables from MainActivity to animateImages() method. The animation runs with button click as well but there is a bump in animation, where too images moves too fast then bump and so on..
// Added just before while loop
DELAY_MS = 1000;
PERIOD_MS = 1000;
i = 1;
currentPage = 0;
I notice the same animation bump if I move the URL loading while loop to OnCreate().
The second time you call animateImages it clears myImages but then doesn't loop because i is not reset so it remains empty. Move creation of that list to onCreate instead to avoid that issue.

I'm trying to make something like Piano Tiles in android studio and I want the tiles to start coming when play button is pressed with same speed

I'm doing this using handler.postdelayed but whenever i start clicking on tiles postdelayed doesn't work sometimes it comes fast and sometimes slow. Here is the code
private Handler mhandler = new Handler();
private Runnable mcontinue = new Runnable() {
#Override
public void run() {
//row5
RockLocationRow5 = RockLocationRow4;
setRockLocation(RockLocationRow5, 5);
//row4
RockLocationRow4 = RockLocationRow3;
setRockLocation(RockLocationRow4, 4);
//row3
RockLocationRow3 = RockLocationRow2;
setRockLocation(RockLocationRow3, 3);
//row2
RockLocationRow2 = RockLocationRow1;
setRockLocation(RockLocationRow2, 2);
//row1
RockLocationRow1 = r.nextInt(3) + 1;
setRockLocation(RockLocationRow1, 1);
mhandler.postDelayed(this, 3000);
}
};
I'm calling it in initgame function whenever the game starts and if i click on any tile I'm also calling this Runnable their
iv_13.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(RockLocationRow1 == 3){
mcontinue.run();
}
else{
//endGame();
}
}
});
or is their anything else that I can use?? I'm a beginner...
this is how RockLocationRow is initialized
//row3
RockLocationRow3 = 1;
iv_31.setImageResource(tapImage);
//row2
RockLocationRow2 = r.nextInt(3) + 1;
setRockLocation(RockLocationRow2, 2);
//row1
RockLocationRow1 = r.nextInt(3) + 1;
setRockLocation(RockLocationRow1, 1);
and this is setRockLocation
private void setRockLocation(int place, int row){
if(row == 1){
iv_11.setImageResource(emptyImage);
iv_12.setImageResource(emptyImage);
iv_13.setImageResource(emptyImage);
switch (place) {
case 1:
iv_11.setImageResource(tapImage);
break;
case 2:
iv_12.setImageResource(tapImage);
break;
case 3:
iv_13.setImageResource(tapImage);
break;
}
}
same for row 2,3,4 and 5
I think I found the problem.
The problem is when you click a tile. If I have understood good, this code is this:
iv_13.setOnClickListener(new View.OnClickListener() {
//rest of your code...
});
You see, when you click on a tile, you call the method run() of Runnable: mcontinue.run();
By calling this method, you execute AGAIN the postDelayed: mhandler.postDelayed(this, 3000); So, for every click on a tile, you execute the postDelayed. As a result, every 3 seconds FROM THE TIME YOU CLICKED A TILE, new tiles will be showing up. If you click lots of tiles, postDelayed will be executing many times and the tiles we be showing up fast.
A solution that may be correct, is to remove mcontinue.run(); when you click a tile. Like this:
iv_13.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(RockLocationRow1 == 3){
}
else {
//endGame();
}
}
});
Please, feel free to comment any of your thoughts/questions about this issue, and I will help as I can.

How to modify a global variable in a method

I have an animation for android with 10 buttons, and I need to trigger this buttons with an order, so I have a variable named order, if order=1 button1 can get activated, if order=2 button 2 can get activated and so on. When I open the program, an animation starts, then a second animation repeats itself after the first one ends and in between I need to change the variable order to 1. I have the next code:
public class Juego extends Activity
{
private AnimationDrawable animacion, loop;
private MediaPlayer miPlayer;
private int order = 0;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_juego);
ImageView video = (ImageView) findViewById(R.id.secuencia);
video.setBackgroundResource(R.drawable.animation_drawable_start);
animacion = (AnimationDrawable) video.getBackground();
animacion.start();
checkIfAnimationDone0(animacion);
}
public void checkIfAnimationDone0(AnimationDrawable anim)
{
final AnimationDrawable a = anim;
int timeBetweenChecks = 20;
android.os.Handler h = new android.os.Handler();
h.postDelayed(new Runnable()
{
public void run()
{
if (a.getCurrent() != a.getFrame(a.getNumberOfFrames() - 1))
{
checkIfAnimationDone1(a);
}
else
{
ImageView video = (ImageView) findViewById(R.id.secuencia);
video.setBackgroundResource(R.drawable.animation_drawable_loop_inicio);
loop = (AnimationDrawable) video.getBackground();
loop.start();
order=1;
}
}
}, timeBetweenChecks);
};
public void onClickButton2(View any)
{
if (order == 1)
{
ImageView video = (ImageView) findViewById(R.id.secuencia);
video.setBackgroundResource(R.drawable.animation_drawable_boton_1);
animacion = (AnimationDrawable) video.getBackground();
miPlayer = MediaPlayer.create(Juego.this, R.raw.sonido_boton_1);
animacion.start();
miPlayer.start();
checkIfAnimationDone1(animacion);
order=2;
}
}
etc..
The problem is that the value of the global variable order does not get changed in the line order=1, and the method onClickButton() cannot start. How do I solve this?
In checkIfAnimationDone0(), when
a.getCurrent() != a.getFrame(a.getNumberOfFrames() - 1)
you go to checkIfAnimationDone1(), so order is never set as 1.
Change checkIfAnimationDone1() in checkIfAnimationDone0() to checkIfAnimationDone0().

Android "Skipped XX frames!"

So I am learning on how to develop android applications.
I am trying to get this program to flash some letters, one at a time fairly quickly
on a textView, but when I try this on my android device and it does not work I get the message "I/Choreographer﹕ Skipped 57 frames! The application may be doing too much work on its main thread."
(AttetionalBlinkTrial is a class that has a field called "blinkList" that is an ArrayList of strings)
public void startTask(View view) throws InterruptedException {
TextView textView = (TextView) findViewById(R.id.display);
AttentionalBlinkTrial theTrial = new AttentionalBlinkTrial();
theTrial.generateTargets();
theTrial.generateBlinkList(5);
for (int i = 0; i <= 5; i++) {
textView.setText(theTrial.getBlinkList().get(i));
Thread.sleep(40);
textView.setText(");
Thread.sleep(40);
}
}
Thread.sleep makes UI thread inaccessible. You should use Handler class instead. Sorry I can't provide any codes since I am on mobile but it's quite easy. If i remember right "postDelayed" method is what you need.
public void blink(TextView textView) {
if (textView.getText() == "Blink!") {
textView.setText("");
} else {
textView.setText("Blink!");
}
}
public void blinkingTask() throws InterruptedException {
final Handler handler = new Handler();
final TextView textView = (TextView) findViewById(R.id.my_text);
Runnable runnable = new Runnable() {
#Override
public void run() {
blink(textView);
}
};
for (int i = 0; i <= 5; i++) {
handler.postDelayed(runnable, 1000 + (i * 1000)); // 5 delayed actions with 1000 ms interval.
}
}
take a look at
Update UI from Thread.
you should do all the operations on seperate thread
AttentionalBlinkTrial theTrial = new AttentionalBlinkTrial();
theTrial.generateTargets();
theTrial.generateBlinkList(5);
and only set text on UI thread.

Categories