I'm creating an android app that has to draw a map of an ambient that i have explored with laserscans.
I have e text file with all my data like:
index x y
path 0 0 0
path 1 1 0
path 2 2 0
...etc
obstacle 0 10 10
obstacle 1 10 22
..etc
so I have xy coordinates of where I've been and xy of obstacles I've seen.
I have a thread that reads the data from the text file and stores that data in a list.
Another thread reads that list and draws all the points that are put in the list until that moment by the reading thread.
My problem is that I don't want to re-read everything every time the reading thread has put new data into the data list. There is a way to draw something like a bitmap and modify this dynamically? I mean that every time I have read some new data I "open" the bitmap, I add to that the new points, "close" that bitmap and show on the screen?
what I am doing now is to read all the list in my onDraw() function and draw point by point, but I have 170 000 points and that is a useful work because every time the points are in the old position, I only have some new points...
You can create a bitmap and a canvas in your view and just continue to draw into this bitmap as necessary. To prevent points from being drawn over again, the thread that draws the points should either remove points from the list as they are drawn, or keep track of the index of the last point.
Here's an example that contains the basics:
public class myView extends View {
Bitmap mBitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
Canvas mCanvas = new Canvas(mBitmap);
Paint mPaint = new Paint();
public void updateBitmap(List<Point> points) {
while (!points.isEmpty()) {
int x = points.get(0).x;
int y = points.get(0).y;
mCanvas.drawPoint(x, y, mPaint);
points.remove(0);
}
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, null);
}
}
The thread that draws the points calls updateBitmap, passing it the current list of points to draw. These points are then removed from the list so they will not be drawn again later on.
Related
I have an Activity in which the user touches the eye positions on a picture, and this is supposed to draw a little white circle over each. I have a working bit of code that, using the Android FaceDetector tools, finds the eye positions and facial midpoint and draws a rectangle. The drawing part of that code, for reference, is this:
private void drawRectangles(){
Canvas canvas = new Canvas(mBitmap);
Paint paint = new Paint();
paint.setStrokeWidth(2);
paint.setColor(Color.BLUE);
paint.setStyle(Style.STROKE);
for (int i=0; i < faceFrames.length; i++) {
RectF r = faceFrames[i];
if (r != null){
canvas.drawRect(r, paint);
Log.d(TAG, "Drew rectangle");
}
}
mImageView.setImageResource(0);
mImageView.setImageBitmap(mBitmap);
mImageView.draw(canvas);
}
That part's fine. I figured, as a method that is called from onTouchEvent, that I could use the following to draw a circle:
private void makeDrawableLayer(int x, int y, int touchCount){
if (touchCount == 1){
Bitmap eyeOneBmp = Bitmap.createBitmap(mBitmap);
Canvas c1 = new Canvas(eyeOneBmp);
c1.drawCircle(x, y, 5, eyePaint);
mImageView.setImageResource(0);
mImageView.setImageBitmap(eyeOneBmp);
mImageView.draw(c1);
}
}
Here are screen shots showing the result of each code snippet. The first picture is the rectangle drawn on the face. The second picture shows the very strange result I get when I attempt to draw using the second code snippet. Note, however, that I had specified x and y as 10, 10 for the circle's position when drawing the second output. It's the same thing when I give it the passed-in eye position coordinates, just with the pixelated circle coming from wherever the eye is.
Does anyone have any idea what the heck is going on with this behavior?
Thanks so much.
So I found that you can basically only draw one time to the canvas before needing to make a class that extends View to start calling methods from. What I ended up needing to do was: customView.prepareCircle(), customView.invalidate(), and then parentView.addView(customView). And actually, I could only prepare, invalidate, and re-add the modified custom view to the canvas once before having to make any subsequent calls from a Runnable on the UI thread. I am not under the impression this is an ideal way to do it (certainly doesn't feel elegant), but it is giving me the results I want:
This link: http://www.mediafire.com/view/?hr441qalu6b6d7s
points to an image that show that my drawing of Bitmaps is taking a long time and resulting in lag in my application. How can I optimize this so as not to cause so much lag. Currently I have this as my canvas method:
Canvas c = holder.lockCanvas();
Paint p = new Paint();
p.setTextSize(30);
p.setColor(Color.BLACK);
new handleStuff().execute("");
//Actions End
//Background
Bitmap scaledBackground = Bitmap.createScaledBitmap(background, this.getWidth(), this.getHeight(), true);
c.drawBitmap(scaledBackground, 0, 0, null);
//Background End
My initial thoughts are that the drawing of the background every single time is what is causing that lag, but I am not sure.
Put all object creation outside of the draw method (so only create the bmp/paint etc in your init/whatever) and then use them in the draw method.
This will speed up thing and reduce memory use and reduce garbage collection ... a lot.
I have an application which requires me to draw paths to a canvas. As the number of paths builds up, the cumulative drawing action takes longer, so I thought I would improve speed by using the drawing cache.
To do this I have an onDraw method looking a bit like this:
#Override
protected void onDraw(Canvas canvas) {
Path path;
Paint paint;
synchronized(mPaths) {
buildDrawingCache();
Bitmap bmp = getDrawingCache();
if(bmp!=null) canvas.drawBitmap(bmp,
new Rect(0, 0, bmp.getWidth(), bmp.getHeight()),
new Rect(getLeft(), getTop(), getRight(), getBottom()),
null);
for(int i=mLastCount; i<mPaths.size(); ++i) {
path = mPaths.get(i);
paint = mPaints.get(i);
canvas.drawPath(path, paint);
}
mLastCount = 0;
mDrawn = true;
destroyDrawingCache();
}
}
mPaths and mPaints are lists of Path and Paint objects and I have a method set up to work out how many are new so it only redraws the last one. I originally called setDrawingCacheEnabled(true) instead of buildDrawingCache() and destroyDrawingCache() but this didn't work (that may be significant).
Anyway, this code works—it produces a bitmap which I can write to the canvas, then I only draw the last path and everything is fine except that as I draw more and more paths, it still slows down, as though it were still redrawing all the paths during buildDrawingCache().
Is that what's happening? Ideally I would like the draw method to be blitting a bitmap, then placing a single path over it. If it's generating the bitmap from all the paths, every time, I might as well not bother (in fact I will probably write my own bitmap generation code if this is the case, but it seems a pain).
If it isn't what's happening, is there something else that could be causing the code to slow down?
I am learning android Live wallpaper development. I found an awesome template in the AndEngine Forums
In this template I found an overridable method OnTab which provides 2 parameters i.e x coordintate & y coordinate .
protected void onTap(final int pX, final int pY)
{
SurfaceHolder holder= //Get current surface holder object
Paint paint = new Paint();
Canvas canvas= holder.lockCanvas();
paint.setColor(Color.WHITE);
canvas.drawCircle(20, 50, 25, paint);
}
I want to draw a circle when user tabs or touches the screen but i am finding it difficult to get the sufaceholder object which will let me draw a circle on the canvas Or can i achieve this some other way?
You need to do the drawing within the onDraw() method. When a touch is occurring you should save the X and Y location and then in the onDraw() method draw the circle.
I have this sprite rotating algorithm (its poorly named and just used for testing). It is so close, sprites drawn with it do rotate. Everyframe I can add +5 degrees to it and see my nice little sprite rotate around. The problem is, the other stuff drawn to the canvas now flickers. If I don't do the rotation the regular drawn sprites work great. I think I am close but I just don't know what piece I am missing. Below is my two "Draw_Sprite" methods, one just draws the previously resource loaded bitmap to the canvas passed in. The other one, does some rotation the best I know how to rotate the sprite by so x many degrees..and then draw it. If I have a nice game loop that draws several objects, one type is the rotated kind. Then the non-rotated sprites flicker and yet the rotated sprite never does. Though if I draw the non-rotated sprites first, all is well, but then the Z-Ordering could be messed up (sprites on top of UI elements etc)... The method definitions:
/*************************************************
* rotated sprite, ignore the whatever, its for ease of use and testing to have this argument list
* #param c canvas to draw on.
* #param whatever ignore
* #param rot degrees to rotate
* #return
*/
public int Draw_Sprite(Canvas c, int whatever, int rot) {
//rotating sprite
Rect src = new Rect(0, 0, width, height);
Rect dst = new Rect(x, y, x + width, y + height);
Matrix orig = c.getMatrix();
mMatrix = orig;
orig.setTranslate(0, 0);
orig.postRotate(rot, x+width/2, y+height/2);
c.setMatrix(orig);
c.drawBitmap(images[curr_frame], src, dst, null);
c.setMatrix(mMatrix); //set it back so all things afterwards are displayed correctly.
isScaled=false;
return 1;
}
/********************************************************
* draw a regular sprite to canvas c
* #param c
* #return
*/
public int Draw_Sprite(Canvas c) {
Rect src = new Rect(0, 0, width, height);
Rect dst = new Rect(x, y, x + width, y + height);
c.drawBitmap(images[curr_frame], src, dst, null);
isScaled=false;
return 1;
}
And now the usage:
void onDraw(Canvas c)
{
canvas.drawRect( bgRect, bgPaint); //draw the background
//draw all game objects
// draw the normal items
for (GameEntity graphic : _graphics) {
graphic.toScreenCoords((int)player_x, (int)player_y);
if(graphic.getType().equals("planet")) //draw planets
graphic.Draw_Sprite(canvas); //before the rotation call draws fine
else
{
//rotate all space ships every frame so i see them spinning
//test rotation
mRot +=5;
if(mRot>=360)
mRot=0;
graphic.Draw_Sprite(canvas, 0, mRot); //yes function name will be better in future. this rotates spins draws fine
}
}
thePlayer.Draw_Sprite(canvas); //FLICKERS
drawUI(canvas);//all things here flickr
}
So it does do it, things after a call to a rotational draw are drawn correctly. But the problem is it flickrs. Now One could say I should just do all my non rotational stuff and save that last, but the zordering would be off.... suggestions as to how to tackle this issue of zordering or the flickering?
Just for the next guy who may read this. You can do this with only a few lines of code:
canvas.save();
canvas.rotate(rotation_angle, x + (widthofimage / 2), y + (heightofimage / 2));
canvas.drawBitmap(bitmap, x, y, null);
canvas.restore();
Try using canvas.save() before the rotation and canvas.restore() after manipulation is complete.
When performing manipulations on the canvas in order to change the way an object is drawn you have to remember the manipulations set how the canvas handles origins etc... So if you translate or rotate the canvas, that will be set for the lifetime of that canvas. In order to avoid this you first call save, which saves a snapshot of the canvas matrix before you manipulate it, then you run all your changes, then call restore which will restore the canvas back to the last saved point. Otherwise all your changes build up and you get unintended results.