##MyDraw.java##
This part of the code is where the bitmap image is created, the bitmap sits on the canvas, form this point I want to be able to save the image that is created on the bitmap, I have a drop down menu in the MainActivity with a 'save' option.
package com.example.save_file;
import java.util.Random;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.View;
import android.view.MotionEvent;
public class MyDraw extends View
{
Canvas c;
Bitmap bmp;
Paint paint;
Random g;
float X, Y;
public MyDraw (Context context)
{
super(context);
g = new Random ();
Bitmap.Config conf = Bitmap.Config.ARGB_8888;
bmp = Bitmap.createBitmap (1100, 1800, conf);
paint = new Paint ();
paint.setStyle (Paint.Style.STROKE);
paint.setColor (Color.WHITE);
this.setOnTouchListener (new OnTouchListener()
{
public boolean onTouch (View v, MotionEvent event)
{
int h, w, R, G, B, A;
float x, y;
c = new Canvas (bmp);
x = event.getX ();
y = event.getY ();
System.out.printf ("%f %f\n", X, Y);
paint.setAntiAlias (true);
w = g.nextInt (70)+90;
h = g.nextInt (70);
R = g.nextInt (255);
G = g.nextInt (255);
B = g.nextInt (255);
A = g.nextInt (255);
paint.setStyle (Paint.Style.FILL);
paint.setColor ((A << 24) + (R << 16) + (G << 8) + (B << 0));
if (MyApp.fill == 0) // FILLED SHAPE
{
paint.setStyle (Paint.Style.FILL);
paint.setColor ((A << 24) + (R << 16) + (G << 8) + (B << 0));
if (MyApp.shape == 0)
c.drawRect (x, y, x + w, y + h, paint);
else
c.drawOval(new RectF (x, y, x + w, y + h), paint);
paint.setStyle (Paint.Style.STROKE);
paint.setColor (Color.BLACK);
if (MyApp.shape == 0)
c.drawRect (x, y, x + w, y + h, paint);
else
c.drawOval(new RectF (x, y, x + w, y + h), paint);
}
else // OUTLINED SHAPE
{
paint.setStyle (Paint.Style.STROKE);
paint.setColor ((A << 24) + (R << 16) + (G << 8) + (B << 0));
if (MyApp.shape == 0)
c.drawRect (x, y, x + w, y + h, paint);
else
c.drawOval(new RectF (x, y, x + w, y + h), paint);
}
paint.setColor (Color.WHITE);
invalidate ();
return true;
}
});
}
#Override
protected void onDraw (Canvas c)
{
super.onDraw (c);
c.drawBitmap (bmp, 0, 0, paint);
}
}
##MyApp.java##
package com.example.save_file;
public class MyApp
{
static public int shape = 0;
static public int fill = 0;
}
##MainActivity.java##
This is the part of the code where the menu code is, I want to be able to pres the save button here and for the bitmap image to be saved to the phone, preferably a standard gallery folder.
package com.example.save_file;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Random;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.view.Menu;
import android.view.MenuItem;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.view.Menu;
//import android.gesture.GestureOverlayView;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
MyDraw d = new MyDraw (this);
setContentView (d);
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu (menu);
MenuItem menu1 = menu.add(0, 0, Menu.NONE, "Filled Shape");
MenuItem menu2 = menu.add(0, 1, Menu.NONE, "Outline Shape");
MenuItem menu3 = menu.add(0, 2, Menu.NONE, "Rectangle");
MenuItem menu4 = menu.add(0, 3, Menu.NONE, "Oval");
MenuItem menu5 = menu.add(0, 4, Menu.NONE, "Save!");
return true;
}
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case 0:
MyApp.fill = 0;
return true;
case 1:
MyApp.fill = 1;
return true;
case 2:
MyApp.shape = 0;
return true;
case 3:
MyApp.shape = 1;
return true;
default:
return super.onOptionsItemSelected(item);
case 4:
bmp.setDrawingCacheEnabled(true);
Bitmap bitmap = bmp.getDrawingCache();
File root = Environment.getExternalStorageDirectory();
File file = new
File(root.getAbsolutePath()+"/DCIM/Camera/img.jpg");
try
{
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG, 100, ostream);
ostream.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
I use this code to save any graphic drawed using canvas, like fingerpaint or similar, I hope can be useful for your case
Set the instance as global
MyDraw d;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
d = new MyDraw (this);
setContentView (d);
}
And put this in the case of your onOptionsItemSelected();
case 4:
try {
Bitmap bitmap = Bitmap.createBitmap(d.getWidth(),d.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
d.draw(canvas);
File folder = new File(Environment.getExternalStorageDirectory()+ "/DCIM/Camera/");
if (!folder.exists())
folder.mkdirs();
String fileName = Environment.getExternalStorageDirectory()+ "/DCIM/Camera/img.jpg"";
if (new File(fileName).exists())
new File(fileName).delete();
OutputStream stream = new FileOutputStream(fileName);
/*
* Write bitmap to file using JPEG or PNG and 100% quality hint
* for JPEG.
*/
bitmap.compress(CompressFormat.JPEG, 100, stream);
stream.close();
} catch (Exception e) {
// TODO Auto-generated catch block
Toast.makeText(this, "Error: " + e.getMessage(),Toast.LENGTH_LONG).show();
}
break;
UPDATE:
Check that your emulated device has SD Card
Remind that you have to add the permissions to manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Related
I made the snake and ladder game in android studio. I want to change the height and width of the buttons, and I want to add one more button for exit. Right now I am using only one .png file for all buttons. So, How to change it? When i add the fourth button my application crash and its shows the error.
Check this image
Error
FATAL EXCEPTION: main
Process: com.sixtinbyte.snakeandladder, PID: 25115
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.sixtinbyte.snakeandladder.components.GameButton.onDraw(android.graphics.Canvas)' on a null object reference
at com.sixtinbyte.snakeandladder.HomeView.onDraw(HomeView.java:151)
HomeView. java (This are the java file where i want to change because this is the homescreen of the game)
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.view.MotionEvent;
import android.view.View;
import com.sixtinbyte.snakeandladder.components.GameButton;
import com.sixtinbyte.snakeandladder.constant.Sound;
public class HomeView extends View {
public Context ctx;
private Resources res;
private String refText ="Snakes and Ladders";
private GameButton gButton, sButton, hButton,eButton;
private Bitmap logo, play, settings, help, exit;
private int hWidth, hHeight;
private Point touchCoordinate = new Point();
public HomeView(Context ctx) {
super(ctx);
this.ctx = ctx;
res = getResources();
logo = BitmapFactory.decodeResource(res, R.drawable.snakes_n_ladders);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// TODO: Implement this method
super.onSizeChanged(w, h, oldw, oldh);
hWidth = w;
hHeight = h;
preparePlayButton();
prepareSettingsButton();
prepareHelpButton();
// prepareExitButton();
}
private void preparePlayButton() {
String text =" ";
int textSize = 40;
Point po = getBmpMeasureFrom(text, refText, textSize);
play = getBitmap(R.drawable.play, po.x, po.y);
gButton = new GameButton(play, text, textSize);
gButton.setLocation((hWidth - po.x) / 2, (int)(hHeight * 0.6f));
gButton.setTextColor(Color.CYAN);
}
private void prepareSettingsButton() {
String text =" ";
int textSize = 40;
Point po = getBmpMeasureFrom(text, refText, textSize);
settings = getBitmap(R.drawable.play, po.x, po.y);
sButton = new GameButton(settings, text, textSize);
sButton.setLocation((hWidth - po.x) / 2, (int)(hHeight * 0.7f));
sButton.setTextColor(Color.CYAN);
}
//
//
private void prepareHelpButton() {
String text =" ";
int textSize = 40;
Point po = getBmpMeasureFrom(text, refText, textSize);
help = getBitmap(R.drawable.play, po.x, po.y);
hButton = new GameButton(help, text, textSize);
hButton.setLocation((hWidth - po.x) / 2, (int)(hHeight * 0.8f));
hButton.setTextColor(Color.CYAN);
}
// private void prepareExitButton() {
// String text =" ";
// int textSize = 40;
// Point po = getBmpMeasureFrom(text, refText, textSize);
// help = getBitmap(R.drawable.play, po.x, po.y);
// hButton = new GameButton(help, text, textSize);
// hButton.setLocation((hWidth - po.x) / 2, (int)(hHeight * 0.8f));
// hButton.setTextColor(Color.CYAN);
//
// }
private Point getBmpMeasureFrom(String text, String refText, int textSize) {
Point p = new Point();
Paint pa = new Paint();
pa.setTextSize(textSize);
p.y = (int)(pa.getTextSize() * 2.2f);
String tt = refText.length() > text.length() ?refText: text;
p.x = (int) (pa.measureText(tt) * 1.2f);
return p;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// TODO: Implement this method
int evt = event.getAction();
touchCoordinate.x = (int)event.getX();
touchCoordinate.y = (int)event.getY();
switch (evt) {
case MotionEvent.ACTION_DOWN:
MainActivity.playSound(Sound.BUTTON_CLICK_1, false);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
// MainActivity.stopSound();
if (gButton.contains(touchCoordinate)) {
Intent intent = new Intent(ctx, GameActivity.class);
ctx. startActivity(intent);
}
if (sButton.contains(touchCoordinate)) {
Intent intent = new Intent(ctx, Playing.class);
ctx.startActivity(intent);
}
if (hButton.contains(touchCoordinate)) {
Intent intent = new Intent(ctx, Aboutus.class);
ctx. startActivity(intent);
}
// if(eButton.contains(touchCoordinate)){
// Intent intent = new Intent(ctx, Exit.class);
// ctx.startActivity(intent);
// }
break;
}
return true;
}
#Override
protected void onDraw(Canvas canvas) {
// TODO: Implement this method
super.onDraw(canvas);
canvas.drawColor(Color.CYAN);
canvas.drawBitmap(logo, (hWidth - logo.getWidth()) / 2, (int)((hHeight - logo.getHeight()) * 0.1), null);
gButton.onDraw(canvas);
sButton.onDraw(canvas);
hButton.onDraw(canvas);
// eButton.onDraw(canvas);
// Paint p= new Paint();
// p.setColor(Color.RED);
// canvas.drawRect(100, 200, 400, 500, p);
invalidate();
}
private Bitmap getBitmap(int drawableRes, int width, int height) {
Drawable d = res.getDrawable(drawableRes);
Canvas c = new Canvas();
Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
c.setBitmap(b);
d.setBounds(0, 0,width, height);
d.draw(c);
return b;
}
}
The prepareExitButton method is assigning hButton, I think it should be assigning eButton. That's why you're getting a NullPointerException there. Also, you're setting the y-coordinate to (int)(hHeight * 0.8f)) which means it will overlap with the help-button.
You may need to alter the GameButton class to get the ability to adjust the button's size. In particular, you'll want to change onDraw to draw the button in the specified size.
I have started to learn android and java using the android studio beta. As a first simple test app I am trying to get a basic Mandelbrot renderer working. I have gotten it to display, but now I want it faster. Can anyone give advice on the following?
The docs say canvas.drawbitmap is depreciated. What should I use instead? What is the fastest ways to show a bitmap onscreen?
How can I show the progress of the calculations? If I unremark the 2 lines marked "update display after each line has been calculated" there is no updating during the calculations and the extra calls to canvas.drawbitmap really slow it all down (79 seconds compared to 31 seconds without it).
Is there anything I can do to speed up the general math calls?
I have tried to keep it as simple as possible for this example.
Many thanks for any tips for a newbie. I don't want to learn bad habits from the start if possible.
The layout has a single imageview aligned to the screen. The full code is
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.Display;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import java.text.DecimalFormat;
import java.util.Random;
import static android.graphics.Color.argb;
import static android.graphics.Color.rgb;
public class myActivity extends Activity {
myView myview;
Bitmap bmp;
Canvas myCanvas;
ImageView img;
Paint paint;
Boolean started=false;
Integer ih,iw,i,redraws,fw,fh;
long startms,finishms;
Random rnd;
double xmin,xmax,ymin,ymax,padding,bailout,bailout_squared,stepx,stepy,x,y,magnitude;
double realiters,tweenval;
Integer col,colval1,colval2;
Integer iterations,maxiterations,superx,supery,samplepixels,square_samplepixels,xloop,yloop;
double zr,zi,cr,ci,xloopdouble,yloopdouble;
int[] colorpalette = new int[256];
int[] pixels;
int r,g,b,r1,g1,b1,r2,g2,b2,totalr,totalg,totalb;
private void init(){
//screen size
Display display = getWindowManager().getDefaultDisplay();
Point sizePoint = new Point();
paint = new Paint();
display.getSize(sizePoint);
iw=sizePoint.x;
ih=sizePoint.y;
//pixels array
fw=iw;
fh=ih;
pixels=new int[fw*fh];
//create bitmap
bmp=Bitmap.createBitmap(iw, ih, Bitmap.Config.RGB_565);
//create canvas
myCanvas =new Canvas();
myCanvas.setBitmap(bmp);
img = (ImageView) findViewById(R.id.imageView1);
rnd = new Random();
}
// calculates and displays the Mandelbrot fractal
private void Mandelbrot(){
startms= SystemClock.uptimeMillis();
//coordinates
// xmin=-1.6345100402832;
// xmax=-1.63043992784288;
// ymin=-0.00209962230258512;
// ymax=0.00209259351094558;
xmin=-2.3;
xmax=2.3;
ymin=-2.1;
ymax=2.1;
fw=iw;
fh=ih;
//adjust coords to match screen aspect
if (iw<ih) {
padding=(xmax-xmin)/iw*(ih-iw);
ymin=ymin-padding/2.0;
ymax=ymax+padding/2.0;
} else {
padding=(ymax-ymin)/ih*(iw-ih);
xmin=xmin-padding/2.0;
xmax=xmax+padding/2.0;
}
bailout=8.0; //needs to be higher than default 2 for the CPM coloring to be smooth
bailout_squared=bailout*bailout;
maxiterations=64;
samplepixels=1;
square_samplepixels=samplepixels*samplepixels;
//random color palette
for (col=0;col<256;col++){
colorpalette[col]=android.graphics.Color.argb(255,rnd.nextInt(256),rnd.nextInt(256),rnd.nextInt(256));
}
stepx=(xmax-xmin)/fw/samplepixels;
stepy=(ymax-ymin)/fh/samplepixels;
for (yloop=0;yloop<fh;yloop++){
for (xloop=0;xloop<fw;xloop++){
totalr=0;
totalg=0;
totalb=0;
r=0;
g=0;
b=0;
xloopdouble=(double)xloop;
yloopdouble=(double)yloop;
for (supery=0;supery<samplepixels;supery++)
{
for (superx=0;superx<samplepixels;superx++)
{
cr = xmin+xloopdouble/(double)fw*(xmax-xmin)+(stepx*(double)superx);
ci = ymin+yloopdouble/(double)fh*(ymax-ymin)+(stepy*(double)supery);
zr = 0.0;
zi = 0.0;
magnitude=0.0;
for(iterations=0; iterations<maxiterations; iterations++)
{
i=iterations;
x = (zr * zr - zi * zi) + cr;
y = (zi * zr + zr * zi) + ci;
magnitude=(x * x + y * y);
if(magnitude>bailout_squared) break;
zr = x;
zi = y;
}
if (iterations>=maxiterations) {
r=0;
g=0;
b=0;
} else {
//CPM smooth colors
realiters=iterations+1-((Math.log(Math.log(Math.sqrt(magnitude)))/Math.log(2.0)));
colval1=(int) Math.floor(realiters % 255);
colval2=(colval1+1) % 255;
tweenval=realiters-Math.floor(realiters);
r1=Color.red(colorpalette[colval1]);
g1=Color.green(colorpalette[colval1]);
b1=Color.blue(colorpalette[colval1]);
r2=Color.red(colorpalette[colval2]);
g2=Color.green(colorpalette[colval2]);
b2=Color.blue(colorpalette[colval2]);
r=(int) (r1+((r2-r1)*tweenval));
g=(int) (g1+((g2-g1)*tweenval));
b=(int) (b1+((b2-b1)*tweenval));
}
totalr=totalr+r;
totalg=totalg+g;
totalb=totalb+b;
}
}
r=(int) totalr/square_samplepixels;
g=(int) totalg/square_samplepixels;
b=(int) totalb/square_samplepixels;
//update pixels array
pixels[xloop+yloop*fw]=rgb(r, g, b);
}
//update display after each line has been calculated
//myCanvas.drawBitmap(pixels,0,fw,0,0,fw,fh,false,null);
//if (img != null) img.invalidate();
}
myCanvas.drawBitmap(pixels,0,fw,0,0,fw,fh,false,null);
finishms=SystemClock.uptimeMillis();
}
private void updateTimeTaken(){
//turn antialiasing on
paint.setAntiAlias(true);
// draw some text using FILL style
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(30);
DecimalFormat myFormatter = new DecimalFormat("#,###,###");
paint.setColor(Color.BLACK);
myCanvas.drawText("Time taken = " + myFormatter.format(finishms - startms) + " ms", 15, 45, paint);
paint.setColor(Color.WHITE);
myCanvas.drawText("Time taken = " + myFormatter.format(finishms - startms) + " ms", 14, 44, paint);
paint.setColor(Color.BLACK);
myCanvas.drawText("Screen size = " + String.valueOf(iw) + " x " + String.valueOf(ih), 15, 85, paint);
paint.setColor(Color.WHITE);
myCanvas.drawText("Screen size = " + String.valueOf(iw) + " x " + String.valueOf(ih), 14, 84, paint);
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
//fullscreen no menu
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
redraws=0;
super.onCreate(savedInstanceState);
myview = new myView(this);
setContentView(myview);
init();
started=true;
Mandelbrot();
updateTimeTaken();
}
private class myView extends View{
public myView(Context context){
super(context);
}
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//draw off screen bitmap to screen
if (started==true){
canvas.drawBitmap(bmp,0,0,paint);
}
}
}
}
This android app is acting as if I had double tapped it each time I touch the screen, can anyone see why is this happening? I have it log "touch # " + [the number of touches] and it does "touch 1" and "touch 2" at the same time, same as "touch 3" and "touch 4"
package com.example.mondrianmaker;
import java.util.ArrayList;
import java.util.Random;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
public class MainActivity extends Activity {
int width, height, x, y, color, touch;
ArrayList<Rectangle> rectangles, childsRect;
Bitmap bg;
Canvas canvas;
Display display;
LinearLayout ll;
Point size;
Paint paint;
Random rn;
Rectangle parentRect;
TextView text, info;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//***FULL SCREEN***
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
//---FULL SCREEN---
setContentView(R.layout.activity_main);
display = getWindowManager().getDefaultDisplay();
size = new Point();
display.getSize(size);
width = size.x;
height = size.y;
paint = new Paint(); //paint to color rectangle OBLI
bg = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);
canvas = new Canvas(bg);
ll = (LinearLayout) findViewById(R.id.mondrian);
rectangles = new ArrayList<Rectangle>();
text = (TextView) findViewById(R.id.coordinates);
info = (TextView) findViewById(R.id.info);
parentRect = new Rectangle(0, 0, 480, 800); //create super parent rectangle
rectangles.add(parentRect); //add super parent rectangle to list
touch = 0;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//Get Coordinate
x = (int) event.getX();
y = (int) event.getY();
//set text view to clicked coordinates and number of rectangles on list
text.setText(x + ", " + y + " rectangles: "+rectangles.size());
//set rectangle color *randomly
setColor();
paint.setColor(color);
//get rectangle clicked
parentRect = getRectParent(x, y);
//make children of rectangle clicked
childsRect = makeChilds(parentRect, x, y);
addChildsToRectanglesDeleteParentRect(childsRect, parentRect);
//check on childs
// text.setText(childsRect.get(0) + " " + childsRect.get(1));
//get onTouch action
switch (event.getAction()) {
// case MotionEvent.ACTION_DOWN:
// text.setText(x + ", " + y);
// ll.setBackgroundDrawable(new BitmapDrawable(bg));
// case MotionEvent.ACTION_MOVE:
// ll.setBackgroundDrawable(new BitmapDrawable(bg));
// System.out.println("22222");
case MotionEvent.ACTION_UP:
touch++;
Log.i("info", "touch # " + touch);
// ll.setBackgroundDrawable(new BitmapDrawable(bg));
// System.out.println("33333");
}
return false;
}
public void addChildsToRectanglesDeleteParentRect(ArrayList<Rectangle> childsRect, Rectangle parentRect){
rectangles.remove(parentRect);
rectangles.add(childsRect.get(0));
rectangles.add(childsRect.get(1));
int i = 0;
Log.i("info", "length= "+rectangles.size());
for(Rectangle e : rectangles){
Log.i("info", i+"--> "+ e.toString());
i++;
}
}
public ArrayList<Rectangle> makeChilds(Rectangle parent, int x, int y){
ArrayList<Rectangle> defaults = new ArrayList<Rectangle>();
defaults.add(new Rectangle(0,0,240,800));
defaults.add(new Rectangle(240,0, 480, 800));
ArrayList<Rectangle> childs = new ArrayList<Rectangle>();
for(Rectangle rect : rectangles){
if(x>=rect.getX1() && x<=rect.getX2() && y>=rect.getY1() && y<=rect.getY2()){
childs.add(new Rectangle(rect.getX1(), rect.getY1(), rect.getX2()/2, rect.getY2()/2));
childs.add(new Rectangle(rect.getX2()/2, rect.getY2()/2, rect.getX2(), rect.getY2()));
}
}
if(childs.size()>0){
return childs;
}else{
info.setText(x + ", " + y + " " + parent + "no childs for this parent");
return defaults;
}
}
public Rectangle getRectParent(int x, int y){
for(Rectangle g : rectangles){
if (x > g.getX1() && x < g.getX2() && y > g.getY1() && y < g.getY2()){
info.setText(info.getText() + "\n " + g.getX1()+"_x=" + x +"_"+g.getX2() +"\n"+g.getY1()+"_y="+y+"_"+g.getY2());
return g;
}
}
return null;
}
public void setColor(){
rn = new Random();
switch ((int) Math.floor(rn.nextDouble() * 5)) {
case 0:
color = Color.BLACK;
break;
case 1:
color = Color.RED;
break;
case 2:
color = Color.YELLOW;
break;
case 3:
color = Color.WHITE;
break;
case 4:
color = Color.GREEN;
break;
}
}
}
You're probably getting an ACTION_DOWN and an ACTION_MOVE and counting both.
Try moving your ++ to inside the switch case for ACTION_DOWN.
I tested your code and works without any issue however you can try using if statement. Also make sure your switch statement return true or break; tho it works without using any of them; here how you can use if statement:
if(event.getAction() == MotionEvent.ACTION_UP){
// up is called
touch++;
Log.i("info", "touch # " + touch);
return true;
}
Can anyone help, my app does not seem to do the onDraw() in the GraView class, even if .invalidate is called upon from either inside or outside the class. I managed to figure out with system.err that it does invalidate the view, however it never gets in the onDraw( ), even though the rest of the app keeps running. I found a lot of solutionssuggesting putting setWillNotDraw(false) in the constructor, but that did not solve anything.
GravIO.java File:
package dabawi.gravitas;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class GravIO extends Activity implements Runnable, OnTouchListener {
public final static int clock = 1000;
private GravEngine engine;
private GraView TV;
private SensorManager mSensorManager;
private Sensor mSensor;
private Thread t1;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
t1 = new Thread(this);
t1.start();
engine = new GravEngine();
TV = new GraView(this, engine);
setContentView(TV);
TV.setOnTouchListener(this);
TV.setVisibility(View.VISIBLE);
//mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
System.err.println("Starting Engine") ;
run();
}
#Override
public void run() {
while (true) {
try {
System.err.println("Tik") ;
engine.tick();
TV.invalidate();
Thread.sleep(GravIO.clock);
} catch (InterruptedException ex) {
System.err.println("faal");
}
}
}
#Override
public boolean onTouch(View view, MotionEvent event) {
engine.switchGravity();
return true;
}
}
GraView.java File:
package dabawi.gravitas;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
#SuppressLint({ "DrawAllocation", "ViewConstructor" })
public class GraView extends View {
private GravEngine engine;
private int screenWidth, screenHeight, ySpace = 5, xSpace, scale;
private Paint paint;
private int xLoc, yLoc;
private boolean xWall = false, yWall = false;
public GraView(Context context, GravEngine engine) {
super(context);
setWillNotDraw(false);
this.engine = engine;
calcScale(context);
}
#Override // We think the problem is with this method, that it is never called upon.
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
System.err.println("Calculating position");
calcPos();
canvas = new Canvas();
// drawing background
paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
drawGame(canvas);
}
private void drawGame(Canvas canvas) {
drawRoom(canvas);
drawPlayer(canvas);
}
#SuppressWarnings("deprecation")
private void calcScale(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
screenWidth = d.getWidth();
screenHeight = d.getHeight();
scale = screenHeight / ySpace;
xSpace = screenWidth / scale;
}
private void calcPos() {
xLoc = (engine.getxPlayer() / GravEngine.roomScaling);
yLoc = (engine.getyPlayer() / GravEngine.roomScaling);
if (xLoc < (xSpace + 1) / 2) {
xLoc = (xSpace + 1) / 2;
xWall = true;
} else if (xLoc > (GravRoom.xSize - ((xSpace + 1) / 2))) {
xLoc = GravRoom.xSize - ((xSpace + 1) / 2);
xWall = true;
} else {
xWall = false;
}
if (yLoc < (ySpace + 1) / 2) {
yLoc = (ySpace + 1) / 2;
yWall = true;
} else if (yLoc > (GravRoom.xSize - ((ySpace + 1) / 2))) {
xLoc = GravRoom.ySize - ((ySpace + 1) / 2);
yWall = true;
} else {
yWall = false;
}
}
private void drawPlayer(Canvas canvas) {
float xPos = engine.getxPlayer() / GravEngine.roomScaling, yPos = engine
.getyPlayer() / GravEngine.roomScaling;
if (xWall) {
}
if (yWall) {
}
paint.setColor(Color.BLUE);
int left = (int) (xPos * scale), top = (int) (yPos * scale);
int right = left + (GravEngine.pxSize / GravEngine.roomScaling) * scale;
int bot = top + (GravEngine.pySize / GravEngine.roomScaling) * scale;
canvas.drawRect(left, top, right, bot, paint);
}
private void drawRoom(Canvas canvas) {
for (int i = 0, x = xLoc - ((xSpace + 1) / 2); i < xSpace + 1; x++, i++) {
for (int j = 0, y = yLoc - ((ySpace + 1) / 2); i < ySpace + 1; y++, j++) {
drawRoomPart(x,y,i,j,canvas);
}
}
}
private void drawRoomPart(int x, int y, int i, int j, Canvas canvas) {
if (x >= 0 && y >= 0 && x < GravRoom.xSize && y < GravRoom.ySize) {
short type = engine.getRoom(engine.getCurrentRoom()).getGridPos(x,y);
if (type != 0) {
drawBlock(canvas, i, x, j, y, type);
}
}
}
private void drawBlock(Canvas canvas, int i, int x, int j, int y, short type) {
int left = i * scale, top = y * scale;
int right = left + scale;
int bot = top + scale;
paint.setColor(colorBlock(type));
canvas.drawRect(left, top, right, bot, paint);
System.err.println("Left" + left + " top: " + top + " right: "
+ right + " bot: " + bot);
}
private int colorBlock(short type) {
if (type == 1) {
return Color.DKGRAY;
} else if (type == 2) {
return Color.CYAN;
} else if (type == 3) {
return Color.GREEN;
} else if (type == 4) {
return Color.RED;
} else {
return Color.MAGENTA;
}
}
// private void imageBlock(short type) {
//
// }
}
Ouch !
Your call to your run method is executed in the UIThread (as the onCreate method), and it's doing an infinite loop in it.
Just add a println after the call and you will see that the UI thread is never released, your application should not even start !
You don't see any changes because you are creating a new canvas and drawing on that. To fix this, remove the line
canvas = new Canvas();
Also, you should initiate your Paint outside of the onDraw method (this is an optimization recommended by the Android documentation).
I'm getting
Canvas: trying to use a recycled bitmap
android.graphics.Bitmap#4057a3a8
everytime i'm trying to show one image.
Image
When i delete bmp.recycle() everything goes well but i dont use this image in my code so i dont understand where the problem is.
package com.example.photobooth;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
public class EditorActivity extends Activity implements OnClickListener{
String path = null;
private int screen_height;
private int screen_width;
private Bitmap setUpImage(Bitmap image) {
int min_side = Math.min(screen_height, screen_width);
float scale_factor = (float) (((float) min_side / image.getWidth()) * 1.5);
float[] scalef = { scale_factor, scale_factor };
Bitmap scaled_image = ImageUtilities.scaleImage(image, scalef);
return scaled_image;
}
private void setUp() {
Bundle b = getIntent().getExtras();
if (b != null) {
path = b.getString("path");
}
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
this.screen_height = metrics.heightPixels;
this.screen_width = metrics.widthPixels;
int min_measure = Math.min(screen_width, screen_height);
// Make ImageView square
ImageView img = (ImageView) findViewById(R.id.photo_holder);
android.view.ViewGroup.LayoutParams lp = img.getLayoutParams();
lp.height = min_measure;
img.setLayoutParams(lp);
Bitmap bmp = BitmapFactory.decodeFile(path);
final Bitmap ready_image = setUpImage(bmp);
bmp.recycle();
ImageView iv = (ImageView) findViewById(R.id.photo_holder);
iv.setImageBitmap(ready_image);
// set up touch event for imageview(photo_holder)
img.setOnTouchListener(new OnTouchListener() {
float touch_x, touch_y, scrolled_x = 0.0f, scrolled_y = 0.0f;
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_x = event.getX();
touch_y = event.getY();
break;
case MotionEvent.ACTION_MOVE:
float cur_x = event.getX();
float cur_y = event.getY();
float scroll_x = -cur_x + touch_x;
float scroll_y = -cur_y + touch_y;
scrolled_x += scroll_x;
scrolled_y += scroll_y;
if (scrolled_x > (ready_image.getWidth() - screen_width)/2
|| scrolled_x < -(ready_image.getWidth() - screen_width)/2){
scrolled_x -= scroll_x;
scroll_x = 0;
}
if (scrolled_y > (ready_image.getHeight() - screen_width)/2
|| scrolled_y < -(ready_image.getHeight() - screen_width)/2){
scrolled_y -= scroll_y;
scroll_y = 0;
}
v.scrollBy((int) (scroll_x),
(int) (scroll_y));
touch_x = cur_x;
touch_y = cur_y;
break;
}
return true;
}
});
//Set up buttons
Button btn = (Button)findViewById(R.id.save);
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
ImageView img = (ImageView)findViewById(R.id.photo_holder);
int scroll_x = img.getScrollX();
int scroll_y = img.getScrollY();
int left = (ready_image.getWidth() - screen_width)/2
+ scroll_x;
int top = (ready_image.getHeight() - screen_width)/2
+ scroll_y;
int right = left + screen_width;
int bottom = top + screen_width;
Rect r = new Rect(left, top, right, bottom);
Bitmap croped_image = ImageUtilities.cropImage(ready_image,
r,
screen_width,
screen_width);
String path_to_folder = Environment.getExternalStorageDirectory()
.getAbsolutePath();
String pic_path = path_to_folder + File.separator + MainActivity.app_name;
File f = new File(pic_path);
File picture = null;
try {
picture = File.createTempFile("photo_", ".jpg", f);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
FileOutputStream fos = new FileOutputStream(picture);
croped_image.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (requestWindowFeature(Window.FEATURE_NO_TITLE))
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_editor);
setUp();
}
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
bmp is recycled in setUp() method.
ImageUtility is
package com.example.photobooth;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
public class ImageUtilities {
public static Bitmap getRoundedCornerBitmap(Context context, Bitmap input,
int pixels, int w, int h, boolean squareTL, boolean squareTR,
boolean squareBL, boolean squareBR, boolean border) {
Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final float densityMultiplier = context.getResources()
.getDisplayMetrics().density;
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, w, h);
final RectF rectF = new RectF(rect);
// make sure that our rounded corner is scaled appropriately
final float roundPx = pixels * densityMultiplier;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
// draw rectangles over the corners we want to be square
if (squareTL) {
canvas.drawRect(0, 0, w / 2, h / 2, paint);
}
if (squareTR) {
canvas.drawRect(w / 2, 0, w, h / 2, paint);
}
if (squareBL) {
canvas.drawRect(0, h / 2, w / 2, h, paint);
}
if (squareBR) {
canvas.drawRect(w / 2, h / 2, w, h, paint);
}
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(input, 0, 0, paint);
if (border) {
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(3);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
}
return output;
}
public static Bitmap cropImage(Bitmap origina_bmp, Rect rec, int w, int h) {
Bitmap target_bitmap = Bitmap.createBitmap(w, h,
Bitmap.Config.ARGB_8888);
target_bitmap.setDensity(origina_bmp.getDensity());
Canvas canvas = new Canvas(target_bitmap);
canvas.drawBitmap(origina_bmp, new Rect(rec.left, rec.top, rec.right,
rec.bottom), new Rect(0, 0, w, h), null);
return target_bitmap;
}
public static Bitmap makeSquareImage(Bitmap original_image, int size){
int min_side = Math.min(original_image.getWidth(),
original_image.getHeight());
int side_size = ImageUtilities.get2del(min_side);
int crop_to;
Bitmap croped_image = null;
if (min_side == original_image.getWidth()){
crop_to = (original_image.getHeight() - side_size) / 2;
croped_image = ImageUtilities.cropImage(original_image, new Rect(
0, crop_to, original_image.getWidth(),
original_image.getHeight() - crop_to), size, size);
}else{
crop_to = (original_image.getWidth() - side_size) / 2;
croped_image = ImageUtilities.cropImage(original_image, new Rect(
crop_to, 0, original_image.getWidth() - crop_to,
original_image.getHeight()), size, size);
}
return croped_image;
}
public static int get2del(int num) {
while (num % 2 != 0)
num++;
return num;
}
public static Bitmap scaleImage(Bitmap originalBMP, float[] scaleFactor) {
Matrix scaleMat = new Matrix();
scaleMat.postScale(scaleFactor[0], scaleFactor[1]);
Bitmap scaledImage = Bitmap.createBitmap(originalBMP, 0, 0,
originalBMP.getWidth(), originalBMP.getHeight(), scaleMat,
false);
return scaledImage;
}
}
so it doesn't.
If i write bmp = null instead of bmp.recycle() everything is ok but i wonder why in the second chance application is crashed.
What is ImageUtilities? Maybe scaleImage may reuse the same image.
Does your program work correctly if you do:
bmp = null;
instead of
bmp.recycle();
?
The official documentation of recycle says:
"This is an advanced call, and normally need not be called, since the normal GC process will free up this memory when there are no more references to this bitmap. "
So using "bmp = null" should be better than "bmp.recycle()".