In this really simple mini-project, we will really harness the power of classes and objects by using classes from the Android API which allow us to draw graphics on the screen. We will see how we can draw shapes, lines, pixels, text, and even custom-designed graphics like game characters. We will do all of this by making objects of other people’s classes. We are then a big step closer to building our first real game.
Create a new Android Studio project, call it Graphics Demo with a blank Activity called GraphicsDemoActivity. Delete all the code in GraphicsDemoActivity.java and enter the code below. Notice it has a few differences from our previous mini-projects. Also, note that your project will have errors until we enter the rest of the code. Also, I have listed all the import... code. Remember you can either type this in now or wait until we use the appropriate class and press the Alt|Enter keyboard combination to enter the import... line automatically.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.os.Bundle; import android.widget.ImageView; public class GraphicsDemoActivity extends Activity { ImageView ourView; // This is the entry point to our game @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Do all our drawing in a separate method draw(); // Make ourView ImageView object the view for the Activity setContentView(ourView); } } |
Notice that immediately below the class declaration we declare an object of the type ImageView called ourView. It is this ImgaeView class, provided by Android that we will use to draw upon. So why did we declare it outside of any method? The reason we did this is so that any methods in the class can “see” and use the method. Up until now, we have declared all of our objects and other variables in a method. We will not only use ourView in the onCreate method but also our draw method. Declaring it here makes this possible. This is called a member variable.
The next new thing in our code is the call to the draw method. This is a method that we will create in a moment and will draw on ourView. Notice then that we use the setContentView method just like all the other mini-projects but this time we pass in ourView. This makes whatever we draw upon ourView appear on the screen. So let’s get on and implement our draw method.
Before we get coding we want to add a cute character graphic to our project files so we can use it in our drawing code. Meet Bob.
You can download Bob by right-clicking on the image and selecting Save image as… Just make sure the file is named bob.png. Add the bob bitmap to the drawable folder in your Android Studio folders by dragging it there just like you would move any other file between folders on your PC. The drawable folder is shown in the next image.
Now let’s implement our draw method. I am going to show you all the code at once so you can examine it and run it right away. We will dissect how it works when we have seen it in action. Enter the code as shown below. Make sure you do so just before the final closing curly brace } of the GraphicsDemoActivity class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
// This is our draw() method public void draw(){ // Declare an object of type Bitmap Bitmap blankBitmap; // Make it 600 x 600 pixels in size and an appropriate format blankBitmap = Bitmap.createBitmap(600,600,Bitmap.Config.ARGB_8888); // Declare an object of type canvas Canvas canvas; // Initialize it by making its surface our previously created blank bitmap canvas = new Canvas(blankBitmap); // Initialize our previously declared member object of type ImageView ourView = new ImageView(this); // Put our blank bitmap on ourView ourView.setImageBitmap(blankBitmap); // We now have a surface ready to draw on // But we need something to draw with // Declare an object of type Paint Paint paint; // Initialize it ready for painting our canvas paint = new Paint(); // Make the canvas white canvas.drawColor(Color.argb(255, 255, 255, 255)); // Make the brush blue paint.setColor(Color.argb(255, 26, 128, 182)); // We can change this around as well // Declare an object of type Bitmap Bitmap bitmapBob; // Initialize it using the bob.png file bitmapBob = BitmapFactory.decodeResource(this.getResources(), R.drawable.bob); // Now draw bob to our canvas canvas.drawBitmap(bitmapBob, 500, 50, paint); // Draw a line canvas.drawLine(50,50,250,250,paint); // Draw some text canvas.drawText("Game Code School", 50, 50, paint); // Draw a pixel canvas.drawPoint(40,50,paint); // Draw a circle canvas.drawCircle(350,250,100,paint); // Change the brush color paint.setColor(Color.argb(255, 249, 129, 0)); // Draw a rectangle canvas.drawRect(50,450,500,550,paint); // Back to onCreate method to set our canvas as the view } |
Here is what the code does chunk by chunk.
First, we have our method signature and the opening curly brace {.
1 2 |
// This is our draw() method public void draw(){ |
Next, we do a number of things to create a virtual canvas on which to draw. If you try to imagine the internal workings of a graphics card and its relationship to the CPU and the complexity of how our graphics are stored in memory and then represented on the device screen it might give you a headache- it’s not simple. But what these four lines (excluding comments) do is vastly simplify the whole thing.
We create an object of type Bitmap, which we can think of as a blank graphic to draw upon. First, we declare it and then we initialize it using the createBitmap method. The method parameters are 600, 600, Config.ARGB_888, which are the length, width, and format of the bitmap.
Then we declare an object of type Canvas and immediately initialize it- with our blank Bitmap object. Here is that code again we will see how we use this new object of type Canvas really soon.
1 2 3 4 5 6 7 8 |
// Declare an object of type Bitmap Bitmap blankBitmap; // Make it 600 x 600 pixels in size and an appropriate format blankBitmap = Bitmap.createBitmap(600,600,Bitmap.Config.ARGB_8888); // Declare an object of type canvas Canvas canvas; // Initialize it by making its surface our previously created blank bitmap canvas = new Canvas(blankBitmap); |
Below we initialize ourView which is an ImageView object. Then we set blankBitmap as its image. Now anything we do with canvas will appear on ourView which you might remember we set as the view for the entire program in the onCreate method.
1 2 3 4 5 6 7 |
// Initialize our previously declared member object of type ImageView ourView = new ImageView(this); // Put our blank bitmap on ourView ourView.setImageBitmap(blankBitmap); // We now have a surface ready to draw on // But we need something to draw with |
Now we declare and initialize an object of the type Paint which perhaps unsurprisingly will allow us to paint on our canvas object.
1 2 3 4 |
// Declare an object of type Paint Paint paint; // Initialize it ready for painting our canvas paint = new Paint(); |
Below we draw the entire screen as white using the drawColor method and we set the color of the brush we will be using in a moment to Game Code School blue. The four numbers that we use represent the level of transparency, red, green, and blue. If you have not come across the RGB color model before it is simply a way of describing a color using amounts of transparency, red, green, and blue with values between 0 and 255.
1 2 3 4 5 6 |
// Make the canvas white canvas.drawColor(Color.argb(255, 255, 255, 255)); // Make the brush blue paint.setColor(Color.argb(255, 26, 128, 182)); // We can change this around as well |
Next, we declare another Bitmap object and then use the decodeResource() method to decode our bob.png file into a format suitable for use in our bitmapBob. Then we get to see our canvas object in action. we call the drawBitmap method of the Canvas class. The parameters are the bitmap to draw ( bitmapBob), the x,y screen location ( 500, 50) and our Paint object ( paint).
1 2 3 4 5 6 |
// Declare an object of type Bitmap Bitmap bitmapBob; // Initialize it using the bob.png file bitmapBob = BitmapFactory.decodeResource(this.getResources(), R.drawable.bob); // Now draw bob to our canvas canvas.drawBitmap(bitmapBob, 500, 50, paint); |
Now we draw a line with drawLine and the numbers represent the starting and ending x,y coordinates of the line. Next in the code below, we use drawText to perhaps unsurprisingly draw a String at a specific x,y location. After that, we draw a single pixel with drawPoint. Again we pass in the x, y location where we want the point and our object, paint.
1 2 3 4 5 6 7 8 |
// Draw a line canvas.drawLine(50,50,250,250,paint); // Draw some text canvas.drawText("Game Code School", 50, 50, paint); // Draw a pixel canvas.drawPoint(40,50,paint); |
[widgets_on_pages id=”udemy_advert_java_3″][widgets_on_pages id=”udemy_code_details”]
We see next that we can also draw shapes like circles and rectangles with the respective methods of the
Canvas class. Notice in between we change the color that we draw the rectangle with the
setColor method. The parameters of
drawCircle are the x, y screen location followed by the radius. The parameters of
drawRect are the left, top, right, and bottom locations that represent the rectangle.
1 2 3 4 5 6 7 8 |
// Draw a circle canvas.drawCircle(350,250,100,paint); // Change the brush color paint.setColor(Color.argb(255, 249, 129, 0)); // Draw a rectangle canvas.drawRect(50,450,500,550,paint); |
Finally, we end the draw method with a closing curly brace } and execution returns to the onCreate method where you might remember we call setContentView(ourView) which displays all our lovely doodling on the screen.
1 2 3 |
// Back to onCreate method to set our canvas as the view } |
Run the code on an Android device if you haven’t already.
Having achieved what we just have it should not be too hard to imagine replacing the coordinates we used to draw our graphics with variables. We could then manipulate those variables to make them move, perhaps in some kind of loop. Now we are able to draw pixels, shapes, text for perhaps a game’s GUI, and bitmaps that can be used like sprites, we are so close to our first real game project I can nearly smell it.
Before we do we just need a little bit more Java knowledge. The logical next step is Handling game data with Java arrays.
I am currently learning Android Studio to be able to run through your tutorials. I continue to receive the error “Error:Execution failed for task ‘:app:mergeDebugResources’.> Crunching Cruncher bob.png failed, see logs” I placed the bob.png file into the res/drawable class. I am hoping there is someone that has had the same problem and could possible help me out.
This sounds like an error to do with versions. Try restarting Android Studio.
If not, check your java files are in the java/com.yourdomain.yourproject and NOT java/com.yourdomain.yourproject(androidTest). Check this using the Android Studio project explorer window (the one on the left) not using your OS file browser.
As a last resort, start again with a fresh project and copy-paste the code again.
Hope this helps.
Hello John! I am having a problem on display. My emulator screen doesn’t show Bob! All other images are working fine. Bob is not there.
What can be the problem?
Double check bob.png is in the drawable folder and not misspelt in the file name or the code. If not, try Tools | Android | Sync Project with Gradle Files. Good luck.
Hey John! Can you please tell me what’s wrong with this? My android studio is showing that there are 2 errors. Can you please put strain on your eyes and tell me what it is?
package com.developer.swapnil.graphicsdemo;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.widget.ImageView;
public class GraphicsDemoActivity extends Activity {
ImageView ourView;
// This is the entry point to our game
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Do all our drawing in a separate method
draw();
// Make ourView ImageView object the view for the Activity
setContentView(ourView);
// This is our draw() method
public void draw() {
// Declare an object of type Bitmap
Bitmap blankBitmap;
// Make it 600 x 600 pixels in size and an appropriate format
blankBitmap = Bitmap.createBitmap(600, 600, Bitmap.Config.ARGB_8888);
// Declare an object of type canvas
Canvas canvas;
// Initialize it by making its surface our previously created blank bitmap
canvas = new Canvas(blankBitmap);
// Initialize our previously declared member object of type ImageView
ourView = new ImageView(this);
// Put our blank bitmap on ourView
ourView.setImageBitmap(blankBitmap);
// We now have a surface ready to draw on
// But we need something to draw with
// Declare an object of type Paint
Paint paint;
// Initialize it ready for painting our canvas
paint = new Paint();
// Make the canvas white
canvas.drawColor(Color.argb(255, 255, 255, 255));
// Make the brush blue
paint.setColor(Color.argb(255, 26, 128, 182));
// We can change this around as well
// Declare an object of type Bitmap
Bitmap bitmapBob;
// Initialize it using the bob.png file
bitmapBob = BitmapFactory.decodeResource(this.getResources(), R.drawable.bob);
// Now draw bob to our canvas
canvas.drawBitmap(bitmapBob, 500, 50, paint);
// Draw a line
canvas.drawLine(50, 50, 250, 250, paint);
// Draw some text
canvas.drawText(“Game Code School”, 50, 50, paint);
// Draw a pixel
canvas.drawPoint(40, 50, paint);
// Draw a circle
canvas.drawCircle(350, 250, 100, paint);
// Change the brush color
paint.setColor(Color.argb(255, 249, 129, 0));
// Draw a rectangle
canvas.drawRect(50, 450, 500, 550, paint);
// Back to onCreate method to set our canvas as the view
}
}
Hi there,
I can’t see anything wrong with the code. Try copy/pasting the code from the page because that definitely works. Then let me know which specific errors you get. Thanks for your comment.
The first error is: // Make ourView ImageView object the view for the Activity
setContentView(ourView);
After the semicolon of the above line, it is showing that a ‘}’ is expected
The second error is: Cannot resolve symbol ‘bob’
Thanks in advance for looking into this.
Hi Swapnil, to be honest I’m a little babaffled with the first error. I have pasted the code today and it seems to be working. Can I suggest starting again incase there is aproject setting that is wrong. Then copy paste all the code. There will probably be errors until it is all coded.
Regarding the bob error this is usually caused by a mispelling or the the graphic being in the wrong folder. Make sure to add the graphic into the drawable folder in Android Studio Solution Explorer window directly and not using the OS (windows explorer etc).
I hope this helps. If not, let me know and I will try and think of something else.
Good luck, John.
‘Make sure to add the graphic into the drawable folder in Android Studio Solution Explorer window directly’— How to do this?
Hi Swapnil, “Add the bob bitmap to the drawable folder in your Android Studio folders by dragging it there just like you would move any other file between folders on you PC.”. My previous comment was making sure that you were locating the folder in Android Studio, on the left-hand side, in the window labeled Solution Explorer, rather than by using your operating system’s file manager.
Hi again,
I just launched Android Studio and I am uploading a screen shot of the area in a few minutes. I will place it near the beginning of the tutorial. Hope this helps.
Thank you so much John. I followed your instructions and solved both the problems.
The thing which I have never said you is that your tutorials are real great. After searching a lot I got your tutorials. Thank you again for putting up such great tutorials.
Now I need to ask something about the codes::
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Can you tell me what’s the use and significance of this above program code ?
Hi Swapnil, really pleased it is working at last.
To understand the code in full is a lengthy topic but here is a summary. Do, follow the links if you want to find out more.
onCreate is a method. The interesting thing about this method is that it is not “our” method. It is provided as part of the Android API and we are overriding it, hence the @Override. This enables the Andoid operating system to choose when it needs to call/execute onCreate and it does so whenever the app needs to be newly created. That is why our apps always have an onCreate method that is overriden.
The line super.onCreate(savedInstanceState) means that before our overriden/modified version of onCreate is executed, the super class/original version is executed. This means that our code runs after some code provided as part of Android. The onCreate method is part of the Android Activity lifecycle.
Hope this helps a bit.
Thanks man. You made my day!
Keep up the good work.
And can you please explain BitmapFactory a little bit.
Thanks!:)
Hi Rishabh, Thanks for your message. BitmapFactory is a class that contains static methods which is why we can do so much with it, without having an instance of it. You can do quite allot with it apart from simply loading from a file. You can for example load a specific set of coordinates, perhaps if you are preparing to animate from a sprite sheet. Take a look at the official docs, it is always a good idea because they reveal much more than just a tutorial like this can. https://developer.android.com/reference/android/graphics/BitmapFactory.html
Hi
when ever I run a project I’m getting this error message “terminate called after throwing an instance of ‘std::logic_error what(): basic_string::_S_construct null not valid”. how do I go about solving this.
kind regards
Hi Clifford,
I’m a bit baffled by your error. Doesn’t even sound Java/Android related. Are you using Android Studio? I would try starting a new project and try using “Empty Activity” project template.
Hi John
I’m using Android studio 2.1 and windows 10, i re-started a new project but i get same error massage. i will try to install older versions of Android Studio and see if i will get same results.
regards
Hi Clifford, Just a long-shot but when you make the new application, which Activity template do you use?
Hi John
I started with the empty activity and I even tried using the basic activity.
kind regards
Hi Clifford,
I really am stuck. The error you give reminds me of an error you might get when using C++ or maybe Android NDK. But if you are using empty Activity this shouldn’t be possible. The only thing I can suggest is trying a totally different project. Try the simplest possible Android project and if you get the same error then something fundamental is going on. Try this tutorial basic tutorial and if you get the same error then I would consider reinstalling your development environment. If it works then try this tutorial again.
Hi John
I Finally fixed the problem, I had to change ANDROID_SDK_ROOT from this C:\Users\\AppData\Local\Android to this C:\Users\\AppData\Local\Android\sdk.
Finally though, thanks for everything.
So pleased this is resolved Clifford. Well done and have fun.
Hi John
I’ve got the problem with compilation, got error : package R does not exist
in this lane
bitmapBob = BitmapFactory.decodeResource(this.getResources(), R.drawable.bob);
It means something, usually in one of the generated files is causing the R package not to compile. Assuming you haven’t changed anything from one of the layout files, try Tools | Android | Invalidate cache and restart. Or as a last resort, start a new project and paste the code in.
Let me know how you get on, I will try and help.
Hello John.
I have got errors when trying to run the app.
It said Error:(28, 9) error: illegal start of expression and Error:Execution failed for task ‘:app:compileDebugJavaWithJavac’.
> Compilation failed; see the compiler error output for details.
Many thanks.
Hi there,
My best guess is a syntax error. Look around line 28(as well as a bit before and after) and make sure there isn’t a missing bracket/semicolon/misspelling.
Let me know how you get on.
Hi again.
It is weird, I’ve checked the whole code and it seems nothing is wrong. I clicked the error report and it is refering to this ” public void draw(){ ” line
This is my whole code:
package com.gamecodeschool.graphicsdemo;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.widget.ImageView;
public class GraphicsDemoActivity extends Activity {
ImageView ourView;
// This is the entry point to our game
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Do all our drawing in a separate method
draw();
// Make ourView ImageView object the view for the Activity
setContentView(ourView);
// This is our draw() method
public void draw(){
// Declare an object of type Bitmap
Bitmap blankBitmap;
// Make it 600 x 600 pixels in size and an appropriate format
blankBitmap = Bitmap.createBitmap(600,600,Bitmap.Config.ARGB_8888);
// Declare an object of type canvas
Canvas canvas;
// Initialize it by making its surface our previously created blank bitmap
canvas = new Canvas(blankBitmap);
// Initialize our previously declared member object of type ImageView
ourView = new ImageView(this);
// Put our blank bitmap on ourView
ourView.setImageBitmap(blankBitmap);
// We now have a surface ready to draw on
// But we need something to draw with
// Declare an object of type Paint
Paint paint;
// Initialize it ready for painting our canvas
paint = new Paint();
// Make the canvas white
canvas.drawColor(Color.argb(255, 255, 255, 255));
// Make the brush blue
paint.setColor(Color.argb(255, 26, 128, 182));
// We can change this around as well
// Declare an object of type Bitmap
Bitmap bitmapBob;
// Initialize it using the bob.png file
bitmapBob = BitmapFactory.decodeResource(this.getResources(), R.drawable.bob);
// Now draw bob to our canvas
canvas.drawBitmap(bitmapBob, 500, 50, paint);
// Draw a line
canvas.drawLine(50,50,250,250,paint);
// Draw some text
canvas.drawText(“Game Code School”, 50, 50, paint);
// Draw a pixel
canvas.drawPoint(40,50,paint);
// Draw a circle
canvas.drawCircle(350,250,100,paint);
// Change the brush color
paint.setColor(Color.argb(255, 249, 129, 0));
// Draw a rectangle
canvas.drawRect(50,450,500,550,paint);
// Back to onCreate method to set our canvas as the view
}
}
}
I think you have coded the draw method inside the closing brace } of the onCreate method instead of inside the closing brace of the class. Copy paste the class again from the top of the tutorial and then very carefully copy and paste the draw method outside onCreate but inside the class.
Hope this helps.
Ah you are right, thank you for pointing that out and thank you for a great tutorial
It’s a pity you don’t have a donate button! I’d definitely donate to this fantastic blog!
I do. Here it is. https://www.patreon.com/Gamecodeschool
Along with a sound understanding of the above concepts, you have a great teaching and explaining skills as well!
Best wishes to you!
Thanks Rahul.
So what exactly you mean by “Blank activity”: A) No activity B) Empty activity C) Basic activity ?
Hi Lux, “Empty Activity” is best. Android Studio had its options updated about 9 months ago. I am updating all the Android tutorials today. Thanks for the nudge.
Thanks to you….
The activity “GraphicDemoActivity” is not declared in AndroidManifiest.xml… whatas that error?
Error prompts when i right click the code to “Run GraphicDemoActivity” … havent been able to run it but i guess it is gonna ask me “in which virtual machine” i want to run that code…
This might be caused by a slight difference between the name of the class you chose when you created the project and the name of the class in the class declaration in the Java code. Graphic/Graphics
maybe.
Cool, then to run “activity must be exported or have intent” error prompted…. but then i went to auto fix the code with “Action View” … kind of an auto corrector that prompted me some extra code to my androidmanifiest xml file and then string value (for label) didnt exist so i needed to created it.. been able to run the avd with arm image because im AMD… BUT.. still the apk for being so simple took about 15 mins to get installed… another 15 to android to start… and another 5 for apk to draw everything… i mean… isnt a pc supposed to be most powerfull than an smartphone???
dude??
Not sure what I can add here. Try and setup USB debugging on an actual device. If you have to run it on an emulator then leave it running after start up so you don’t need to do it each time.
I already tried to add the class manually to androidmanifiest… but it says Create GraphicDemoActivity is currently not available in batch mode, user interaction is required for each problem found…
This is the second problem in the space of a few hours where I have no idea what is wrong. I would start the project again. You shouldn’t need to do anything to the manifest. Start a new project using the “empty Activity” template. Sorry, I can’t be definite.
Ahh fixed it… i think it was something related to code to be fixed manually with “intent” and action view things… didnt understand a lot about what happened but fixed it… android studio basically gave me a “Format” of activity normal code that let me ran the avd
I copy/pasted your code, it has no erros and still when i compile and run it crash and give me this code :
A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 7260 (Thread-4)
[ 11-06 17:41:44.228 1207: 1207 W/ ]
debuggerd: handling request: pid=7244 uid=10072 gid=10072 tid=7260
Application terminated.
I’m 100% sure we have exact same code…
Hi Florian. I am really sorry to say I have no idea. Are you using Android Studio and creating an “empty activity” project?
Hi john,
Consider these lines from your code-
paint.setColor(Color.argb(255,26,128,182));
canvas.drawBitmap(bitmapBob,500,50,paint);
What I understood is that this code draws an image onto the canvas. But what is the use of passing in paint object(which is set to blue color BTW) inside the method? It did not feel logical to have a blue brush drawing an image. I was expecting that the bob image would be painted in blue. However, it did not happen.
It makes absolute sense to have paint object while drawing a line/rectangle/point/circle to decide the color of the drawn shape.
A little probe into the documentation(ctrl+Q) of the drawBitmap method showed me that I can pass a “null” instead of paint object. This seems to be right to me because we don’t want to pass anything to paint in case of drawing an image from png.
I passed null in my code instead of paint and it worked!
Whats your opinion on the usage of null while drawing images(png)?
Yes, and you might even save a few milliseconds as well. I just did it without thinking but on reflection it is consistent and no harm is done. The Android tutorials are going to progress to OpenGL as soon as I get the time and Canvas/ Paint is just a good way to get started.
Thanks!