Please refer to the textbook to fully understand and complete the section of this chapter ...
When documenting office habits, it can be much easier to solve problems if they are supported by live photographs. The next two chapters, using the system's own camera API, add the ability to shoot crime scene photos for criminalintent applications.
Although the Camera API is powerful, it's not easy to use it well. Not only to write a large number of implementation code, but also struggling to learn and understand a lot of new concepts. Therefore, it is easy to produce a question is: "Just take a snapshot, there is no convenient standard interface can be used?" ”
The answer is yes. We can interact with the camera through implicit intent. Most Android devices will have a built-in camera app. The camera app automatically listens for intent created by Mediastore.action_image_capture. The 21st chapter describes how to use implicit intent.
This chapter will create an activity based on fragment, and then use the Surfaceview class with the camera hardware to show live video previews in real time, as shown in 19-1.
Figure 19-1 Real-time preview of the camera in viewfinder
Again, we can refer to figure 19-2 for a preview of the new object that will be created later.
Figure 19-2 Object plots for the Criminalintent Application camera Section
The camera instance provides a call to the device's camera hardware level. A camera is an exclusive resource: Only one activity can invoke the camera at a time.
The Surfaceview instance is the viewfinder of the camera. Surfaceview is a special view that renders output to the device's screen directly from what will be displayed.
First, we will create the layout of the Crimecamerafragment view, the Crimecamerafragment class, and the Crimecameraactivity class. Then, create and manage a viewfinder for taking pictures in the Crimecamerafragment class. Finally, configure Crimefragment to start the crimecameraactivity instance. 19.1 Create a Fragment layout
First, in Strings.xml, add a string resource for the camera button we're about to add, as shown in Listing 19-1.
Code Listing 19-1 Adding a string resource to the camera button (Strings.xml)
Next, create a layout file named Fragment_crime_camera.xml with framelayout as the root element. Then refer to Figure 19-3 to complete the addition of each component.
Figure 19-3 Layout of crimecamerafragment (Fragment_crime_camera.xml)
As you can see, in a new layout file, Framelayout contains only one linearlayout child element, which causes Android lint to report linearlayout warning messages that are not useful. Temporarily ignoring it, the 20th chapter adds a second child view for Framelayout.
In the Surfaceview component definition, we use the property combination of Layout_width and layout_weight to lay out its child views. Because the android:layout_width= "wrap_content" property value is set, the button component consumes only the space it needs, and according to the property value of Android:layout_width= "0DP", The Surfaceview component does not occupy any space. However, from the perspective of the remaining space, because the Layout_weight attribute is used, the Surfaceview component uses all the space outside the button component.
Figure 19-4 shows the preview interface for the new layout.
Figure 19-4 Viewfinder and button interface 19.2 create crimecamerafragment
Create a new class named Crimecamerafragment with Android.support.v4.app.Fragment as the superclass. In the subsequent open Crimecamerafragment.java, add the variable as shown in Listing 19-2. Then, overwrite the Oncreateview (...) method to instantiate the layout and reference each component.
Note: Android.hardware.Camera is obsolete ,import Android. hardware. Camera;;
Now, set an event listener for the button, exit the currently hosted activity and return to the list item detail interface when the user taps the button.
Code Listing 19-2 Initial Camera fragment class (Crimecamerafragment.java)
19.3 Create Crimecameraactivity
To SingleFragmentActivity
create a new class named for the superclass CrimeCameraActivity
. In Crimecameraactivity.java, the override createFragment()
method returns one CrimeCameraFragment
, as shown in Listing 19-3.
Code Listing 19-3 Creating a Camera activity Class (Crimecameraactivity.java)
Statement Activity and add allow to call camera settings
Next, you need to add the element node in the configuration file uses-permission
to get permission to use the camera. Update the Androidmanifest.xml configuration file with reference to listing 19-4.
Code Listing 19-4 Declaring the activity of the camera and adding allow to call camera settings (Androidmanifest.xml)
uses-feature
element is used to specify a feature of a feature device used by the app. Via Android. Hardware.camera features are set up to ensure that only those devices equipped with the camera feature will be able to see the apps you post on Google Play.
Note that in the activity statement, in order to prevent the user from taking a photo at the angle of adjustment, the device screen spins freely, and we use android:screenOrientation
properties to force the activity interface to always show in horizontal mode.
Property android:screenOrientation
also has many other optional property values. For example, you can set the display orientation of activity to be consistent with its parent class, or you can choose to display only in horizontal mode based on device sensor sensing when the device is in a different direction. You can view the elements of the development document for <activity>
more information about other available property values. 19.4 using the camera API
So far, we've been working on basic activity creation. Now it's time to learn to understand camera-related concepts and start using the camera class. 19.4.1 Open and release the camera
First, the management of the camera resources. We have CrimeCameraFragment
added an instance to the Camera
. The camera is an important resource at the system level, so the key point is that it needs to be used and released in time. If you forget to release, other apps will not be able to use the camera unless you restart your device.
Here are the methods that will be used to manage Camera
instances:
public static Camera open (int cameraid)
public static Camera open ()
Public final void release ()
open(int)
This method is introduced at level 9th of the API, so if the device's API level is less than level 9th, then only the method without parameters is used open()
.
In the CrimeCameraFragment
life cycle, we should onResume()
onPause()
open and release the camera resources in and callback methods. These two methods determine the time boundary that the user can interact with the fragment view, and the camera can only be used when the user is able to interact with the fragment view. (Note that the onResume()
method will be called even if the fragment first appears on the screen.) )
In the CrimeCameraFragment.onResume()
method, use a Camera.open(int)
static method to initialize the camera. Then pass in parameter 0 to open the first camera available to the device (usually the rear camera). If the device does not have a rear-facing camera (such as a Nexus 7 model), the front camera will open.
For devices at level 8th of the API, you need to invoke a method without parameters Camera.open()
. onResume()
Use annotation protection for the method, @TargetApi
and then check the compiled version of the device, depending on the version number of the device, to determine whether to call the Camera.open(0)
method or Camera.open()
method, as shown in Listing 19-5.
Code Listing 19-5 Opening the camera in a onResume()
method (Crimecamerafragment.java)
Fragment
When destroyed, the camera resources should be released in a timely manner so that they can be used when needed by other applications. The override onPause()
method releases the camera resource, as shown in Listing 19-6.
Code Listing 19-6 Implementation life cycle approach (Crimecamerafragment.java)
Note that release()
before invoking a method, you must first make sure that there is an Camera
instance. This check should be done before calling the camera-related code. Be aware that the camera may not be available even if you request access to the camera. For example, another activity is using it, or because it is a virtual device, the camera does not exist at all. In summary, no matter what the reason, when the camera instance does not exist, a null check can prevent the app from accidentally crashing. 19.4.2 SurfaceView
, SurfaceHolder
with Surface
SurfaceView
class implements the SurfaceHolder
interface. In Crimecamerafragment.java, add the following code to get SurfaceView
the SurfaceHolder
instance, as shown in Listing 19-7.
Code Listing 19-7 Get SurfaceHolder
instance (Crimecamerafragment.java)
setType(...)
Methods and SURFACE_TYPE_PUSH_BUFFERS
constants have been deprecated, so the compiler will prompt a warning message for obsolete code. Android Studio The deprecated code is also marked with a strikethrough .
Why use them now that they are deprecated code? The camera preview works without the setType(...)
support of methods and constants on devices running prior to Honeycomb SURFACE_TYPE_PUSH_BUFFERS
. In code listing 19-7, we use @SuppressWarnings
annotations to eliminate deprecated code-related warning messages. This seems like a weird process, but it's the best way to deal with deprecated code and compatibility issues. For a more in-depth discussion of deprecated code in Android, see the Deep Learning section at the end of chapter 20th. (It may also be Google's way of promoting a new version of Android, after all, developers are not enthusiastic about it!) )
SurfaceHolder
is the link between us and Surface
the object. Surface
the object represents the buffer of the raw pixel data.
Surface
Objects also have a life cycle: they are SurfaceView
created when they appear on the screen, Surface
SurfaceView
and are destroyed when they disappear from the screen Surface
. Surface
when it does not exist, you must ensure that nothing is drawn on it.
Figure 19-5 SurfaceView
, SurfaceHolder
and Surface
Unlike other view objects, SurfaceView
and their co-working objects, they do not self-draw content. For any object that wants to draw the content into the Surface
buffer, we call it Surface
the client . In the CrimeCameraFragment
class, the Camera
instance is Surface
the client.
Remember that Surface
when it does not exist, you must ensure that nothing is Surface
drawn in the buffer. Figure 19-6 shows two possible scenarios that need to be handled, Surface
after the creation is complete, the connection will be made to the top, and Camera
SurfaceHolder
Surface
then disconnected from the top after the destruction Camera
SurfaceHolder
.
Figure 19-6 the ideal working condition
To complete the above tasks, SurfaceHolder
another interface is provided: SurfaceHolder.Callback
. This interface listens Surface
for events in the life cycle, so that it can control the Surface
work with its clients.
In Crimecamerafragment.java, the SurfaceHolder.Callback
interface is implemented so that the camera preview and Surface
life cycle methods work together, as shown in Listing 19-8.
Code Listing 19-8 Implementation SurfaceHolder.Callback
Interface (Crimecamerafragment.java)
Note that when the preview fails to start, we release the camera resource through the exception control mechanism. At any time, after opening the camera and completing the task, you must remember to release it in a timely manner, even when an exception occurs.
In the surfaceChanged(...)
implementation method, we set the camera preview size to null. This is only a temporary assignment until the acceptable preview size is determined. The camera's preview size cannot be set arbitrarily, and if an unacceptable value is set, the app throws an exception. 19.4.3 determine the preview interface size
First, you Camera.Parameters
get a list of camera preview sizes supported by the system through nested classes. Camera.Parameters
class includes the following methods:
Public list<camera.size> getsupportedpreviewsizes ()
This method returns android.hardware.Camera.Size
a list of class instances, each of which encapsulates a specific picture width and height dimension.
To find a suitable Surface
preview size, you can compare the preview size in the list to the surfaceChanged()
Surface
width and height of the incoming method.
In the CrimeCameraFragment
class, add the method shown in Listing 19-9. This method takes a set of preview dimensions and then finds the dimensions with the largest number of pixels. To illustrate, it is not elegant to calculate the optimal size of the implementation code, but it is well-adapted to our usage needs.
Code Listing 19-9 Find the best size for device support (Crimecamerafragment.java)
surfaceChanged(...)
call the method in the method to set the preview size, as shown in Listing 19-10.
Code Listing 19-10 Call getBestSupportedSize(...)
method (Crimecamerafragment.java)
19.4.4 StartCrimeCameraActivity
To use the viewfinder, you need to CrimeFragment
add a camera call button in the user interface. Click the camera button to CrimeFragment
launch an CrimeCameraActivity
instance. Figure 19-7 shows the view interface for the added camera button (inside the red box) CrimeFragment
.
Figure 19-7 The camera button was added CrimeFragment
To implement the component Reflow user interface shown in Figure 19-7, you need to add three LinearLayout
and one ImageButton
. Refer to Figure 19-8 to Modify the CrimeFragment
layout file fragment_crime.xmlbelow Res\layout and Res\layout-land, respectively.
Figure 19-8 Add a camera button and rearrange the layout ( Layout/fragment_crime.xml )
Follow figure 19-9 to complete a similar horizontal layout adjustment.
Figure 19-9 Add a camera button and rearrange the layout ( Layout-land/fragment_crime.xml )
In the CrimeFragment
class, add a member variable, reference the Picture button through the resource ID, and then set it to OnClickListener
start CrimeCameraActivity
, as shown in Listing 19-11.
Code Listing 19-11 start CrimeCameraActivity
(Crimefragment.java)
For devices without a camera, the photo button ( mPhotoButton
) should be disabled. You can check to PackageManager
see if the device comes with a camera. In the onCreateView(...)
method, for devices that do not have a camera, add the code that disables the Take photo button, as shown in Listing 19-12.
Code Listing 19-12 Check if the device has a camera (Crimefragment.java)
After getting to PackageManager
, call the hasSystemFeature(String)
method and pass in constants that represent the features of the device. FEATURE_CAMERA
A constant represents a rear camera, and a FEATURE_CAMERA_FRONT
constant represents a front-facing camera. For devices that do not have a camera, call ImageButton
the button's setEnabled(false)
property method.
Run the Criminalintent app. View a crime detail record, then click the Take photo button to view the camera Live preview screen. but now it is not possible to take pictures and save, this type of feature will be completed in the next chapter , now click the "Forensics" button will return to the CrimeFragment
view, 19-10 shows.
Figure 19-10 Real-time preview screen from the camera
We've already forced the interface in the configuration file CrimeCameraActivity
to always show in horizontal mode. If you try to rotate the device, you can see that the preview and photo buttons are locked in horizontal mode, even if the device is in vertical mode.
Hide the status bar and action Bar
As shown in 19-10, the activity's Action bar and status bar mask some of the viewfinder windows. In general, users only focus on the screen in the viewfinder, and will not stay in the photo screen for a long time, so the action bar and the status bar is not useful, and even hinder the photo framing, if you can hide them it is best.
Interestingly, we can only hide the CrimeCameraActivity
CrimeCameraFragment
Action Bar and the status bar in the middle instead of in. Open the Crimecameraactivity.java file, and in the code listing 19-13, onCreate(Bundle)
add the hidden function code to the method.
Code Listing 19-13 Configuring activity (Crimecameraactivity.java)
Why does it have to be hidden in activity? Called in the method that is called in the Activity.setContentView(...)
CrimeCameraActivity
onCreate(Bundle)
Superclass version method of the class. Before you create activity
a view, you must call requestWindowFeature(...)
methods and addFlags(...)
methods. Fragment cannot be added before its managed activity view is created, so it is necessary to invoke the relevant method of hiding the action bar and the status bar in the activity.
Run the Criminalintent app again. Now you see an unobstructed viewfinder window, shown in 19-11.
Figure 19-11 the status bar and action Bar are hidden. Activity Screen
The next chapter will cover more camera API-related content, enabling you to save image files locally and display them in the Crimefragment view.
19th Camera I: Viewfinder