I am trying to drawn on a TextureView with a canvas in Android. I am doing it inside a thread but for some reason, when I try to run my program, I am getting a null pointer exception. I have implemented my thread in the surfaceAvailable() callback but I'm still unable to draw. What could I be doing wrong?
This is what i tried so far:
public class MainActivity extends Activity implements TextureView.SurfaceTextureListener, Camera.PreviewCallback {
private Camera mCamera;
private TextureView mTextureView;
Context mContext;
private int[] pixels = null;
private ImageView imageView;
private MainActivity.RenderingThread mThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
imageView = new ImageView(this);
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);
setContentView(mTextureView);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
int screenWidth = displayMetrics.widthPixels;
int screenHeight = displayMetrics.heightPixels;
int mPreviewRate = Math.round((float)screenHeight / (float)screenWidth);
mCamera = Camera.open();
Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
mTextureView.setLayoutParams(new FrameLayout.LayoutParams(
previewSize.width*mPreviewRate, previewSize.height*mPreviewRate, Gravity.CENTER));
try {
mCamera.setPreviewTexture(surface);
} catch (IOException t) {
}
mCamera.startPreview();
mTextureView.setAlpha(1.0f);
mTextureView.setRotation(90.0f);
mThread = new RenderingThread(mTextureView);
mThread.start();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Ignored, the Camera does all the work for us
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
mCamera.stopPreview();
mCamera.release();
if (mThread != null) mThread.stopRendering();
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Update your view here!
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
}
private static class RenderingThread extends Thread {
private final TextureView mSurface;
private volatile boolean mRunning = true;
public RenderingThread(TextureView surface) {
mSurface = surface;
}
@Override
public void run() {
float x = 0.0f;
float y = 0.0f;
float speedX = 5.0f;
float speedY = 3.0f;
Paint paint = new Paint();
paint.setColor(0xff00ff00);
while (mRunning && !Thread.interrupted()) {
final Canvas canvas = mSurface.lockCanvas(null);
try {
canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
canvas.drawRect(x, y, x + 20.0f, y + 20.0f, paint);
} finally {
mSurface.unlockCanvasAndPost(canvas);
}
if (x + 20.0f + speedX >= mSurface.getWidth() || x + speedX <= 0.0f) {
speedX = -speedX;
}
if (y + 20.0f + speedY >= mSurface.getHeight() || y + speedY <= 0.0f) {
speedY = -speedY;
}
x += speedX;
y += speedY;
try {
Thread.sleep(15);
} catch (InterruptedException e) {
// Interrupted
}
}
}
void stopRendering() {
interrupt();
mRunning = false;
}
}
}
This is my stacktrace:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int, android.graphics.PorterDuff$Mode)' on a null object reference
I believe the problem is here:
final Canvas canvas = mSurface.lockCanvas(null);
Take a look at the official documentation:
lockCanvas
public abstract Canvas lockCanvas ()
Start editing the pixels in the surface. The returned Canvas can be used to draw into the surface's bitmap. A null is returned if the surface has not been created or otherwise cannot be edited. You will usually need to implement Callback.surfaceCreated to find out when the Surface is available for use.
You might be trying to draw on a surface before it has been created. In this case, you must make sure that lockCanvas() is only called after the surface is ready (listen for the surface creation). Also, in your case, you should use the lockCanvas() without arguments, like this:
final Canvas canvas = mSurface.lockCanvas();
User contributions licensed under CC BY-SA 3.0