Probable android memory leak - android

I have this android project, can not identify why it is eating up RAM ? Note there is no processing just RAM being filled in. I have read Android RAM issues and how to solve, but can't make out what to do. I am new to both android and java.
Noticed just now (in Android Monitor - RAM) my app is using only 4MB of memory.
If anyone tries to run (please do - MainActivity is launcher and MyCanvas is just a class used as View) this, i can use speed variable as high as 100 (even more maybe), make thread call back in 10ms or even more frequent - it creates no problem. But as soon as I touch and move garbage collector comes pauses everything.
MyCanvas.java (used as view)
package com.abc.mygraphics;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
import java.util.Random;
import android.os.Handler;
public class MyCanvas extends View {
public static Paint paint;
//public static int n = 5000;
public static int N = 100, particleSize = 3;
public static int height, width;
public static float[][] pos = new float[N][2];
public static float[][] pos0 = new float[N][2];
//public static float distX, distY, dist;
Handler handler = new Handler();
public static int speed = 1;
public static int gravityX, gravityY;
public static Random random = new Random();
public static int[] colorList = new int[10];
public static int sphereSize = 100, M = 10;
public static float[] distance = new float[N];
public static int[][] gravity = new int[N][2];
public static boolean[] direction = new boolean[N];
public static int[] moved = new int[N];
public MyCanvas(Context context) {
super(context);
width = MainActivity.sharedPreferences.getInt("screenX", 200);
height = MainActivity.sharedPreferences.getInt("screenY", 200);
colorList = new int[]{Color.RED, 0xffff4000, 0xffffff00, 0xff40ff00, 0xff00ff00, 0xff00ff80, 0xff0080ff, 0xff0000ff, 0xffbf00ff, 0xffff0040};
paint = new Paint();
paint.setColor(Color.GRAY);
int i;
for (i = 0; i < N; i++) {
pos[i][0] = random.nextInt(width);
pos[i][1] = random.nextInt(height);
pos0[i][0] = pos[i][0];
pos0[i][1] = pos[i][1];
moved[i] = 0;
direction[i] = true;
}
final Runnable r = new Runnable() {
public void run() {
invalidate();
handler.postDelayed(this, 100);
}
};
handler.postDelayed(r, 100);
}
public static void changeGravity(){
gravityX = MainActivity.sharedPreferences.getInt("x",200);
gravityY = MainActivity.sharedPreferences.getInt("y",200);
// gravityY -= 68;
for(int i=0;i<N;i++){
calcDist(i);
}
}
#Override
public void onDraw(Canvas canvas){
int i;
int x; //remove at some poitnt
canvas.drawColor(Color.BLACK);
//canvas.drawCircle(gravityX,gravityY, 50, paint);
for(i=0;i<N;i++) {
setPosition(i);
x = random.nextInt(10);
paint.setColor(colorList[x]);
canvas.drawCircle(pos[i][0], pos[i][1], particleSize, paint);
}
}
public static void setPosition(int i){
// this is wrong
if(moved[i] >= (int)distance[i]/speed){
direction[i] = !direction[i];
setGravity(i);
}
else{
pos[i][0] = pos0[i][0] + speed*moved[i]*(gravity[i][0]- pos0[i][0])/distance[i];
pos[i][1] = pos0[i][1] + speed*moved[i]*(gravity[i][1]- pos0[i][1])/distance[i];
moved[i]++;
}
}
public static void calcDist(int i){
setGravity(i);
distance[i] = (float) Math.sqrt( Math.pow((gravity[i][0]-pos[i][0]),2) + Math.pow((gravity[i][1]-pos[i][1]),2) );
}
public static void setGravity(int i){
// do not forget to set pos0 in both cases
if(direction[i]){
gravity[i][0] = gravityX;
gravity[i][1] = gravityY;
}
else{
// make this biased on radius of sphere
gravity[i][0] = random.nextInt(width);
gravity[i][1] = random.nextInt(height);
}
pos0[i][0] = pos[i][0];
pos0[i][1] = pos[i][1];
moved[i]=0;
}
}
Main Activity.java
package com.abc.mygraphics;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.Window;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.TextView;
import com.abc.mygraphics.MyCanvas;
import org.w3c.dom.Text;
public class MainActivity extends AppCompatActivity {
//DrawingView dr = new DrawingView(this);
public static SharedPreferences sharedPreferences;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int height = displaymetrics.heightPixels;
int width = displaymetrics.widthPixels;
sharedPreferences = getSharedPreferences( getPackageName() + "_preferences", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt("screenX",width);
editor.putInt("screenY", height);
editor.putInt("x", 200);
editor.putInt("y", 200);
editor.commit();
setContentView(new MyCanvas(this));
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// int x = (int)event.getX();
//int y = (int)event.getY();
int x = (int) event.getRawX();
int y = (int) event.getRawY();
//sharedPreferences = getSharedPreferences("CheckSharing",Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt("x", x);
editor.putInt("y", y);
editor.apply();
MyCanvas.changeGravity();
return false;
}
}

Got my problem.
I was trying to call my methods every time a touch event happens, this is something we can't do because when you drag your mouse there are literally thousands(possibly more) touch events happening.
Try understanding from code. In main activity we have our onTouch event listener which calls changeGravity() method which in turn calls calcDist() and setGravity() (from calcDist() ) . So thats a lot of garbage being generated and hence the GC comes in to play, it pauses the application and everything seems like hanged.
Solution - Just place the calcDist() call inside thread, so whatever be the vakue of gravity will come in effect in 10ms. This is something our emulator and phone are capable of, compared to what happens if we call from changeGravity() method.

Related

Android memory leak Custom view

I'm trying to make small App. This App have Activity, Custom View Class, and service.
1) Activity ask service for new Data and redraw Custom view
2) Service is listning to Bluetooth device and parse data.
Everything was fine, but I noticed that App is slowing down after 40 mins working.
I made another project remove service and find that it slowing too! So problem is my Customview class, maybe i have memory leaks in service to... but i have problem with drawings 100%.
I found that i have some objects that i'm creating on onDraw() method.. i try to move all thise staff to onSizeChanged() - but get more lags.
And now i need help. I need some example with simple drawings that depends on device width and height (I think my method is wrong - i use proportions of my 'Design' to calculate demetions in px)
By the way i'm using animator which make animations more smooth))
public class Dynamics {
/**
* Used to compare floats, if the difference is smaller than this, they are
* considered equal
*/
private static final float TOLERANCE = 0.01f;
/** The position the dynamics should to be at */
private float targetPosition;
/** The current position of the dynamics */
private float position;
/** The current velocity of the dynamics */
private float velocity;
/** The time the last update happened */
private long lastTime;
/** The amount of springiness that the dynamics has */
private float springiness;
/** The damping that the dynamics has */
private double damping;
public Dynamics(float springiness, float dampingRatio) {
this.springiness = springiness;
this.damping = dampingRatio * 2 * Math.sqrt(springiness);
}
public void setPosition(float position, long now) {
this.position = position;
lastTime = now;
}
public void setVelocity(float velocity, long now) {
this.velocity = velocity;
lastTime = now;
}
public void setTargetPosition(float targetPosition, long now) {
this.targetPosition = targetPosition;
lastTime = now;
}
public void update(long now) {
float dt = Math.min(now - lastTime, 50) / 1000f;
float x = position - targetPosition;
double acceleration = -springiness * x - damping * velocity;
velocity += acceleration * dt;
position += velocity * dt;
lastTime = now;
}
public boolean isAtRest() {
final boolean standingStill = Math.abs(velocity) < TOLERANCE;
final boolean isAtTarget = (targetPosition - position) < TOLERANCE;
return standingStill && isAtTarget;
}
public float getPosition() {
return position;
}
public float getTargetPos() {
return targetPosition;
}
public float getVelocity() {
return velocity;
}
}
In my Custom view i have this to set new data:
public void SetData(int[] NewData2,float[]newDatapoints)
{
this.NewData=NewData2;
long now = AnimationUtils.currentAnimationTimeMillis();
if (datapoints == null || datapoints.length != newDatapoints.length) {
datapoints = new Dynamics[newDatapoints.length];
for (int i = 0; i < newDatapoints.length; i++) {
datapoints[i] = new Dynamics(70f, 0.50f);
datapoints[i].setPosition(newDatapoints[i], now);
datapoints[i].setTargetPosition(newDatapoints[i], now);
}
invalidate();
} else {
for (int i = 0; i < newDatapoints.length; i++) {
datapoints[i].setTargetPosition(newDatapoints[i], now);
}
removeCallbacks(animator);
post(animator);
}
LastData=NewData;
//redraw();
}
Thise is "code" of my custom view, after all changes it's look terible, so i cut 90% of it. And i make some test code insted:
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ComposeShader;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.animation.AnimationUtils;
import java.io.IOException;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Random;
public class CustomDisplayView extends View {
//paint for drawing custom view
private Paint RectPaint = new Paint();
//Динамические данные float
private Dynamics[] datapoints;
//Динамические статические Int
private int[] NewData = new int[500];
//созадем новый объект квадрат
private RectF rectf= new RectF();
//Задаем массив динамических цветов
int[] CurColors= new int[100];
int[] TargetColors= new int[100];
public CustomDisplayView(Context context, AttributeSet attrs){
super(context, attrs);
//Установка парметров красок
RectPaint.setAntiAlias(true);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (w != 0 && h != 0) {
//create Bitmap here
}
}
/**
* Override the onDraw method to specify custom view appearance using canvas
*/
#Override
protected void onDraw(Canvas canvas) {
//Get Screen size
//int viewWidth=this.getMeasuredWidth();
// int viewHeight = this.getMeasuredHeight();
//Выводим код цвета
RectPaint.setColor(0xff000000);
RectPaint.setTextSize(40);
canvas.restore();
canvas.drawText("V: " + datapoints[1].getPosition(), 20, 60, RectPaint);
//int saveCount = canvas.save();
for(int a=0;a<1000;a++)
{
rectf.set(datapoints[a].getPosition(), datapoints[a + 1].getPosition(), datapoints[a].getPosition() + datapoints[a + 1].getPosition() / 10, datapoints[a + 1].getPosition() + datapoints[a + 1].getPosition() / 10);
RectPaint.setColor(0x88005020);
//RectPaint.setColor(CurColor[a]);
//canvas.rotate(datapoints[1].getPosition(), viewWidth/2, viewHeight/2);
canvas.drawRoundRect(rectf, 0, 0, RectPaint);
//canvas.restore();
}
//canvas.restoreToCount(saveCount);
/*
for(int a=0;a<999;a++)
{
CurColors[a]=progressiveColor(CurColors[a], TargetColors[a], 2);
if(CurColors[a]==TargetColors[a])
{
TargetColors[a]=randomColor();
}
}
*/
canvas.restore();
}
//Рандом колор
public static int randomColor(){
Random random = new Random();
int[] ColorParams= new int[4];
ColorParams[0]=random.nextInt(235)+20;
ColorParams[1]=random.nextInt(255);
ColorParams[2]=random.nextInt(255);
ColorParams[3]=random.nextInt(255);
return Color.argb(ColorParams[0], ColorParams[1], ColorParams[2], ColorParams[3]);
}
//Интерполяция цвета
public static int progressiveColor(int CurColor,int TargetColor,int Step){
//Current color
int[] ColorParams= new int[4];
ColorParams[0]=(CurColor >> 24) & 0xFF;
ColorParams[1]=(CurColor >> 16) & 0xFF;
ColorParams[2]=(CurColor >> 8) & 0xFF;
ColorParams[3]=CurColor & 0xFF;
//TargetColor
int[] TargetColorParams= new int[4];
TargetColorParams[0]=(TargetColor >> 24) & 0xFF;
TargetColorParams[1]=(TargetColor >> 16) & 0xFF;
TargetColorParams[2]=(TargetColor >> 8) & 0xFF;
TargetColorParams[3]=TargetColor & 0xFF;
for(int i=0;i<4;i++)
{
if(ColorParams[i]<TargetColorParams[i])
{
ColorParams[i]+=Step;
if(ColorParams[i]>TargetColorParams[i])
{
ColorParams[i]=TargetColorParams[i];
}
}
else if(ColorParams[i]>TargetColorParams[i])
{
ColorParams[i]-=Step;
if(ColorParams[i]<TargetColorParams[i])
{
ColorParams[i]=TargetColorParams[i];
}
}
}
//int red = r - (int)((float)(r*255)/(float)all);
//int green = (int)((float)(g*255)/(float)all);
return Color.argb(ColorParams[0], ColorParams[1], ColorParams[2], ColorParams[3]);
//return String.format("#%06X", (0xFFFFFF & Color.argb(ColorParams[0], ColorParams[1], ColorParams[2], ColorParams[3])));
//return " "+opacity+" "+red+" "+green+" "+blue;
}
//each custom attribute should have a get and set method
//this allows updating these properties in Java
//we call these in the main Activity class
/**
* Get the current text label color
* #return color as an int
*/
public int getLabelColor(){
return 1;
}
/**
* Set the label color
* #param newColor new color as an int
*/
public void setLabelColor(int newColor){
//update the instance variable
//labelCol=newColor;
//redraw the view
invalidate();
requestLayout();
}
public void redraw(){
//redraw the view
invalidate();
requestLayout();
}
public void SetData(int[] NewData2,float[]newDatapoints)
{
this.NewData=NewData2;
long now = AnimationUtils.currentAnimationTimeMillis();
if (datapoints == null || datapoints.length != newDatapoints.length) {
datapoints = new Dynamics[newDatapoints.length];
for (int i = 0; i < newDatapoints.length; i++) {
datapoints[i] = new Dynamics(70f, 0.50f);
datapoints[i].setPosition(newDatapoints[i], now);
datapoints[i].setTargetPosition(newDatapoints[i], now);
}
invalidate();
} else {
for (int i = 0; i < newDatapoints.length; i++) {
datapoints[i].setTargetPosition(newDatapoints[i], now);
}
removeCallbacks(animator);
post(animator);
}
//redraw();
}
public int GetAction(float x,float y)
{
/*
if(x>(DicsCenterX-LineHalfSpeedZone) && x<(DicsCenterX+LineHalfSpeedZone) && y>(DicsCenterY-PowerOutRadius) && y<(DicsCenterY-SpeedZoneRadius2))
{
// private int SpeedZoneRadius2=0;
// private int PowerOutRadius=0;
//Смена режима
//начинаем смену размеру index / ms
ChangeVal(0,700);
return 1;
}
else if(x>(CofCantBGDrop*2) && x<(CofCantBGDrop*4) && y>(DicsCenterY-PowerOutRadius) && y<(DicsCenterY-SpeedZoneRadius2))
{
return 2;
}
else
{
return 0;
}
//return 0;
*/
return 1;
}
public static String fmt(double d)
{
double val = d/100;
String result;
if(val == (long) val)
result= String.format("%d",(long)d);
else
result= String.format("%s",d);
if(result.length()<2)
{
String result2=result;
result="0"+result2;
}
return result;
}
private Runnable animator = new Runnable() {
#Override
public void run() {
boolean needNewFrame = false;
long now = AnimationUtils.currentAnimationTimeMillis();
for (Dynamics dynamics : datapoints) {
dynamics.update(now);
if (!dynamics.isAtRest()) {
needNewFrame = true;
}
}
if (needNewFrame) {
postDelayed(this, 15);
}
invalidate();
}
};
}
I just want to understand where i need to declare scale values, where i need to calc real dimensions in px.. and et.c. to have no memory leaks..
If i remove color change and incrice number of Rects up to 1000 - i get lags.
All methods o any information how to debug memory leaks - you are wellcome!
You have to remove runnable for animation when view is detached.
if (needNewFrame) {
postDelayed(this, 15); <--- memory leak
}
Try like this.
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
removeCallback(your runnable);
}
Also refreshing every 15 milliseconds is very heavy.

How do I add a scrolling background to Frame-by-Frame Animation?

I have a working frame-by-frame animation inside an Android application.
That's fine - but how would I add a scrolling background to this application, so that the animation run over the background?
I can find plenty of examples for implementing the 2 processes separately - but NOT together.
Any help would be appreciated!
Here's my code for the animation Activity..
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceView;
import android.widget.ImageView;
/**
*
*
*/
public class MyAnimationView extends ImageView
{
private static final String TAG = "AnimationTest:AnimationView";
private Context mContext = null;
private static final int DELAY = 100; //delay between frames in milliseconds
private boolean mIsPlaying = false;
private boolean mStartPlaying = false;
private ArrayList<Bitmap> mBitmapList = new ArrayList<Bitmap>();
private int play_frame = 0;
private long last_tick = 0;
public MyAnimationView(Context context, AttributeSet attrs)
{
super(context, attrs);
mContext = context;
}
#Override
protected void onDraw(Canvas c)
{
Log.d(TAG, "onDraw called");
if (mStartPlaying)
{
Log.d(TAG, "starting animation...");
play_frame = 0;
mStartPlaying = false;
mIsPlaying = true;
postInvalidate();
}
else if (mIsPlaying)
{
if (play_frame >= mBitmapList.size())
{
mIsPlaying = false;
}
else
{
long time = (System.currentTimeMillis() - last_tick);
int draw_x = 0;
int draw_y = 0;
if (time >= DELAY) //the delay time has passed. set next frame
{
last_tick = System.currentTimeMillis();
c.drawBitmap(mBitmapList.get(play_frame), draw_x, draw_y, null);
play_frame++;
postInvalidate();
}
else //still within delay. redraw current frame
{
c.drawBitmap(mBitmapList.get(play_frame), draw_x, draw_y, null);
postInvalidate();
}
}
}
}
/*ideally this should be in a background thread*/
public void loadAnimation(String prefix, int nframes)
{
mBitmapList.clear();
for (int x = 0; x < nframes; x++)
{
String name = prefix + "_" + x;
Log.d(TAG, "loading animation frame: " + name);
int res_id = mContext.getResources().getIdentifier(name, "drawable", mContext.getPackageName());
BitmapDrawable d = (BitmapDrawable) mContext.getResources().getDrawable(res_id);
mBitmapList.add(d.getBitmap());
}
}
public void playAnimation()
{
mStartPlaying = true;
postInvalidate();
}
}
"draw_x" and "draw_y" are the variables for your bitmap position. If you change this two variables (or just one of them), you can move (scroll) your picture over the screen.

One class cannot extend two classes

Hey :) I have a code of a ball that using the motion sensor and I want to make my app count time and when you lose, save this time for a record, so I did it, but my problem is, I can't extend my fragment layout, here is my full code:
package com.example.theball;
import java.util.Timer;
import java.util.TimerTask;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
#SuppressLint("NewApi") public class MainActivity extends Activity implements SensorEventListener {
private SensorManager sensorManager;
private Sensor accelerometer;
#SuppressWarnings("unused")
private long lastUpdate;
AnimatedView animatedView = null;
ShapeDrawable mDrawable = new ShapeDrawable();
public static int x;
public static int y;
public static final int width = 50;
public static final int height = 50;
public boolean firstDraw = true;
private int screen_width;
private int screen_height;
private int sensorX;
private Timer t;
private int TimeCounter = 0;
private int sensorY;
private static int score = 0;
private static SharedPreferences prefs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer = sensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
lastUpdate = System.currentTimeMillis();
animatedView = new AnimatedView(this);
setContentView(animatedView);
t=new Timer();
t.scheduleAtFixedRate(new TimerTask() {
public void run() {
runOnUiThread(new Runnable() {
public void run() {
TimeCounter++;
}
});
}
}, 0, 1000);
}
public static class MainFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.activity_main, container, false);
TextView highscore_int = (TextView)v.findViewById(R.id.highscore_int );
score = prefs.getInt("key", 0);
highscore_int.setText("Highscore:" + score +" seconds.");
return v;
}
}
#Override
protected void onResume() {
super.onResume();
sensorManager.registerListener(this, accelerometer,
SensorManager.SENSOR_DELAY_GAME);
}
#Override
protected void onPause() {
super.onPause();
sensorManager.unregisterListener(this);
}
#Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
sensorY = (int) event.values[1];
sensorX = (int) event.values[0];
x -= sensorX*3;
y += sensorY*3;
if(x <= 0 || x >= screen_width || y <= 0 || y >= screen_height) {
SharedPreferences prefs = this.getSharedPreferences("myPrefsKey", Context.MODE_PRIVATE);
int oldScore = prefs.getInt("key", 0);
if( TimeCounter > oldScore ){
Editor edit = prefs.edit();
edit.putInt("key", TimeCounter);
edit.commit(); }
Intent myIntent = new Intent(this, YouLost.class);
startActivity(myIntent);
}
}
}
public class AnimatedView extends ImageView {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
static final int width = 50;
static final int height = 50;
#SuppressLint("NewApi")
public AnimatedView(Context context) {
super(context);
// TODO Auto-generated constructor stub
display.getSize(size);
screen_width = size.x;
screen_height = size.y;
mDrawable = new ShapeDrawable(new OvalShape());
mDrawable.getPaint().setColor(0xffffAC23);
mDrawable.setBounds(0, 0, screen_width, screen_height);
}
#Override
protected void onDraw(Canvas canvas) {
mDrawable.setBounds(x, y, x + width, y + height);
if(firstDraw) {
x = screen_width / 2;
y = screen_height / 2;
firstDraw = false;
}
mDrawable.draw(canvas);
invalidate();
}
}
}
XML FILE:
<LinearLayout 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:orientation="vertical" >
<TextView
android:id="#+id/highscore_int"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="0dp"
android:layout_marginTop="0dp"
android:layout_weight="0.14"
android:text="12312312"
android:textColor="#android:color/black"
android:textSize="40sp" />
</LinearLayout>
I can't see the highscore_int on my device, only at the eclipse xml file grahpic layout.
You have defined MainActivity twice. Rename the second one to e.g. MainFragment (or something else) and you should be fine.
But I would also recommend to move the Fragment to a different file as well.

Adding drawable image to background of canvas

I know its possible to paint the background of canvas using
mPaint = new Paint();
mPaint.setColor(Color.RED);
Im just wondering how to i set a permanent background for it. Ive tried using the xml file but nothing happens. Any ideas?
This is the source code of the project, ive been following a tutorial how to do it because im fairly unfamiliar with bitmaps.
Canvas Class
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
public class GameBoard extends View{
private int mFlagX = -1;
private int mFlagY = -1;
private Bitmap mBitmap = null;
private Bitmap nBitmap = null;
private Paint mPaint = null;
private boolean isFlagHidden = false;
private int mBoundX = -1;
private int mBoundY = -1;
//play with these values to make the app more or less challenging
public final int CLOSER = 50;
public final int CLOSE = 100;
public GameBoard(Context context, AttributeSet aSet) {
super(context, aSet);
//load our bitmap
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.star);
//create a paint brush
mPaint = new Paint();
mPaint.setColor(Color.RED);
}
#Override
public void onDraw(Canvas canvas) {
//initialize
if ((mFlagX < 1) || (mFlagY < 1)) {
mFlagX = (int) (getWidth() / 2) - mBitmap.getWidth() / 2;
mFlagY = (int) (getHeight() / 2) - mBitmap.getHeight() / 2;
mBoundX = (int)getWidth() - mBitmap.getWidth();
mBoundY = (int)getHeight() - mBitmap.getHeight();
}
//draw background
canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
//draw the flag
if (!isFlagHidden) {
canvas.drawBitmap(mBitmap, mFlagX, mFlagY, null);
}
}
public void hideTheFlag(){
//randomize flag location
mFlagX = (int) Math.ceil(Math.random() * mBoundX);
mFlagY = (int) Math.ceil(Math.random() * mBoundY);
isFlagHidden = true;
//force redraw
invalidate();
}
public void giveUp(){
isFlagHidden = false;
//force redraw
invalidate();
}
public Indicators takeAGuess(float x, float y) {
//this is our "warm" area
Rect prettyClose = new Rect(mFlagX - CLOSE, mFlagY - CLOSE, mFlagX+mBitmap.getWidth() + CLOSE, mFlagY+mBitmap.getHeight() + CLOSE);
//normalize
if (prettyClose.left < 0) prettyClose.left = 0;
if (prettyClose.top < 0) prettyClose.top = 0;
if (prettyClose.right > mBoundX) prettyClose.right = mBoundX;
if (prettyClose.bottom > mBoundY) prettyClose.bottom = mBoundY;
//this is our "hot" area
Rect reallyClose = new Rect(mFlagX - CLOSER, mFlagY - CLOSER, mFlagX+mBitmap.getWidth() + CLOSER, mFlagY+mBitmap.getHeight() + CLOSER);
//normalize
if (reallyClose.left < 0) reallyClose.left = 0;
if (reallyClose.top < 0) reallyClose.top = 0;
if (reallyClose.right > mBoundX) reallyClose.right = mBoundX;
if (reallyClose.bottom > mBoundY) reallyClose.bottom = mBoundY;
//this is the area that contains our flag
Rect bullsEye = new Rect(mFlagX, mFlagY, mFlagX+mBitmap.getWidth(), mFlagY+mBitmap.getHeight());
//check to see where on the board the user pressed
if (bullsEye.contains((int) x, (int)y)) {
//found it
isFlagHidden = false;
invalidate();
return Indicators.BULLSEYE;
} else if (reallyClose.contains((int) x, (int)y)) {
//hot
return Indicators.HOT;
} else if (prettyClose.contains((int)x, (int)y)) {
//warm
return Indicators.WARM;
} else {
//not even close
return Indicators.COLD;
}
}
}
Game Class
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.TextView;
public class FindTheStar extends Activity implements OnTouchListener, OnClickListener{
private GameBoard mGameBoard = null;
private boolean isFlagHidden = false;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_star);
mGameBoard = (GameBoard) findViewById(R.id.Hide_canvas);
mGameBoard.setOnTouchListener(this);
Button b = (Button) findViewById(R.id.the_button);
b.setOnClickListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (v.getId() == R.id.Hide_canvas) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (isFlagHidden) {
TextView tv = (TextView)findViewById (R.id.the_label);
switch (mGameBoard.takeAGuess(event.getX(), event.getY())) {
case BULLSEYE:
Button b = (Button) findViewById(R.id.the_button);
isFlagHidden = false;
b.setText("Go Hide!");
tv.setText("You found me!");
tv.setTextColor(Color.GREEN);
break;
case HOT:
tv.setText("You're hot!");
tv.setTextColor(Color.RED);
break;
case WARM:
tv.setText("Getting warm...");
tv.setTextColor(Color.YELLOW);
break;
case COLD:
tv.setText("You're cold.");
tv.setTextColor(Color.BLUE);
break;
}
}
}
return true;
}
return false;
}
#Override
public void onClick(View v) {
if (v.getId() == R.id.the_button) {
TextView tv = (TextView)findViewById (R.id.the_label);
tv.setText("");
Button b = (Button) findViewById(R.id.the_button);
isFlagHidden = !isFlagHidden;
if (isFlagHidden) {
b.setText("Can't find me?");
mGameBoard.hideTheFlag();
} else {
b.setText("Go Hide!");
mGameBoard.giveUp();
}
}
}
}
XML File
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="#+id/the_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:textSize="20sp"
android:layout_marginBottom="10dip"
android:text="Lets Play Hide and Seek!"/>
<Button
android:id="#+id/the_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:layout_marginBottom="10dip"
android:text="Go Hide!"/>
<app.autismapp.GameBoard
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/Hide_canvas"/>
</LinearLayout>
yes you can set your permanent background using xml layout..i done this by creating two class.
this is my code in MainACtivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final BrushView view=new BrushView(this);
setContentView(R.layout.mylayout);//removed this one if the paint doesnt work
view.setBackgroundResource(R.drawable.background);//to set background
setContentView(view);// to display the background
and my second class
public class PaintView extends View {
private Paint paint = new Paint();
public LayoutParams params;
public PaintView(Context context) {
super(context);
paint.setAntiAlias(true);
paint.setColor(Color.BLUE);
i hope it gives you an idea

Manipulating variables in an activity with a method in another class

I am working on a game and have run into some issues. My architecture is something like this:
class GameView is used to draw bitmaps on my surfaces
class GameLoopThread is used to implement my game loop (if it wasn't obvious...)
class MovementUtils is used to hold all of my utilities related to moving objects
I want to house methods like gravity and movement controls in MovementUtils, but I'm having trouble actually updating the values in GameView. I tried using an intent, to no avail. I'll post my code, and maybe someone can show me what I should do. Also, ignore the Accelerometer lines, that's another problem entirely...
GameView.java
package com.example.connorgame;
import java.util.EventObject;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
public class GameView extends SurfaceView {
private Bitmap platform;
private Bitmap character;
private Bitmap background;
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private MainActivity mainactivity;
private MovementUtils moveutil;
public float charX = 0;
public float charY = 0;
private boolean isFalling = true;
private boolean isJumping = false;
private float initialJumpY = 0;
private int initialFrame;
private int currentFrame;
private int frameDifference;
public GameView(Context context) {
super(context);
gameLoopThread = new GameLoopThread(this);
mainactivity = (MainActivity) context;
moveutil = new MovementUtils();
holder = getHolder();
holder.addCallback(new Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
});
platform = BitmapFactory.decodeResource(getResources(), R.drawable.platform);
character = BitmapFactory.decodeResource(getResources(), R.drawable.character);
background = BitmapFactory.decodeResource(getResources(), R.drawable.background);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(background, 0, 0, null);
canvas.drawBitmap(platform, 30, 700, null);
canvas.drawBitmap(character, charX, charY, null);
moveutil.gravity(charY, isFalling);
if (charY > getHeight() - character.getHeight()) {
initialFrame = gameLoopThread.numFrames;
initialJumpY = charY;
isFalling = false;
isJumping = true;
}
if (isJumping == true && isFalling == false) {
currentFrame = gameLoopThread.numFrames;
frameDifference = (currentFrame - initialFrame);
charY = charY - 5;
if (charY == initialJumpY - 100) {
isJumping = false;
isFalling = true;
}
}
}
}
MovementUtils.java
package com.example.connorgame;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
public class MovementUtils {
public void gravity (float charY, boolean isFalling) {
if(isFalling == true){
charY = charY + 5;
}
}
}
If I understand what you're doing correctly, you're trying to have charY in the GameView class modified by the gravity function. The issue is that float is a primitive, so it is based by value and only the local copy will be modified. If you passed an object instead, the object would be modified.
One solution is probably to just return the new Y position instead of trying to make gravity() change the Y position.
Another solution is to pass the GameView to MovementUtils and let MovementUtils modify it.
In other words, you would pass the GameView like this new MovementUtils(this);
And the gravity function would call a void setCharY(int y); in GameView.
public class MovementUtils {
private GameView gameView;
public MovementUtils(GameView view) {
this.gameView = view;
}
public void gravity (float charY, boolean isFalling) {
if(isFalling == true){
charY = charY + 5;
gameView.setCharY(charY);
}
}
}
Java only supports passing by value
So when you call moveutil.gravity(charY, isFalling);
and change it within the function, e.g.
public void gravity (float charY, boolean isFalling) {
if(isFalling == true){
charY = charY + 5;
}
Such change only occur in the local copy of the variable charY and does not affect the instance variable charY defined in your GameView class
To solve this, you can define your variables as objects as well as the argument to your functions, e.g.
public void gravity (Float charY, boolean isFalling) {}
And in your GameView class:
private Float charX = 0; // why you define them public !?
private Float charY = 0;
Alternatively, you can pass an instance of your GameView class or create a ValueObject class (similar to Context object in android) and use it to pass arguments

Categories

Resources