How to run code multiple times in Java Android Studio - java

I am new to making android apps, and I don't know how to run a piece of code multiple times.
Here is my code:
package com.example.test;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import java.util.Random;
import android.widget.AbsoluteLayout;
import android.util.*;
import java.util.concurrent.TimeUnit;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
int score = 0;
TextView scoreText;
ImageButton mole;
Random random = new Random();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scoreText = findViewById(R.id.scoreCount);
mole = findViewById(R.id.mole);
//I want to run this multiple times
TimeUnit.MILLISECONDS.sleep(random.nextInt(500));
AbsoluteLayout.LayoutParams absParams =
(AbsoluteLayout.LayoutParams) mole.getLayoutParams();
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int width = displaymetrics.widthPixels;
int height = displaymetrics.heightPixels;
Random r = new Random();
absParams.x = r.nextInt(width);
absParams.y = r.nextInt(height);
mole.setLayoutParams(absParams);
}
#Override
public void onClick(View v) {
}
}
I am trying to make a mole game where the mole randomly goes across the screen and you have to tap it to earn points, the thing is though, I don't know how to run
TimeUnit.MILLISECONDS.sleep(random.nextInt(500));
AbsoluteLayout.LayoutParams absParams =
(AbsoluteLayout.LayoutParams) mole.getLayoutParams();
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int width = displaymetrics.widthPixels;
int height = displaymetrics.heightPixels;
Random r = new Random();
absParams.x = r.nextInt(width);
absParams.y = r.nextInt(height);
mole.setLayoutParams(absParams);
again and again. I've tried doing
Thread test = new Thread(new Runnable() {
#Override
public void run() {
try {
//I want to run this multiple times
TimeUnit.MILLISECONDS.sleep(500);
AbsoluteLayout.LayoutParams absParams =
(AbsoluteLayout.LayoutParams) mole.getLayoutParams();
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int width = displaymetrics.widthPixels;
int height = displaymetrics.heightPixels;
Random r = new Random();
absParams.x = r.nextInt(width);
absParams.y = r.nextInt(height);
mole.setLayoutParams(absParams);
}catch(InterruptedException e){
Log.i("Error", "Thread");
}
}
});
test.start();
But it keeps returning the following error:
com.example.test E/AndroidRuntime: FATAL EXCEPTION: Thread-1057
Process: com.example.test, PID: 25335
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7266)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1065)
at android.view.View.requestLayout(View.java:19098)
at android.view.View.requestLayout(View.java:19098)
at android.view.View.requestLayout(View.java:19098)
at android.view.View.requestLayout(View.java:19098)
at android.view.View.requestLayout(View.java:19098)
at android.view.View.requestLayout(View.java:19098)
at android.view.View.requestLayout(View.java:19098)
at android.view.View.setLayoutParams(View.java:12590)
at com.example.test.MainActivity$1.run(MainActivity.java:48)
at java.lang.Thread.run(Thread.java:818)

you can use RxJava as #Mohammad Reza Khahani mentioned which make life easier but if you don't want to get in to it you have two option to run your Thread and change the UI.
first one is to create Handler and inside of your Thread use it to run your code related to UI:
Handler handler = new Handler(); // create new instance in ui thread eg: #onCreate or #onResume
handler.post(new Runnable() {
#Override
public void run() {
//UI changes
}
});
Or you can use YourActivity.this.runOnUiThread method of activity inside of your background-thread to run your UI related code.
runOnUiThread(new Runnable() {
#Override
public void run() {
//UI changes
}
});

Related

Android OOM Error, Loading multiple images

I was looking at this answer over here, however it didn't really fix my problem.
For some reason the manifest.xml doesn't overwrite my changes, even though I deleted my build folder.
I am trying to load up 5 images on the screen, however even after optimizing them; they still run out of memory.
I was watching a video that teaches image scaling. It did solved a small portion of my problem. I am able to load my background image, however I wasn't able to load my other 4 images.
How can I optimize more efficiently? I was watching this video regards Bitmap optimization by Android, however I didn't understand much from it.
Here is my source code
MainActivity.java
package com.example.cliente.myapplication;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
private static final float BYTES_PER_PX = 4.0f;
ImageView backgroundImage, upImage, downImage, leftImage, alertImage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
backgroundImage = findViewById(R.id.background_image);
loadImage(backgroundImage, R.drawable.background);
upImage = findViewById(R.id.up_arrow_image);
loadImage(upImage, R.drawable.up);
downImage = findViewById(R.id.down_arrow_image);
loadImage(downImage, R.drawable.down);
leftImage = findViewById(R.id.left_arrow_image);
loadImage(leftImage, R.drawable.left);
alertImage = findViewById(R.id.alert_image);
loadImage(alertImage, R.drawable.alert);
}
private void loadImage(ImageView image, int imgSrc) {
if (readBitmapInfo() > MemUtils.megabytesFree()) {
subSampleImage(image, 32);
} else {
image.setImageResource(imgSrc);
}
}
private float readBitmapInfo() {
final Resources res = this.getResources();
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, R.drawable.background, options);
final float imageHeight = options.outHeight;
final float imageWidth = options.outWidth;
return imageWidth * imageHeight * BYTES_PER_PX / MemUtils.BYTES_IN_MB;
}
private void subSampleImage(ImageView image, int powerOf2) {
if (powerOf2 < 1 || powerOf2 > 2) {
return;
}
final Resources res = this.getResources();
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inSampleSize = powerOf2;
final Bitmap map = BitmapFactory.decodeResource(res, R.drawable.background, options);
image.setImageBitmap(map);
}
}
MemUtils.java
package com.example.cliente.myapplication;
public class MemUtils {
public static final float BYTES_IN_MB = 1024.0f * 1024.0f;
public static float megabytesFree() {
final Runtime rt = Runtime.getRuntime();
final float bytesUsed = rt.totalMemory();
final float mbUsed = bytesUsed / BYTES_IN_MB;
final float mbFree = megabytesAvailable() - mbUsed;
return mbFree;
}
public static float megabytesAvailable() {
final Runtime rt = Runtime.getRuntime();
final float bytesAvailable = rt.maxMemory();
return bytesAvailable / BYTES_IN_MB;
}
}
So I had 2 errors to begin with.
OOM (out of memory) exception, thanks too #Chisko, I used a library called Picasso to solve my problem.
Another issue was Canvas: trying to draw too large... problem. Which I needed to move my images from drawable-mdpi to drawable-xxhdpi.
Here is the solution to my problem:
package com.example.cliente.myapplication;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
public class MainActivity extends AppCompatActivity {
ImageView backgroundImage, upImage, downImage, leftImage, alertImage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
backgroundImage = findViewById(R.id.background_image);
Picasso.get().load(R.drawable.background).into(backgroundImage);
upImage = findViewById(R.id.up_arrow_image);
Picasso.get().load(R.drawable.up).into(upImage);
downImage = findViewById(R.id.down_arrow_image);
Picasso.get().load(R.drawable.down).into(downImage);
leftImage = findViewById(R.id.left_arrow_image);
Picasso.get().load(R.drawable.left).into(leftImage);
alertImage = findViewById(R.id.alert_image);
Picasso.get().load(R.drawable.alert).into(alertImage);
}
}

Displaying Images Dynamically

I am using the following code to display images from drawable folder.
But now i want to display pictures dynamically.Every time a new image is added to the drawable folder i don't want go again in the code and add it in the array it should automatically increment and get displayed.
Any Idea how should I go about this.Just started working on Android.
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.Menu;
import android.widget.ImageView;
import android.app.Service;
import android.os.Handler;
public class MainActivity extends AppCompatActivity {
private static ImageView imgView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imgView = (ImageView) findViewById(R.id.imageView);
final int[] images=images{R.drawable.ic_launcher,
R.drawable.ic_launcher1,R.drawable.ic_launcher2,etc..};
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
int i=0;
public void run() {
imgView.setImageResource(images[i]);
i++;
if(i>images.length-1)
{
i=0;
}
handler.postDelayed(this,5000); //for interval...
}
};
handler.postDelayed(runnable, 5000); //for initial delay..
}
if you want to add the image Dynamically you can Naming the image File like this : Image1.png; Image2.png; and so on.
And then you dont need to call all of them in the array, instead you can using lopp to get the name of the image in resource.
and then get the id using the code below :
public int getID(String resourceName,Context context){
Resources resources = context.getResources();
final int resourceId = resources.getIdentifier(resourceName, "drawable",
context.getPackageName());
return resourceId;
}
Note : after adding the image don't forget to increament the loop. hope it helps.
please keep variable i as static
i.e static int i=0;
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
imgView.setImageResource(images[i]);
i++;
if(i>images.length-1)
{
i=0;
}
handler.postDelayed(this,5000); //for interval...
}
};
handler.postDelayed(runnable, 5000); //for initial delay..
change the handle code as follow
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
imgView.setImageResource(images[i]);
if(i>images.length-1)
{
i=0;
}
else
{
i++;
}
handler.postDelayed(this,5000); //for interval...
}
};
handler.postDelayed(runnable, 5000); //for initial delay..

How to make a Button randomly Move

I have a question about how to make a button randomly move every second.
The black tiles are a button:
So I want to make it move randomly in every second or more fast.
this is my xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/backgroundblank" >
<Button
android:id="#+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/black1" />
</RelativeLayout>
this is the code
public class tested extends Activity {
Button buttonblack;
int score=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.tested);
buttonblack = (Button)findViewById(R.id.black1);
buttonblack.setOnClickListener(new View.OnClickListener() {
public void onClick(View v){
//score+10(i dont know how to make score +10 if the button clicked)
//if the button clicked
//Do some logic here
}
});
if (score = 100){
//the speed of move are increase more fast
}
}
anyone can help me?
First you should get the screen size
public static Point getDisplaySize(#NonNull Context context) {
Point point = new Point();
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
manager.getDefaultDisplay().getSize(point);
return point;
}
Then you should get a random x and random y position for the button to go to so that its still on screen
private void setButtonRandomPosition(Button button){
int randomX = new Random().nextInt(getDisplaySize(this).x);
int randomY = new Random().nextInt(getDisplaySize(this).y);
button.setX(randomX);
button.setY(randomY);
}
Finally to make this happen every second
private void startRandomButton(Button button) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
setButtonRandomPosition(button);
}
}, 0, 1000);//Update button every second
}
In on create run it like this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.tested);
buttonblack = (Button)findViewById(R.id.black1);
startRandomButton(blackbutton);
}
Activity onCreate use this code
Button button = (Button)findViewById(R.id.my_button);
Create method
public void buttonmove()
{
RelativeLayout .LayoutParams absParams = (RelativeLayout .LayoutParams)button.getLayoutParams();
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int width = displaymetrics.widthPixels;
int height = displaymetrics.heightPixels;
Random r = new Random();
absParams.x = r.nextInt(width) ;
absParams.y = r.nextInt(height);
button.setLayoutParams(absParams);
}
if you want in particular time use Timer
Timer t=new Timer();
t.schedule(new TimerTask() {
public void run() {
buttonmove();//call method
}
}, new SimpleDateFormat("HH:mm:ss").parse("13:40:20"));//set time here

ViewFlipper: flipping at random time intervals using random children

I want to create a menu which "flips" at random time intervals between 5 children of a viewflipper in random order.
I tried the following code and I can get the System.out.println to display my debugging message to be logged in the logcat at random time intervals so that's working.
However, my screen in the emulator is all black.
When I simply use the setDisplayedChild method in the "onCreate" method with a fixed int, it works fine. Can you help me with this? Thanks many!
public class FlipperTest extends Activity {
int randomTime;
int randomChild;
ViewFlipper fliptest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_beat_the_game);
ViewFlipper fliptest = (ViewFlipper) findViewById(R.id.menuFlipper);
//this would work
//fliptest.setDisplayedChild(3);
while (true){
try {
Thread.sleep(randomTime);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
Random timerMenu = new Random();
randomTime = timerMenu.nextInt(6) * 2000;
Random childMenu = new Random();
randomChild = childMenu.nextInt(5);
fliptest.setDisplayedChild(randomChild);
System.out.println("executes the finally loop");
}
}
}
Don't block the UI thread like you do with Thread.sleep()(+ infinite loop), instead use a Handler, for example, to make your flips:
private ViewFlipper mFliptest;
private Handler mHandler = new Handler();
private Random mRand = new Random();
private Runnable mFlip = new Runnable() {
#Override
public void run() {
mFliptest.setDisplayedChild(mRand.nextInt());
mHandler.postDelayed(this, mRand.nextInt(6) * 2000);
}
}
//in the onCreate method
mFliptest = (ViewFlipper) findViewById(R.id.menuFlipper);
mHandler.postDelayed(mFlip, randomTime);
Here is my final code. I changed a few things: I put the randomTime int in the run method so that it's updated at each run and therefore the handler gets delayed randomly. Otherwise, it will be delayed according to the first run of the randomly generated number and the time intervals will stay the same. I also had to manipulate the generated randomTime int because if the randomly generated int is 0, then the delay is 0 as well and the flip happens instantly which is not what I wanted.
Thanks a million for your help! :-)
private ViewFlipper fliptest;
private Handler testHandler = new Handler();
private Random mRand = new Random();
private Random timerMenu = new Random();
int randomTime;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
fliptest = (ViewFlipper) findViewById(R.id.menuFlipper);
testHandler.postDelayed(mFlip, randomTime);
}
private Runnable mFlip = new Runnable() {
#Override
public void run() {
randomTime = (timerMenu.nextInt(6) + 1) * 2000;
System.out.println("executes the run method " + randomTime);
fliptest.setDisplayedChild(mRand.nextInt(6));
testHandler.postDelayed(this, (mRand.nextInt(6)+ 1) * 2000);
}
};

Android: roatating images in a loop

I am trying with no success to modify the code example from:
http://www.inter-fuser.com/2009/08/android-animations-3d-flip.html
so it will rotate the images in a loop, when clicking on the image once. (second click should pause).
I tried using Handler and threading but cannot update the view since only the main thread can update UI.
Exception I get from the code below:
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
[in 'image1.startAnimation(rotation);' ('applyRotation(0, 90);' from the main thread)]
package com.example.flip3d;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;
public class Flip3d extends Activity {
private ImageView image1;
private ImageView image2;
private boolean isFirstImage = true;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
image1 = (ImageView) findViewById(R.id.image01);
image2 = (ImageView) findViewById(R.id.image02);
image2.setVisibility(View.GONE);
image1.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (isFirstImage) {
applyRotation(0, 90);
isFirstImage = !isFirstImage;
} else {
applyRotation(0, -90);
isFirstImage = !isFirstImage;
}
}
});
}
private void applyRotation(float start, float end) {
// Find the center of image
final float centerX = image1.getWidth() / 2.0f;
final float centerY = image1.getHeight() / 2.0f;
// Create a new 3D rotation with the supplied parameter
// The animation listener is used to trigger the next animation
final Flip3dAnimation rotation =
new Flip3dAnimation(start, end, centerX, centerY);
rotation.setDuration(500);
rotation.setFillAfter(true);
rotation.setInterpolator(new AccelerateInterpolator());
rotation.setAnimationListener(new DisplayNextView(isFirstImage, image1, image2));
if (isFirstImage)
{
image1.startAnimation(rotation);
} else {
image2.startAnimation(rotation);
}
}
}
How can I manage to update the UI and control the rotation within onClick listener?
Thank you,
Oakist
Try wrapping the UI code in runOnUIThread()

Categories

Resources