I am using Android Studio and I wanted to loop this every half a second
"Random rand = new Random();
int value = rand.nextInt(10);"
So anyway thanks for your time and if you can help that would be great. :)
Sincerely,
Igor
EDIT
Thanks everyone for the kind and helpful answers. I will choose the best answer soon after I try each one out. (Not with my computer right now) But once again, thank you all.
Edit
For anyone having a similar problem I got it to work. Here is the final code.
package sarju7.click;
import android.os.Handler;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import java.util.Random;
public class MainActivity extends ActionBarActivity {
Random rand = new Random();
Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Runnable r = new Runnable() {
public void run() {
int value = rand.nextInt(10);
TextView t1 = (TextView) findViewById(R.id.clicker);
t1.setText(Integer.toString(value));
handler.postDelayed(this, 400);
}
};
handler.postDelayed(r, 400);
}
}
Once again thanks everyone. You guys are the best. I love all of stack overflow!
Use postDelayed(). For example, this activity shows a Toast every five seconds:
/***
Copyright (c) 2012 CommonsWare, LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
by applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.
From _The Busy Coder's Guide to Android Development_
http://commonsware.com/Android
*/
package com.commonsware.android.post;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class PostDelayedDemo extends Activity implements Runnable {
private static final int PERIOD=5000;
private View root=null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
root=findViewById(android.R.id.content);
}
#Override
public void onResume() {
super.onResume();
run();
}
#Override
public void onPause() {
root.removeCallbacks(this);
super.onPause();
}
#Override
public void run() {
Toast.makeText(PostDelayedDemo.this, "Who-hoo!", Toast.LENGTH_SHORT)
.show();
root.postDelayed(this, PERIOD);
}
}
Your run() method of your Runnable is where you do the work and schedule the Runnable to run again after your desired delay period. Just call removeCallbacks() to end the looping. You can call postDelayed() on any widget; in my case, I am using the framework-supplied FrameLayout known as android.R.id.content, as this activity has no other UI.
Random rand = new Random();
Handler handler = new Handler()
Runnable r=new Runnable() {
public void run() {
int value = rand.nextInt(10);
handler.postDelayed(this, 500);
}
};
handler.postDelayed(r, 500);
Use this
create this in onCreate
Random rand = new Random();
handler=new Handler();
handler.postDelayed(myRunnable, 100);
declare it outside onCreate
myRunnable=new Runnable() {
#Override
public void run() {
int value = rand.nextInt(10);
handler.postDelayed(this, 100);
}
}
While all of the answers here are good, they do not necessarily address why you want this or what you will do with the result. You can do this anywhere in your code, but you are probably asking because it will block the UI thread if it's run there and you probably don't want that.
You need to run this in the background on a different thread or service so the user can interact while the loop is running. That is the basic answer - run this loop on another thread besides the MAIN or UI thread. (There are a lot of answers here that address that.)
If you want a random number to display on the screen every half second, then a lot of these options are fine except they don't explain that if you run them in a different thread, then you need to create the class in your Activity and then use the runOnUiThread thread method to update your view classes (otherwise you will get errors).
If you want to use it as the start to doing further background processing, you should consider a Service where you can expand the functionality of your loop and whatever other tasks it may need to perform while the UI thread is running. For example, if you are needing random numbers to select images that are displayed on the screen, you may want to run this in a service that provides images to the Activity.
Hope that helps.
Related
I am learning Android's new SplashScreen API introduced with Android 12. I have so far gotten it to work on my Emulator and Google Pixel 4A, but I want to increase its duration. In my Splash Screen I do not want a fancy animation, I just want a static drawable.
I know, I know (sigh) some of you might be thinking, that I should not increase the duration and I know there are several good arguments in favor of not doing so. However, for me the duration of a splash screen with a non animated drawable is so brief (less than a second), I think it raises an accessibility concern, especially so since it cannot be disabled (ironically). Simply, the organization behind the product or its brand/product identity cannot be properly absorbed or recognized by a new user at that size and in that time, rendering the new splash screen redundant.
I see the property windowSplashScreenAnimationDuration in the theme for the splash screen (shown below), but this has no effect on the duration presumably because I am not animating.
<style name="Theme.App.starting" parent="Theme.SplashScreen">
<!--Set the splash screen background, animated icon, and animation duration.-->
<item name="windowSplashScreenBackground">#color/gold</item>
<!-- Use windowSplashScreenAnimatedIcon to add either a drawable or an
animated drawable. One of these is required-->
<item name="windowSplashScreenAnimatedIcon">#drawable/accessibility_today</item>
<item name="windowSplashScreenAnimationDuration">300</item> <!--# Required for-->
<!--# animated icons-->
<!--Set the theme of the activity that directly follows your splash screen-->
<item name="postSplashScreenTheme">#style/Theme.MyActivity</item>
<item name="android:windowSplashScreenBrandingImage">#drawable/wculogo</item>
</style>
Is there a straightforward way to extend the duration of a non animated splash screen?
As I was writing this question and almost ready to post it, I stumbled on the method setKeepOnScreenCondition (below) that belongs to the splashScreen that we must install on the onCreate of our main activity. I thought it seemed wasteful not to post this, given there are no other posts on this topic and no such similar answers to other related questions (as of Jan 2022).
SplashScreen splashScreen = SplashScreen.installSplashScreen(this);
plashScreen.setKeepOnScreenCondition(....);
Upon inspecting it I found this method receives an instance of the splashScreen.KeepOnScreenCondition() interface for which the implementation must supply the following method signature implementation:
public boolean shouldKeepOnScreen()
It seems this method will be called by the splash screen and retain the splash screen visibly until it returns false. This is where the light bulb moment I so love about programming occurred.
What if I use a boolean initialized as true, and set it to false after a delay? That hunch turned out to work. Here is my solution. It seems to work and I thought it would be useful to others. Presumably instead of using a Handler for a delay, one could also use this to set the boolean after some process had completed.
package com.example.mystuff.myactivity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.splashscreen.SplashScreen;
import android.os.Bundle;
import android.os.Handler;
public class MainActivity extends AppCompatActivity {
private boolean keep = true;
private final int DELAY = 1250;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Handle the splash screen transition.
SplashScreen splashScreen = SplashScreen.installSplashScreen(this);
super.onCreate(savedInstanceState);
//Keep returning false to Should Keep On Screen until ready to begin.
splashScreen.setKeepOnScreenCondition(new SplashScreen.KeepOnScreenCondition() {
#Override
public boolean shouldKeepOnScreen() {
return keep;
}
});
Handler handler = new Handler();
handler.postDelayed(runner, DELAY);
}
/**Will cause a second process to run on the main thread**/
private final Runnable runner = new Runnable() {
#Override
public void run() {
keep = false;
}
};
}
If you are into Java Lambdas an even nicer and more compact solution is as follows:
package com.example.mystuff.myactivity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.splashscreen.SplashScreen;
import android.os.Bundle;
import android.os.Handler;
public class MainActivity extends AppCompatActivity {
private boolean keep = true;
private final int DELAY = 1250;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Handle the splash screen transition.
SplashScreen splashScreen = SplashScreen.installSplashScreen(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Keep returning false to Should Keep On Screen until ready to begin.
splashScreen.setKeepOnScreenCondition(() -> keep);
Handler handler = new Handler();
handler.postDelayed(() -> keep = false, DELAY);;
}
}
If you have comments or feedback (besides telling me I should not increase the duration of the splash screen), or a better way please do comment or respond with additional answers.
in Kotlin:
var keepSplashOnScreen = true
val delay = 2000L
installSplashScreen().setKeepOnScreenCondition { keepSplashOnScreen }
Handler(Looper.getMainLooper()).postDelayed({ keepSplashOnScreen = false }, delay)
you can put this into onCreate fun before super.onCreate calling (in activity with LAUNCHER intent filter in Manifest)
One proxy way could be to use
runBlocking { delay(1200) } in onCreate method, to keep on main thread for some specific time.
I tried to get the width of a LinearLayout.
Here is the code of the MainActivity.java:
public class MainActivity extends AppCompatActivity {
BoardClass board;
private int widthareagame;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final LinearLayout gamearea;
ImageView im1 ;
Button abutton;
abutton = (Button) findViewById(R.id.buttonnew);
gamearea = ( LinearLayout) findViewById(R.id.boardarea);
gamearea.post(new Runnable(){
public void run(){
widthareagame = gamearea.getWidth();
}
});
board = new BoardClass(this,widthareagame);
gamearea.addView(board);
}
The value of widthareagame at new BoardClass(this,widthareagame); is still Zero.
Thanks
Here is what documentation says about View#post():
Causes the Runnable to be added to the message queue. The runnable
will be run on the user interface thread.
Your task, of modifying the value of widthareagame variable, has been pushed to the message queue of the view. It doesn't guarantee that it will get executed at the very same instance. The control then proceeds to the next line, where you still get the unmodified value.
You can try something like this, to ensure that you are able to use the modified value:
gamearea.post(new Runnable(){
public void run(){
widthareagame = gamearea.getWidth();
board = new BoardClass(this,widthareagame);
gamearea.addView(board);
}
});
This is because post method call queued the setting of widthareagame where as your view is rendering.You didn't guarantee the order of execution.
You have to make sure the statements inside the run method execute first and then new Board(.. is invoked.For that you can do something like this
final AtomicBoolean done = new AtomicBoolean(false);
run(){
//inside run method
done.set(true);
notify();
}
then do something like this
synchronized(task) {
while(!done.get()) {
task.wait();
}
new Board(..
}
where task is your runnable task defined something like this
final Runnable task = new Runnable() {
#Override
public void run() {
The reason is zero is because within the onCreate the LinearLayout has not been measured yet.
And the reason it only works when within the Runnable is because since this one has been posted then it will run on the next execution cycle, which is after the onCreate and the rest of the Activity lifecycle methods (onStart, onResume, etc.) and even onAttachedToWindow have been called, at which point will be already measured and give the correct size.
Said all that, a safer way to get your layout metrics with certainty would be to listen when the layout state changes.
gamearea.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Remove the listener here unless you want to get this callback for
// "every" layout pass, which can get you into an infinite loop if you
// modify the layout from within this method
gamearea.getViewTreeObserver().removeGlobalOnLayoutListener(this);
// A this point you can get the width and height
widthareagame = gamearea.getWidth();
}
});
I make a game with Java and LibGdx
It's a game of skill with a time limit, and the problem is the player can push home button to pause app, and go to task manager, and can see preview of app to seek what he has to find without counting time
So, I would like to hide the preview of the app when the player push home button to pause
What I tried to do
I override pause and resume handler
#Override
public void pause() {
Gdx.app.log("LibGDX", "pause");
state = State.PAUSE;
Gdx.graphics.setContinuousRendering(false);
Gdx.graphics.requestRendering();
}
#Override
public void resume() {
Gdx.app.log("LibGDX", "resume");
state = State.RUN;
Gdx.graphics.setContinuousRendering(true);
}
and main part of my public void render(float) function
switch (state)
{
case RUN:
// game
break;
case PAUSE:
// a black rectangle on screen
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(Color.BLACK);
shapeRenderer.rect(0, 0, GameScreen.WIDTH, GameScreen.HEIGHT);
shapeRenderer.end();
break;
default:
break;
}
log tell me that pause and resume are indeed invoked
but in task manager, I still see the game and not the black rectangle
Update 1
to Ridcully answer :
I tried what you suggested
package com.mygdx.game;
import android.os.Bundle;
import android.view.WindowManager;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
public class AndroidLauncher extends AndroidApplication {
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
// --
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
// --
initialize(new MyGame(), config);
}
}
But same thing, I still see the screenshot
I'm with Android Studio 2.1
My smartphone: Oneplus One
and Android 6.0.1
Do you have an idea ? thanks
There is a flag for that. You can use this little method, e.g. in onCreate() to prevent Android from creating a 'screenshot' for the 'recent activities' list. You can activate/deactivate as you want, e.g. only activate it when the actual game board is visible etc.
/**
* Sets/clears FLAG_SECURE which prevents system from creating screenshots for 'recent activities' list.
* Flag should be set while user is in vault.
*
* #param set
*/
protected void setWindowFlagSecure(boolean set) {
if (set) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
EDIT
I just found this SO answer, regarding Libgdx applications: Seems you have to set the flag AFTER invoking the initialize() method.
You can do that using
public class SampleActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE);
setContentView(R.layout.main);
}
}
Make sure you do that before you call setContentView.
Ok, somewhat similar questions have been asked, but there is no answer that has made any difference in solving my problem. I've tried Thread.sleep, and also the delayed runnable. Using a Handler, etc.
I want to display a sequence of frame animations(AnimationDrawable) using the same imageview and changing the background animations as needed. The user inputs a series of 5 animations and can then play them back(if my program worked). Once the animations are selected I use a for loop that contains if statements and a switch statement to select that whatever animations were chosen and play them back.
As you might imagine, this doesn't work correctly, as the program whips through the for loop and only the first and last animation actually play. Here is the jist of the code:
for(i=0;i<5;i++){
if(conditions){
view.setBackground(chosenAnimation);
((AnimationDrawable)view.getBackground().start();
}
}
So as I said, I have tried Thread.sleep(), that doesn't do what I'm looking for. I have tried using the Handler class and putting a delay on the runnable. I have tried this:
view.postDelayed(new Runnable() {
#Override
public void run() {
//works the same without this line
((AnimationDrawable)view.getBackground()).stop();
((AnimationDrawable)view.getBackground()).start();
}
}, 1000);
None of these things do anything at all except add pauses before it does the exact same thing it did before I added this stuff. I have meticulously debugged the code and everything is working correctly. The animations have all been individually tested.
As I said, similar questions have been asked and answered and nothing offered does what I want, which is for the program to wait until one animation is finished before it runs through the for loop again.
I'd like to state again that this is a series of frame animations using AnimationDrawable and the same imageview each time. Thanks in advance!
All your animations will be started with the same delay, you should increase this delay by multiplying it by i for example. You also can count duration of every animation programmatically and increase delay as you need it.
I just tried to achieve what you want and had no problems, although my example uses 3rd party library, it's not necessary.
package com.example.masktest.app;
import android.animation.Animator;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.concurrent.atomic.AtomicReference;
import static com.dtx12.android_animations_actions.actions.Actions.*;
public class MainActivity extends AppCompatActivity {
ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView) findViewById(R.id.imageView);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
playAnimation();
}
});
}
private void playAnimation() {
final AnimationDrawable firstDrawable = (AnimationDrawable) ContextCompat.getDrawable(MainActivity.this, R.anim.anim_android);
final AnimationDrawable secondDrawable = (AnimationDrawable) ContextCompat.getDrawable(MainActivity.this, R.anim.anim_android_2);
final AtomicReference<Integer> cpt = new AtomicReference<>(0);
Animator sequence = repeat(6, sequence(run(new Runnable() {
#Override
public void run() {
if (imageView.getDrawable() instanceof AnimationDrawable) {
((AnimationDrawable) imageView.getDrawable()).stop();
}
imageView.setImageDrawable(cpt.get() % 2 == 0 ? secondDrawable : firstDrawable);
((AnimationDrawable) imageView.getDrawable()).start();
cpt.set(cpt.get() + 1);
}
}), delay(countAnimationDuration(secondDrawable))));
play(sequence, imageView);
}
private float countAnimationDuration(AnimationDrawable drawable) {
int duration = 0;
for (int i = 0; i < drawable.getNumberOfFrames(); i++) {
duration += drawable.getDuration(i);
}
return duration / 1000f;
}
}
You can simply using for loop and you dont need 3rd party library.
Lets say you have a LinearLayout(or any viewgroup) that you want to add these buttons dynamically. You can do something like this:
for (int i = 0; i < buttons.size(); i++) {
Button button = new Button(context);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
linearLayout.addView(button);
animateButton(button);
}
}, BUTTON_DELAY_DURATION * i);
}
Thanks to some assistance from dtx12 here, I have realized my problem, and I thought I'd leave some code here since I am not good enough to completely understand their example.
I didn't quite understand what I was doing making new threads, and it turns out I was just making 5 threads that all went off at the same time, as dtx12 explained and I eventually understood. So here's a basic way of doing this:
public void playAnimation(){
// in dtx12's answer they demonstrate how to get the
// exact duration of any give animation using
//getNumberOfFrames() and getDuration() methods of
// AnimationDrawable but I am just hardcoding it for simplicity
int duration=2000;
// This is to keep track of the animations which are in an array, I use this variable in run()
order=1;
for(int i=0;i<5;i++){
//play the first animation
if(i==0){
view.setBackground(animation[0]);
animation[i].stop();
animation[i].start();
}
else{
//Now set up the next animation to play after 2000ms, the next after 4000ms, etc.
//You are supposed to use a handler if you want to change the view in the main thread.
//it is very easy: Handler handler=new Handler():
handler.postDelayed(new Runnable(){
#Override
public void run() {
view.setBackground(animation[order]);
animation[order].stop();
animation[order].start();
order++;
}
}, duration);
//dtx12 suggestion of multiplying by i is probably smarter
duration+=2000;
}
}
}
So there you have it. Not the most elegant display of coding, but it gets the basic job done. You can't use 'i' in the run() method because it is an anonymous inner class, and if you assign the value of 'i' to another variable in the loop, it will be '4', by the time the other threads execute. So, I just did some counting inside of run to make sure everything fired in order.
I'm designing a music player app for Android that will feature pop-up controls. I'm currently trying to get these controls to close after a certain period of inactivity but there doesn't seem to be a clearly documented method of doing this. So far I have managed to cobble the following solution together using a few suggestions both from this site and others.
private Timer originalTimer = new Timer();
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.playcontrols);
View exitButton = findViewById(R.id.controls_exit_pane);
exitButton.setOnClickListener(this);
View volUpButton = findViewById(R.id.controls_vol_up);
volUpButton.setOnClickListener(this);
View playButton = findViewById(R.id.controls_play);
playButton.setOnClickListener(this);
View volDownButton = findViewById(R.id.controls_vol_down);
volDownButton.setOnClickListener(this);
musicPlayback();
originalTimer.schedule(closeWindow, 5*1000); //Closes activity after 10 seconds of inactivity
}
And the code that should close the window
//Closes activity after 10 seconds of inactivity
public void onUserInteraction(){
closeWindow.cancel(); //not sure if this is required?
originalTimer.cancel();
originalTimer.schedule(closeWindow, 5*1000);
}
private TimerTask closeWindow = new TimerTask() {
#Override
public void run() {
finish();
}
};
The above code makes perfect sense to me but it force closes upon any user interaction. It does however close normally if untouched and won't close after interaction if I remove the second schedule, so this seems to be the problem. Also note that I imagine I will be moving this timing task to another thread to help keep the UI snappy. I need to get it working first though :D. If there's any more info I need to supply please ask and thanks for any help...Ye guys are brilliant!
Based on #CommonsWare's suggestion, switched to a Handler. Works perfectly. Thanks very much!
private final int delayTime = 3000;
private Handler myHandler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.playcontrols);
View exitButton = findViewById(R.id.controls_exit_pane);
exitButton.setOnClickListener(this);
View volUpButton = findViewById(R.id.controls_vol_up);
volUpButton.setOnClickListener(this);
View playButton = findViewById(R.id.controls_play);
playButton.setOnClickListener(this);
View volDownButton = findViewById(R.id.controls_vol_down);
volDownButton.setOnClickListener(this);
musicPlayback();
myHandler.postDelayed(closeControls, delayTime);
}
and the other methods...
//Closes activity after 10 seconds of inactivity
public void onUserInteraction(){
myHandler.removeCallbacks(closeControls);
myHandler.postDelayed(closeControls, delayTime);
}
private Runnable closeControls = new Runnable() {
public void run() {
finish();
overridePendingTransition(R.anim.fadein, R.anim.fadeout);
}
};
To complete the answer above, note that the Activity.onUserInteraction() is adequate only if you care about clicks.
The documentation at http://developer.android.com/reference/android/app/Activity.html#onUserInteraction%28%29 states: "Note that this callback will be invoked for the touch down action that begins a touch gesture, but may not be invoked for the touch-moved and touch-up actions that follow."
Actual implementation proved it indeed ignores all movements on the tablet, which means the clock is never reset while, say, drawing without releasing the finger. On the other hand, it also means that the clock is not reset too often, which limits the overhead.