I'm learning android and java and am trying to learn how to make a live wallpaper
I am using the aquarium tutorial, I put it all in one file instead of spreading it but what I am trying to do is get one scale number for everything, I want to get the height of the screen divide that by the background image height (which will always be bigger), this should give me a ratio to use for scaling everything, I tried this in a surfaceView code and it worked perfect, I tried it in livewallpaper and nada.
In the surfaceView test I use onSizeChange and got the height that way and it worked no problems.
This is what I did for the livewallpaper one
This is what I put for the onSurfaceChange
public int screenWidth;
public float rescaler;
public float totalHeight = theTemplate._backgroundImage.getHeight();
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//add rescale and width
screenWidth = width;
rescaler = (float) (height / totalHeight);
super.onSurfaceChanged(holder, format, width, height);
}
The background image comes from an inner class named TheTemplate
This is what I did there
The variables
private SpriteAnimationActivityEngine theTest;
private Bitmap theBackgroundImage;
private float theScaler = theTest.rescaler;
then I try and rescale it using theScaler
public void initialize(Context context, SurfaceHolder surfaceHolder) {
this.spriteThread = new SpriteThread(this);
this._surfaceHolder = surfaceHolder;
this._sprites = new ArrayList<Renderable>();
this._context = context;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
this._backgroundImage = BitmapFactory.decodeResource(context.getResources(),ca.samsstuff.testonepagewallpaper.R.drawable.sky, options);
this.theBackgroundImage = Bitmap.createScaledBitmap(_backgroundImage, (int) (theScaler * _backgroundImage.getWidth()), (int) (theScaler * _backgroundImage.getHeight()), true);
this.addSprites();
}
Then it passes it to draw the background
private void renderBackGround(Canvas canvas) {
canvas.drawBitmap(this.theBackgroundImage, 0, 0, null);
}
Which sends it to draw
protected void onDraw(Canvas canvas) {
this.renderBackGround(canvas);
for (Renderable renderable : this._sprites) {
renderable.render(canvas);
}
}
I keep getting errors and don't know what I am doing wrong. Like I said I am learning both android and java but this method worked in another test I did but I got the screen height from onSizeChange can I get the height by using onSurfaceChange?
Any help would be appreciated
Thanks in advance
sam
EDIT
I also tried to rescale within the theTemplate class just to see if it would work having everything within its own class and still having issues, I used the DisplayMetrics to get the screen height this time.
This might work if I can get it going properly.
Here is this attempt
public class TheTemplate {
private SpriteThread spriteThread;
private SurfaceHolder _surfaceHolder;
private ArrayList<Renderable> _sprites;
public Bitmap _backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.sky);;
private Context _context;
// add rescale stuff
private Bitmap theBackgroundImage;
private float theScaler = initFrameParams() / _backgroundImage.getHeight();
private Bitmap oneBackImage = Bitmap.createScaledBitmap(_backgroundImage, (int) (theScaler * _backgroundImage.getWidth()), (int) (theScaler * _backgroundImage.getHeight()), true);
int initFrameParams()
{
//get the screen height to use to rescale everything
DisplayMetrics metrics = new DisplayMetrics();
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
display.getMetrics(metrics);
int screenHeight = display.getHeight();
return screenHeight;
}
public void render(){
Canvas canvas = null;
try{
canvas = this._surfaceHolder.lockCanvas(null);
synchronized (this._surfaceHolder) {
this.onDraw(canvas);
}
}finally{
if(canvas != null){
this._surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
protected void onDraw(Canvas canvas) {
this.renderBackGround(canvas);
for (Renderable renderable : this._sprites) {
renderable.render(canvas);
}
};
public void start(){
this.spriteThread.switchOn();
}
public void stop(){
boolean retry = true;
this.spriteThread.switchOff();
while (retry) {
try {
this.spriteThread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
public int getLeft() {
return 0;
}
public int getRight() {
return this.theBackgroundImage.getWidth();
}
public void initialize(Context context, SurfaceHolder surfaceHolder) {
this.spriteThread = new SpriteThread(this);
this._surfaceHolder = surfaceHolder;
this._sprites = new ArrayList<Renderable>();
this._context = context;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
this.theBackgroundImage = oneBackImage;
this.addSprites();
}
private void addSprites() {
Point startPoint = new Point(100, 100);
this._sprites.add(new SpriteOne(this._context, this, startPoint, 90));
Point startPoint1 = new Point(100, 300);
this._sprites.add(new SpriteOne(this._context, this, startPoint1, 50));
Point startPoint2 = new Point(200, 200);
this._sprites.add(new SpriteOne(this._context, this, startPoint2, 15));
}
private void renderBackGround(Canvas canvas)
{
canvas.drawBitmap(this.theBackgroundImage, 0, 0, null);
}
}
As I stated before any help would be appreciated.
Thanks again in advance
Sam
Edit SOLVED Here is an answer I came up with, The rescale code is where the comments are
Hope this helps someone out.
public class TheTemplate {
private SpriteThread spriteThread;
private SurfaceHolder _surfaceHolder;
private ArrayList<Renderable> _sprites;
public Bitmap _backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.sky);;
private Context _context;
// add rescale stuff
//private SpriteAnimationActivityEngine theTest;
private Bitmap theBackgroundImage;
private float totalHeight = _backgroundImage.getHeight();
private int screenSized = initFrameParams();
private float theScaler = (float) (screenSized / totalHeight);
private Bitmap oneBackImage = Bitmap.createScaledBitmap(_backgroundImage, (int) (theScaler * _backgroundImage.getWidth()), (int) (theScaler * _backgroundImage.getHeight()), true);
int initFrameParams()
{
DisplayMetrics metrics = new DisplayMetrics();
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
display.getMetrics(metrics);
int screenHeight = display.getHeight();
return screenHeight;
}
public void render(){
Canvas canvas = null;
try{
canvas = this._surfaceHolder.lockCanvas(null);
synchronized (this._surfaceHolder) {
this.onDraw(canvas);
}
}finally{
if(canvas != null){
this._surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
protected void onDraw(Canvas canvas) {
this.renderBackGround(canvas);
for (Renderable renderable : this._sprites) {
renderable.render(canvas);
}
};
public void start(){
this.spriteThread.switchOn();
}
public void stop(){
boolean retry = true;
this.spriteThread.switchOff();
while (retry) {
try {
this.spriteThread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
public int getLeft() {
return 0;
}
public int getRight() {
return this.theBackgroundImage.getWidth();
}
public void initialize(Context context, SurfaceHolder surfaceHolder) {
this.spriteThread = new SpriteThread(this);
this._surfaceHolder = surfaceHolder;
this._sprites = new ArrayList<Renderable>();
this._context = context;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
this.theBackgroundImage = oneBackImage;
this.addSprites();
}
private void addSprites() {
Point startPoint = new Point(100, 100);
this._sprites.add(new SpriteOne(this._context, this, startPoint, 90));
Point startPoint1 = new Point(100, 300);
this._sprites.add(new SpriteOne(this._context, this, startPoint1, 50));
Point startPoint2 = new Point(200, 200);
this._sprites.add(new SpriteOne(this._context, this, startPoint2, 15));
}
private void renderBackGround(Canvas canvas)
{
canvas.drawBitmap(this.theBackgroundImage, 0, 0, null);
}
}
I added the answer to the original post, hope this helps someone.
Sam
Sorry about that folks, new to this method of using a forum
Here is the answer, I added comments in the code where I made the changes for scaling images.
This method can also be used for positioning also.
Here is the answer.
public class TheTemplate {
private SpriteThread spriteThread;
private SurfaceHolder _surfaceHolder;
private ArrayList<Renderable> _sprites;
public Bitmap _backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.sky);;
private Context _context;
// add rescale stuff
//private SpriteAnimationActivityEngine theTest;
private Bitmap theBackgroundImage;
private float totalHeight = _backgroundImage.getHeight();
private int screenSized = initFrameParams();
private float theScaler = (float) (screenSized / totalHeight);
private Bitmap oneBackImage = Bitmap.createScaledBitmap(_backgroundImage, (int) (theScaler * _backgroundImage.getWidth()), (int) (theScaler * _backgroundImage.getHeight()), true);
int initFrameParams()
{
DisplayMetrics metrics = new DisplayMetrics();
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
display.getMetrics(metrics);
int screenHeight = display.getHeight();
return screenHeight;
}
public void render(){
Canvas canvas = null;
try{
canvas = this._surfaceHolder.lockCanvas(null);
synchronized (this._surfaceHolder) {
this.onDraw(canvas);
}
}finally{
if(canvas != null){
this._surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
protected void onDraw(Canvas canvas) {
this.renderBackGround(canvas);
for (Renderable renderable : this._sprites) {
renderable.render(canvas);
}
};
public void start(){
this.spriteThread.switchOn();
}
public void stop(){
boolean retry = true;
this.spriteThread.switchOff();
while (retry) {
try {
this.spriteThread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
public int getLeft() {
return 0;
}
public int getRight() {
return this.theBackgroundImage.getWidth();
}
public void initialize(Context context, SurfaceHolder surfaceHolder) {
this.spriteThread = new SpriteThread(this);
this._surfaceHolder = surfaceHolder;
this._sprites = new ArrayList<Renderable>();
this._context = context;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
this.theBackgroundImage = oneBackImage;
this.addSprites();
}
private void addSprites() {
Point startPoint = new Point(100, 100);
this._sprites.add(new SpriteOne(this._context, this, startPoint, 90));
Point startPoint1 = new Point(100, 300);
this._sprites.add(new SpriteOne(this._context, this, startPoint1, 50));
Point startPoint2 = new Point(200, 200);
this._sprites.add(new SpriteOne(this._context, this, startPoint2, 15));
}
private void renderBackGround(Canvas canvas)
{
canvas.drawBitmap(this.theBackgroundImage, 0, 0, null);
}
}
Related
I am trying to set a sprite image as a background
and I didn't success to set the image size to screen size.
I'm trying this:
public class Game extends SurfaceView implements Runnable {
private SurfaceHolder holder;
private boolean isRunning = false;
private Thread gameThread;
private Sprite s;
private int screenWidth;
private int screenHeight;
Canvas canvas;
// private Sprite[] sprites;
private final static int MAX_FPS = 40; //desired fps
private final static int FRAME_PERIOD = 1000 / MAX_FPS; // the frame period
public Game(Context context) {
super(context);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
screenWidth = width;
screenHeight = height;
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
//====== not working
// Display display = ((Activity)context).getWindowManager().getDefaultDisplay();
// int sWidth = display.getWidth();
// int sHeight = display.getHeight();
//====== not working
// DisplayMetrics dm = new DisplayMetrics();
// ((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(dm);
// int sWidth = dm.widthPixels;
// int sHeight = dm.heightPixels;
//====== not working
// screenHeight=canvas.getHeight();
// screenWidth=canvas.getWidth();
s=new Sprite(0, 0, BitmapFactory.decodeResource(this.getResources(), R.mipmap.back));
}
/**
* Start or resume the game.
*/
public void resume() {
isRunning = true;
gameThread = new Thread(this);
gameThread.start();
}
/**
* Pause the game loop
*/
public void pause() {
isRunning = false;
boolean retry = true;
while (retry) {
try {
gameThread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
class Sprite {
int x;
int y;
int directionX = 1;
int directionY = 1;
int speed = 10;
int color = 0;
Bitmap image;
public Sprite(int x, int y) {
this.x = x;
this.y = y;
}
public Sprite(int x, int y, Bitmap image) {
this(x, y);
this.image = image;
}
public Sprite(int x, int y, Bitmap image, int color) {
this(x, y, image);
this.color = color;
}
}
protected void step()
{
//blablabla
}
protected void render(Canvas canvas) {
canvas.drawColor(Color.BLACK);
Paint p = new Paint();
canvas.drawBitmap(s.image,s.x,s.y,p);
}
#Override
public void run() {
while(isRunning) {
// We need to make sure that the surface is ready
if (! holder.getSurface().isValid()) {
continue;
}
long started = System.currentTimeMillis();
// update
step();
// draw
canvas = holder.lockCanvas();
if (canvas != null) {
render(canvas);
holder.unlockCanvasAndPost(canvas);
}
float deltaTime = (System.currentTimeMillis() - started);
int sleepTime = (int) (FRAME_PERIOD - deltaTime);
if (sleepTime > 0) {
try {
gameThread.sleep(sleepTime);
}
catch (InterruptedException e) {
}
}
while (sleepTime < 0) {
step();
sleepTime += FRAME_PERIOD;
}
}
}
}
This options doesn't work:
//====== not working
// Display display = ((Activity)context).getWindowManager().getDefaultDisplay();
// int sWidth = display.getWidth();
// int sHeight = display.getHeight();
//====== not working
// DisplayMetrics dm = new DisplayMetrics();
// ((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(dm);
// int sWidth = dm.widthPixels;
// int sHeight = dm.heightPixels;
//====== not working
// screenHeight=canvas.getHeight();
// screenWidth=canvas.getWidth();
So how I can get the canvas or current screen size?
And set the Sprite.image to full screen ?
Try this for size in pixels,
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Try this when you decode your bitmap.
final int width = context.getResources().getDisplayMetrics().widthPixels;
final int height = context.getResources().getDisplayMetrics().heightPixels;
BitmapFactory.Options options = new BitmapFactory.Options();
options.outHeight = height;
options.outWidth = width;
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher, options)
I am trying to use 15 to 20 images to show on livewallpaper background one by one on a fix time ,but I am facing grow heap problem (Grow heap (frag case) to 8.987MB for 6220816-byte allocation) I have search everything but couldn't get through this
Any help pleas.
here is my code
public class LiveWallpaperService extends WallpaperService {
private float x;
private int y;
private int angle;
private int speed;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public Engine onCreateEngine() {
stopSelf();
return new MyWallpaperEngine();
}
class MyWallpaperEngine extends Engine {
private final Handler handle = new Handler();
private final Runnable drawRunner = new Runnable() {
#Override
public void run() {
draw();
}
};
private Boolean visble = true;
public Bitmap mBackgroundImage;
public String name;
int[] mImagesArray;
private int mImagesArrayIndex = 0;
MyWallpaperEngine() {
mImagesArray = new int[] { R.drawable.love_1_mini,
R.drawable.love_2_mini, R.drawable.love_3_mini,
R.drawable.love_4_mini, R.drawable.love_5_mini,
R.drawable.love_6_mini, R.drawable.love_7_mini,
R.drawable.love_8_mini, R.drawable.love_9_mini,
R.drawable.love_10_mini,
R.drawable.love_11_mini, R.drawable.love_12_mini,
R.drawable.love_13_mini, R.drawable.love_14_mini,
R.drawable.love_15_mini, R.drawable.love_16_mini,
R.drawable.love_17_mini, R.drawable.love_18_mini,
R.drawable.love_19_mini, R.drawable.love_20_mini };
if (mImagesArrayIndex == 0) {
x = -330; // initialize x position
y = 0; // initialize y position
} else {
x = -330; // initialize x position
y = 0; // initialize y position
}
}
#Override
public Bundle onCommand(String action, int x, int y, int z,
Bundle extras, boolean resultRequested) {
return super.onCommand(action, x, y, z, extras, resultRequested);
}
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
}
#Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xOffsetStep, float yOffsetStep, int xPixelOffset,
int yPixelOffset) {
draw();
}
#Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
this.visble = false;
}
#Override
public void onTouchEvent(MotionEvent event) {
}
#Override
public void onVisibilityChanged(boolean visible) {
this.visble = visible;
if (visible) {
handle.post(drawRunner);
} else {
handle.removeCallbacks(drawRunner);
}
super.onVisibilityChanged(visible);
}
private void incrementCounter() {
mImagesArrayIndex++;
if (mImagesArrayIndex >= mImagesArray.length) {
mImagesArrayIndex = 0;
}
}
#SuppressWarnings("deprecation")
void draw() {
int count = mImagesArray[mImagesArrayIndex];
final SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
int scale = 2;
Resources res = getResources();
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inPreferredConfig = Bitmap.Config.RGB_565;
o2.inSampleSize = scale;
o2.inPurgeable = true;
o2.inInputShareable = true;
Bitmap image = BitmapFactory.decodeResource(res, count, o2);
Calendar mCalendar = Calendar.getInstance();
int h = mCalendar.get(Calendar.HOUR);
int m = mCalendar.get(Calendar.MINUTE);
int s = mCalendar.get(Calendar.SECOND);
if (s == 10) {
mImagesArrayIndex = 0;
}
try {
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);
c = holder.lockCanvas();
c.drawColor(Color.RED);
if (c != null) {
int a = 0;
int counting = 0;
if (counting == a) {
a++;
counting++;
c.drawBitmap(image, x, y, paint);
int widthhhh = c.getWidth();
x = (float) (x + 10.10);
if (x > widthhhh + 400) {
image.recycle();
image = null;
incrementCounter();
}
}
paint.setColor(Color.RED);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} finally {
try {
if (c != null) {
holder.unlockCanvasAndPost(c);
}
handle.removeCallbacks(drawRunner);
if (visble) {
handle.postDelayed(drawRunner, 10);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
}
}
Bitmap image = BitmapFactory.decodeResource(getResources(), mImagesArray[mImagesArrayIndex]);
When your done with it call image.recycle() (see javadoc).
In your draw() method, you have this code:
Bitmap image = BitmapFactory.decodeResource(getResources(),
mImagesArray[mImagesArrayIndex]);
int count = mImagesArray[mImagesArrayIndex];
final SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
int scale = 4;
Resources res = getResources();
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inPreferredConfig = Bitmap.Config.RGB_565;
o2.inSampleSize = scale;
o2.inPurgeable = true;
o2.inInputShareable = true;
image = BitmapFactory.decodeResource(res, count, o2);
Notice the first line calls BitmapFactory.decodeResource() and assigns the result to variable image and then later, the last line again calls BitmapFactory.decodeResource() and assigns the result to variable image. You never called recycle() on the first decoded image, so this is giving you a memory leak.
I'm new in Android Programming I'm Trying to make slideshow animated live wallpaper and all ok but the problem is when I set the wallpaper the scale of image is stretched to screen I want it to scale to all the phone screens and when swipe the wallpaper get the right part of image I Want Advice about this problem.
my code is :
public class CustomWallpaper extends WallpaperService {
#Override
public Engine onCreateEngine() {
return new WallpaperEngine();
}
class WallpaperEngine extends Engine {
//Duration between slides in milliseconds
private final int SLIDE_DURATION = 8;
private int[] mImagesArray;
private int mImagesArrayIndex = 0;
private Thread mDrawWallpaper;
private String mImageScale = "Fit to screen";
private CustomWallpaperHelper customWallpaperHelper;
public WallpaperEngine() {
customWallpaperHelper = new CustomWallpaperHelper(getApplicationContext(), getResources());
mImagesArray = new int[] {R.drawable.image_1,R.drawable.image_2,R.drawable.image_3,R.drawable.image_4,R.drawable.image_5,R.drawable.image_6,R.drawable.image_7,R.drawable.image_8,R.drawable.image_9,R.drawable.image_10,R.drawable.image_11,R.drawable.image_12,R.drawable.image_13,R.drawable.image_14,R.drawable.image_15,R.drawable.image_16,R.drawable.image_17,R.drawable.image_18,R.drawable.image_19,R.drawable.image_20,R.drawable.image_21,R.drawable.image_22,R.drawable.image_23,R.drawable.image_24,R.drawable.image_25,R.drawable.image_26,R.drawable.image_27,R.drawable.image_28,R.drawable.image_29,R.drawable.image_30,R.drawable.image_31,R.drawable.image_32,R.drawable.image_33,R.drawable.image_34,R.drawable.image_35,R.drawable.image_36,R.drawable.image_37,R.drawable.image_38,R.drawable.image_39,R.drawable.image_40,R.drawable.image_41};
mDrawWallpaper = new Thread(new Runnable() {
#Override
public void run() {
try {
while (true) {
drawFrame();
incrementCounter();
Thread.sleep(SLIDE_DURATION);
}
} catch (Exception e) {
//
}
}
});
mDrawWallpaper.start();
}
private void incrementCounter() {
mImagesArrayIndex++;
if (mImagesArrayIndex >= mImagesArray.length) {
mImagesArrayIndex = 0;
}
}
private void drawFrame() {
final SurfaceHolder holder = getSurfaceHolder();
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
if (canvas != null) {
drawImage(canvas);
}
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
private void drawImage(Canvas canvas) {
//Get the image and resize it
Bitmap image = BitmapFactory.decodeResource(getResources(),
mImagesArray[mImagesArrayIndex]);
//Draw background
customWallpaperHelper.setBackground(canvas);
//Scale the canvas
PointF mScale = customWallpaperHelper.getCanvasScale(mImageScale, image.getWidth(), image.getHeight());
canvas.scale(mScale.x, mScale.y);
//Draw the image on screen
Point mPos = customWallpaperHelper.getImagePos(mScale, image.getWidth(), image.getHeight());
canvas.drawBitmap(image, mPos.x, mPos.y, null);
}
}
}
and the other class is:
public class CustomWallpaperHelper {
public final static String IMAGE_SCALE_STRETCH_TO_SCREEN = "Stretch to screen";
public final static String IMAGE_SCALE_FIT_TO_SCREEN = "Fit to screen";
private Context mContext;
private Resources mResources;
private Point screenSize = new Point();
private Bitmap bgImageScaled;
private Point bgImagePos = new Point(0, 0);
public CustomWallpaperHelper(Context mContext, Resources mResources) {
this.mContext = mContext;
this.mResources = mResources;
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
screenSize.x = display.getWidth();
screenSize.y = display.getHeight();
;
}
private void scaleBackground() {
String imageScale = "Stretch to screen";
Bitmap bgImage = null;
if (imageScale.equals(IMAGE_SCALE_STRETCH_TO_SCREEN)) {
bgImagePos = new Point(0, 0);
bgImageScaled = Bitmap.createScaledBitmap(bgImage, screenSize.x, screenSize.y, true);
}
}
public void setBackground(Canvas canvas) {
if (bgImageScaled != null) {
canvas.drawBitmap(bgImageScaled, bgImagePos.x, bgImagePos.y, null);
} else {
canvas.drawColor(0xff000000);
}
}
public int getScreenWidth() {
return screenSize.x;
}
public int getScreenHeight() {
return screenSize.y;
}
public Point getImagePos(PointF canvasScale, int imageWidth, int imageHeight) {
Point imagePos = new Point();
imagePos.x = (int) (screenSize.x - (imageWidth * canvasScale.x)) / 2;
imagePos.y = (int) (screenSize.y - (imageHeight * canvasScale.y)) / 2;
return imagePos;
}
public PointF getCanvasScale(String imageScale, int imageWidth, int imageHeight) {
PointF canvasScale = new PointF(1f, 1f);
if (imageScale.equals(IMAGE_SCALE_STRETCH_TO_SCREEN)) {
canvasScale.x = getScreenWidth() / (1f * imageWidth);
canvasScale.y = getScreenHeight() / (1f * imageHeight);
} else {
boolean tooWide = false;
boolean tooTall = false;
if (getScreenWidth() < imageWidth) {
tooWide = true;
}
if (getScreenHeight() < imageHeight) {
tooTall = true;
}
if (tooWide && tooTall) {
int x = imageWidth / getScreenWidth();
int y = imageHeight / getScreenHeight();
if (x > y) {
canvasScale.x = getScreenWidth() / (1f * imageWidth);
canvasScale.y = 1;
} else {
canvasScale.x = 1;
canvasScale.y = getScreenHeight() / (1f * imageHeight);
}
} else if (tooWide) {
canvasScale.x = getScreenWidth() / (1f * imageWidth);
canvasScale.y = 1;
} else if (tooTall) {
canvasScale.x = 1;
canvasScale.y = getScreenHeight() / (1f * imageHeight);
}
}
return canvasScale;
}
}
I want Advice for this problem.
Thanks.
no need to do anything just Replace your below method with my code.
private void drawImage(Canvas canvas)
{
Bitmap image = BitmapFactory.decodeResource(getResources(),
mImagesArray[mImagesArrayIndex]);
Bitmap b=Bitmap.createScaledBitmap(image, canvas.getWidth(), canvas.getHeight(), true);
canvas.drawBitmap(b, 0,0, null);
}
I would suggest that you crop the images instead of resizing them. Something like:
Rect r = new Rect(left, top, right, bottom);
Bitmap croppedImage = null;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1){
InputStream in = mContentResolver.openInputStream(mSaveUri);
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(in, false);
croppedImage = decoder.decodeRegion(r, null);
} else {
final int width = r.width();
final int height = r.height();
croppedImage = Bitmap.createBitmap(mBitmap, r.left, r.top, width, height);
croppedImage.setDensity(croppedImage.getDensity() * mOutputX / width);
}
return croppedImage;
Hope this helps...
I wanted to make some water ripples in my android application so I used this javascript code http://jsfiddle.net/esteewhy/5Ht3b/6/ converted into C code like it is shown here Live Wallpaper Water Ripple Effect (by esteewhy).
I have a main activity, which calls the water ripples activity after clicking a button. The water ripples are working great with my mutable bitmap, the problem is when I clicked the "back" button of the android device, the system crashes throwing this error:
FATAL EXCEPTION: Thread-2556
java.lang.NullPointerException
at com.wheelly.whater.WaterView.onDraw (line 149)
at com.wheelly.whater.WaterView$GameThread.run (line 255)
I guess there is some problem handling the Thread or the activities themselves.
Here is the code of the Water Ripples:
public class WaterView extends SurfaceView implements SurfaceHolder.Callback {
GameThread thread;
public static Bitmap icon;
//Measure frames per second.
long now;
int framesCount=0;
int framesCountAvg=0;
long framesTimer=0;
Paint fpsPaint=new Paint();
//Frame speed
long timeNow;
long timePrev = 0;
long timePrevFrame = 0;
long timeDelta;
private int width = 480;
private int height = 800;
private short riprad = 6;
boolean flip;
private short[] ripplemap, last_map;
Bitmap ripple;
private static final String TAG = null;
private Rippler rippler;
public WaterView(Context context) {
super(context);
initialize();
}
void initialize() {
//CB
icon = BitmapFactory.decodeResource(getResources(), R.drawable.sand100);
icon = convertToMutable(icon);
//--
rippler = new NativeRippler();
reinitgGlobals();
fpsPaint.setTextSize(30);
//Set thread
getHolder().addCallback(this);
setFocusable(true);
}
void reinitgGlobals() {
int size = width * (height + 2) * 2;
ripplemap = new short[size];
last_map = new short[size];
Bitmap texture = createBackground(width, height); // this creates a MUTABLE bitmap
ripple = texture;
_td = new int[width * height];
texture.getPixels(_td, 0, width, 0, 0, width, height);
_rd = new int[width * height];
}
void randomizer() {
final Random rnd = new Random();
final Handler disHAndler = new Handler();
final Runnable disturbWater = new Runnable() {
#Override
public void run() {
disturb(rnd.nextInt(width), rnd.nextInt(height));
disHAndler.postDelayed(this, 7000);
}
};
disHAndler.post(disturbWater);
}
private static Bitmap createBackground(int width, int height) {
Canvas cb = new Canvas (icon);
cb.save();
cb.restore();
return icon;
}
private Bitmap convertToMutable(Bitmap bitmap) {
try {
File file = new File("/mnt/sdcard/sample/temp.txt");
file.getParentFile().mkdirs();
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
int width_mutable = bitmap.getWidth();
int height_mutable = bitmap.getHeight();
FileChannel channel = randomAccessFile.getChannel();
MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, width_mutable*height_mutable*4);
bitmap.copyPixelsToBuffer(map);
bitmap.recycle();
bitmap = Bitmap.createBitmap(width_mutable, height_mutable, Config.ARGB_8888);
map.position(0);
bitmap.copyPixelsFromBuffer(map);
channel.close();
randomAccessFile.close();
} catch (FileNotFoundException e) {
Log.i(TAG, "::onActivityResult:" + ""+Log.getStackTraceString(e));
} catch (IOException e) {
Log.i(TAG, "::onActivityResult:" + ""+Log.getStackTraceString(e));
}
return bitmap;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
reinitgGlobals();
}
#Override
protected void onDraw(android.graphics.Canvas canvas) {
super.onDraw(canvas);
newframe();
canvas.drawBitmap(ripple, 0, 0, null);
//Measure frame rate (unit: frames per second).
now=System.currentTimeMillis();
canvas.drawText(framesCountAvg+" fps", 40, 70, fpsPaint);
framesCount++;
if(now-framesTimer>1000) {
framesTimer=now;
framesCountAvg=framesCount;
framesCount=0;
}
}
/**
* Disturb water at specified point
*/
private void disturb(int dx, int dy) {
rippler.disturb(dx, dy, width, height, riprad, ripplemap, flip);
}
int[] _td;
int[] _rd;
/**
* Generates new ripples
*/
private void newframe() {
System.arraycopy(_td, 0, _rd, 0, width * height);
flip = !flip;
rippler.transformRipples(height, width, ripplemap, last_map, _td, _rd, flip);
ripple.setPixels(_rd, 0, width, 0, 0, width, height);
}
#Override
public synchronized boolean onTouchEvent(MotionEvent event) {
disturb((int)event.getX(), (int)event.getY());
return true;
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
thread = new GameThread(getHolder(), this);
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
class GameThread extends Thread {
private SurfaceHolder surfaceHolder;
private WaterView gameView;
private boolean run = false;
public GameThread(SurfaceHolder surfaceHolder, WaterView gameView) {
this.surfaceHolder = surfaceHolder;
this.gameView = gameView;
}
public void setRunning(boolean run) {
this.run = run;
}
public SurfaceHolder getSurfaceHolder() {
return surfaceHolder;
}
#Override
public void run() {
Canvas c;
while (run) {
c = null;
//limit frame rate to max 60fps
timeNow = System.currentTimeMillis();
timeDelta = timeNow - timePrevFrame;
if ( timeDelta < 16) {
try {
Thread.sleep(16 - timeDelta);
}
catch(InterruptedException e) {
}
}
timePrevFrame = System.currentTimeMillis();
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
//call methods to draw and process next fame
gameView.onDraw(c);
}
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
I found the solution:
I had to interrupt the thread in the onPause method of the activity instead of doing it in the onStop method. Now it is just working fine.
Thanks a LOT to all of you for helping me with that problem.
you should shut down your working thread in the method Activity.onStop
#Override
protected void onStop() {
thread.interrupt();
super.onStop();
}
in the run method of GameThread check if thread was interrupted right before you call gameView.onDraw(c); like this:
if(isInterrupted()) {
break;
}
gameView.onDraw(c);
BTW, probably it would be better if you replace gameView.onDraw(c) with gameView.invalidate();
Don't call onDraw directly on a view, but rather call gameView.invalidate()
synchronized (surfaceHolder) {
//call methods to draw and process next fame
gameView.invalidate();
}
If it doesn't work, try using debugger with a breakpoint to see which variable is null exactly
I have been trying pretty much everything to get my live wallpaper to stop exceeding the VM memory and nothing seems to works.
I have some animations that are large but hopefully not to large because if I bring them down any more they will look horrible.
I have one sprite that is 30 frames long 7800x329 pixels I put in the mdpi folder it is 356 kb big.
I have two smaller animations I would love to add but it dies also, even when it does load I try to set it as a livewallpaper and it dies again.
Here's the code (I used the aquarium tutorial for this) for the sprite
public class SpriteOne extends SpriteMovement {
private static final int TOTAL_FRAMES_IN_SPRITE = 30;
private static final int SPRITE_ONE_FPS = 15;
public SpriteOne(Context context, TheTemplate thetemplate, Point startPoint, int speed){
super(context, thetemplate);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
Bitmap leftBitmap = BitmapFactory.decodeResource(getContext().getResources(), ca.samsstuff.steampunkdroid.R.drawable.droidfinal, options);
this.initialize(leftBitmap, SPRITE_ONE_FPS, TOTAL_FRAMES_IN_SPRITE, startPoint, speed);
}
public void render(Canvas canvas){
super.render(canvas);
}
}
I heard about recycle but not quite sure how to add this here.
This goes into another class I named TheTemplate, I'll add that also.
//template file
public class TheTemplate {
private SpriteThread spriteThread;
private SurfaceHolder _surfaceHolder;
private ArrayList<Renderable> _sprites;
public Bitmap _backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.background1);
//droid measurements
public Bitmap thedroid = BitmapFactory.decodeResource(getResources(), R.drawable.droidfinal);
public int thedroidHeight = thedroid.getHeight();
public int thedroidWidth = thedroid.getWidth() / 30;
private Context _context;
// add rescale stuff
private float screenWidth = initFrameParamsWidth();
private Bitmap theBackgroundImage;
private float totalHeight = _backgroundImage.getHeight();
private int screenSized = initFrameParams();
private float theScaler = (float) (screenSized / totalHeight);
private Bitmap oneBackImage = Bitmap.createScaledBitmap(_backgroundImage, (int) (theScaler * _backgroundImage.getWidth()), (int) (theScaler * _backgroundImage.getHeight()), true);
public void render(){
Canvas canvas = null;
try{
canvas = this._surfaceHolder.lockCanvas(null);
synchronized (this._surfaceHolder) {
this.onDraw(canvas);
}
}finally{
if(canvas != null){
this._surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
protected void onDraw(Canvas canvas) {
this.renderBackGround(canvas);
for (Renderable renderable : this._sprites) {
renderable.render(canvas);
}
};
public void start(){
this.spriteThread.switchOn();
}
public void stop(){
boolean retry = true;
this.spriteThread.switchOff();
while (retry) {
try {
this.spriteThread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
public int backgroundLeft() {
int startMovement = (int) ((screenWidth - theBackgroundImage.getWidth()) / 2);
return startMovement;
}
public int backgroundRight() {
return this.theBackgroundImage.getWidth();
}
public void initialize(Context context, SurfaceHolder surfaceHolder) {
this.spriteThread = new SpriteThread(this);
this._surfaceHolder = surfaceHolder;
this._sprites = new ArrayList<Renderable>();
this._context = context;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
this.theBackgroundImage = oneBackImage;
this.addSprites();
}
private void addSprites() {
Point startPoint = new Point((int) ((screenWidth / 2) - (thedroidWidth / 2)), ((screenSized / 2) - (thedroidHeight / 2)));
this._sprites.add(new SpriteOne(this._context, this, startPoint , 30));
}
private void renderBackGround(Canvas canvas)
{
float canvasewidthsize = (float) ((screenWidth / 2) - (theBackgroundImage.getWidth() / 2));
canvas.drawBitmap(this.theBackgroundImage, canvasewidthsize, 0, null);
}
}
Any help in this would be greatly appreciated as this one is driving me nuts.
Thanks in advance
Sam
sorry I should of answered this long ago.
just cut down on frames and image size use purgeable or recycle or both