Oct 15, 2012

Using a fragment for the camera preview - Instant Mustache #4

This article is part of a series of articles about the development process of Instant Mustache, a fun camera app that adds mustaches to all faces using face detection. Click here to get a chronological list of all published articles about Instant Mustache.

This article will be the first one about writing the CameraActivity for Instant Mustache. From the last article we already know how the layout of the activity should look like. Now it's time to start the coding part.

I won't cover all the lines of code in this and the following blog articles but you can always get the complete source code of Instant Mustache at GitHub.

Using a fragment
We'll move the actual code (and layout) that handles the camera preview to a fragment. Using fragments has several advantages:

  • Fragments can be reused in different activities and layouts. Therefore they are perfect building blocks for composing UIs for different screen sizes.
  • They encapsulate the code for a specific component including the layout of the component. This makes the activity code and layout much more simpler and cleaner. By using a bunch of fragments the activity basically only has to handle events and delegate them to the appropriate fragments. This leads to the activity becoming some kind of light meta controller instead of an unreadable dumping ground for handling everything on the current screen.
  • Fragments can be dynamically added, removed, replaced, added to the back stack, animated and other cool things that can be painful to do yourself.

Activity layout
As said before we are moving the camera preview code and layout to a fragment. Therefore our activity's layout is really quite simple:

Communication between activity and fragment
There are situations where the fragment needs to notify the activity about events. In our case the fragment needs to tell the activity when it's unable to instantiate a camera preview so that the activity can handle this error case. Of course we could just access the activity inside the fragment using getActivity() and cast it to a CameraActivity object to get access to a method like onCameraError() but then our fragment would only be usable with this particular activity:

CameraActivity activity = (CameraActivity) getActivity();
activity.onCameraError();

We work around this issue by defining an interface that has to be implemented by the CameraActivity and every other component that wants to use the CameraFragment:

CameraFragmentListener.java
Every time our fragment gets attached to an activity onAttach() will be called with the activity as parameter. We use this method to enforce that the activity implements our defined interface:

CameraFragment.java
Finally take a look at the CameraActivity source code on GitHub. It just sets the layout in onCreate() and shows a toast in case of the fragment calling onCameraError(). As this method will be called in case of non-recoverable errors we'll also finish the activity.