android studio debugging identifying cause
Android studio debugging identifying cause – Introduction
The android studio debugging identifying cause tutorial episode explains some steps for helping to identify the cause of a suspected bug.
Android studio debugging step
Software debugging can be considered a black art by some. Which usually involves many years of experience accumulating in almost instinctive diagnostic abilities.
But for those starting off it’s good to setup a systematic framework for following.
Here is something that I would generally normally follow.
- Confirm there is an issue
- Check the android studio monitor debug trace
- See if you can find the line of code the android studio debug trace is pointing to
- Refer to the android SDK documentation from android studio
- Setup some break points in android studio help isolate the cause of the problem
- Insert debug logs in specific places to help confirm application behaviour
Confirm there is an issue
I do my testing and bug verification on a Nexus device running the latest version of android OS. If I cannot reproduce the issue on my environment I will have to reject the issue.
As an exception to the rule I will be using the Samsung Note 4 device as will to check if the issue can reproduced.
Check the android studio monitor debug trace
Below is a trace of the debug from the Samsung Note 4.
From the debug we can see we are getting an illegalStateException, which is our first clue.
See if you can find the line of code the android studio debug trace is pointing to
In my example you may see this line
mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
It’s also telling us the camera device has been closed. Which indicates something has gone wrong and the application is not functional without a configured camera device.
Refer to the android SDK documentation from android studio
Now I will look at the documentation for the CameraDevice createCaptureRequest method. And inside the documentation look for any reasons I may be getting a illegalStateException.
The documentation explains that we get a illegalStateException when the CameraDevice is closed. So lets go to the next CameraDevice method being called, the createCaptureSession. Go to the class documentation and look for the keyword illegalStateException.
The onClose method is interesting. It’s job is to free up the output surfaces so they can be reused for the next session. It gets called when a new capture session is created.
Setup some break points in android studio help isolate the cause of the problem
I’m going to put a break point on this line
mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
I want to check of the CameraDevice is still configured. And if there are any strange null objects.
From stepping part that line we can see that we get our illegalStateException straight away. But the CameraDevice object was configured. Let’s try something different and add some debug trace.
Insert debug logs in specific places to help confirm application behaviour
Now we are going to add some debug logs to be displayed in debug mode. It’s a good idea to remove these once the bug has been resolved.
Let’s add a TAG first.
private static final String TAG = "Camera2VideoImageActivity";
Now in CameraCaptureSession class, close method this documentation gives me some clues
Closing a session frees up the target output Surfaces of the session for reuse with either a new session, or to other APIs that can draw to Surfaces.
Note that creating a new capture session with createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)
will close any existing capture session automatically, and call the older session listener’s onClosed(CameraCaptureSession)
callback
My suspicion is what if the record session close method is not being called before the preview session is being created? The target output surfaces would not be available and I suspect could result in an illegalStateException.
Lets verify this behaviour with some debug logs.
Implementing debug logging
Setup a TAG member for your activity
private static final String TAG = "Camera2VideoImage";
Add debug logging to the preview & record capture sessions when starting & closing
private void startPreview() { SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture(); surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); Surface previewSurface = new Surface(surfaceTexture); try { mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mCaptureRequestBuilder.addTarget(previewSurface); mCameraDevice.createCaptureSession(Arrays.asList(previewSurface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { Log.d(TAG, "PS"); try { session.setRepeatingRequest(mCaptureRequestBuilder.build(), null, mBackgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(CameraCaptureSession session) { Toast.makeText(getApplicationContext(), "Unable to setup camera preview", Toast.LENGTH_SHORT).show(); } @Override public void onClosed(CameraCaptureSession session) { super.onClosed(session); Log.d(TAG, "PC"); } }, null); } catch (CameraAccessException e) { e.printStackTrace(); } }
private void startRecord() { try { setupMediaRecorder(); SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture(); surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); Surface previewSurface = new Surface(surfaceTexture); Surface recordSurface = mMediaRecorder.getSurface(); mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); mCaptureRequestBuilder.addTarget(previewSurface); mCaptureRequestBuilder.addTarget(recordSurface); mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, recordSurface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { Log.d(TAG, "RS"); try { session.setRepeatingRequest( mCaptureRequestBuilder.build(), null, null ); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(CameraCaptureSession session) { } @Override public void onClosed(CameraCaptureSession session) { super.onClosed(session); Log.d(TAG, "RC"); } }, null); } catch (Exception e) { e.printStackTrace(); } }
It’s a good idea to verify this code on a known system to check the expected behaviour. So I’ll run it on the Nexus 5x first and then the Samsung Note 4.
With the Nexus 5x the behaviour is expected. And we are seeing the previous session close() method called prior to the new session onConfigured() member being called.
With the Samsung Note 4 with are seeing the preview session starting & closed prior to the record session starting. But we on not seeing the record session onClosed() method called. This could result in the output surfaces not being released and made available for the preview session. Resulting in the illegalStateException noted in the camera2 documentation.
Outcome
At this stage we believe we have identified the problem which only happens on the Samsung Note 4 (Series 5?). The issues seems to be with either lollipop OS, or the Samsung Note 4 or even a combination of both.
It could be a timing issue and I have known people put timeouts delays in their code which has good results. But I will be providing an alternative solution in the following tutorial.
Android studio debugging identifying cause summary
In the android studio debugging identifying cause tutorial we learnt that android application debugging can be a significant task.
It can be expressed a black art which the experts have many years experience in the field and have almost a sixth sense in identifying the problem.
But for those starting out it is good to have a systematic approach. To which I have provided an example above.
To conclude android debugging can take time and requires perseverance & persistence. And it can be often a good idea to view the problem from different angles and levels.