CameraFragment.class
public class CameraFragment extends BaseFragment {
// Native camera.
private Camera mCamera;
// View to display the camera output.
private CameraPreview mPreview;
// Reference to the containing view.
private View mCameraView;
/**
* Default empty constructor.
*/
public CameraFragment(){
super();
}
/**
* Static factory method
* @param sectionNumber
* @return
*/
/**
* OnCreateView fragment override
* @param inflater
* @param container
* @param savedInstanceState
* @return
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_camera, container, false);
// Create our Preview view and set it as the content of our activity.
boolean opened = safeCameraOpenInView(view);
if(!opened){
Log.d("CameraGuide","Error, Camera failed to open");
return view;
}
// Trap the capture button.
Button captureButton = (Button) view.findViewById(R.id.button_capture);
captureButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
}
);
return view;
}
/**
* Recommended "safe" way to open the camera.
* @param view
* @return
*/
private boolean safeCameraOpenInView(View view) {
boolean qOpened;
releaseCameraAndPreview();
mCamera = getCameraInstance();
mCameraView = view;
qOpened = (mCamera != null);
if(qOpened){
mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera,view);
FrameLayout preview = (FrameLayout) view.findViewById(R.id.camera_preview);
preview.addView(mPreview);
mPreview.startCameraPreview();
}
return qOpened;
}
/**
* Safe method for getting a camera instance.
* @return
*/
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
e.printStackTrace();
}
return c; // returns null if camera is unavailable
}
@Override
public void onPause() {
super.onPause();
}
@Override
public void onDestroy() {
super.onDestroy();
releaseCameraAndPreview();
}
/**
* Clear any existing preview / camera.
*/
private void releaseCameraAndPreview() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
if(mPreview != null){
mPreview.destroyDrawingCache();
mPreview.mCamera = null;
}
}
/**
* Surface on which the camera projects it's capture results. This is derived both from Google's docs and the
* excellent StackOverflow answer provided below.
*
* Reference / Credit: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
*/
class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
// SurfaceHolder
private SurfaceHolder mHolder;
// Our Camera.
private Camera mCamera;
// Parent Context.
private Context mContext;
// Camera Sizing (For rotation, orientation changes)
private Camera.Size mPreviewSize;
// List of supported preview sizes
private List<Camera.Size> mSupportedPreviewSizes;
// Flash modes supported by this camera
private List<String> mSupportedFlashModes;
// View holding this camera.
private View mCameraView;
public CameraPreview(Context context, Camera camera, View cameraView) {
super(context);
// Capture the context
mCameraView = cameraView;
mContext = context;
setCamera(camera);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setKeepScreenOn(true);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
/**
* Begin the preview of the camera input.
*/
public void startCameraPreview()
{
try{
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
}
catch(Exception e){
e.printStackTrace();
}
}
/**
* Extract supported preview and flash modes from the camera.
* @param camera
*/
private void setCamera(Camera camera)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
mCamera = camera;
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
// Set the camera to Auto Flash mode.
if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)){
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
mCamera.setParameters(parameters);
}
requestLayout();
}
/**
* The Surface has been created, now tell the camera where to draw the preview.
* @param holder
*/
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Dispose of the camera preview.
* @param holder
*/
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null){
mCamera.stopPreview();
}
}
/**
* React to surface changed events
* @param holder
* @param format
* @param w
* @param h
*/
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
Camera.Parameters parameters = mCamera.getParameters();
// Set the auto-focus mode to "continuous"
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
// Preview size must exist.
if(mPreviewSize != null) {
Camera.Size previewSize = mPreviewSize;
parameters.setPreviewSize(previewSize.width, previewSize.height);
}
mCamera.setParameters(parameters);
mCamera.startPreview();
} catch (Exception e){
e.printStackTrace();
}
}
/**
* Calculate the measurements of the layout
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null){
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
/**
* Update the layout based on rotation and orientation changes.
* @param changed
* @param left
* @param top
* @param right
* @param bottom
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
if (changed) {
final int width = right - left;
final int height = bottom - top;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null){
Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation())
{
case Surface.ROTATION_0:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
mCamera.setDisplayOrientation(90);
break;
case Surface.ROTATION_90:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
break;
case Surface.ROTATION_180:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
break;
case Surface.ROTATION_270:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
mCamera.setDisplayOrientation(180);
break;
}
}
final int scaledChildHeight = previewHeight * width / previewWidth;
mCameraView.layout(0, height - scaledChildHeight, width, height);
}
}
/**
*
* @param sizes
* @param width
* @param height
* @return
*/
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int width, int height)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
Camera.Size optimalSize = null;
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) height / width;
// Try to find a size match which suits the whole screen minus the menu on the left.
for (Camera.Size size : sizes){
if (size.height != width) continue;
double ratio = (double) size.width / size.height;
if (ratio <= targetRatio + ASPECT_TOLERANCE && ratio >= targetRatio - ASPECT_TOLERANCE){
optimalSize = size;
}
}
// If we cannot find the one that matches the aspect ratio, ignore the requirement.
if (optimalSize == null) {
// TODO : Backup in case we don't get a size.
}
return optimalSize;
}
}
/**
* Picture Callback for handling a picture capture and saving it out to a file.
*/
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null){
Toast.makeText(getActivity(), "Image retrieval failed.", Toast.LENGTH_SHORT)
.show();
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
// Restart the camera preview.
safeCameraOpenInView(mCameraView);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
/**
* Used to return the camera File output.
* @return
*/
private File getOutputMediaFile(){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "UltimateCameraGuideApp");
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("Camera Guide", "Required media storage does not exist");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
DialogHelper.showDialog( "Success!","Your picture has been saved!",getActivity());
return mediaFile;
}
}
下面的CameraFragment.class扩展BaseFragment.class是BaseFragment代码:
public static final String ARG_SECTION_NUMBER = "ARG_SECTION_NUMBER";
/**
* Default empty constructor
*/
public BaseFragment(){
//
}
/**
* This interface must be implemented by activities that contain this
* mFragment to allow an interaction in this mFragment to be communicated
* to the mActivity and potentially other fragments contained in that
* mActivity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
public void onFragmentInteraction(Uri uri);
public void onFragmentInteraction(String id);
public void onFragmentInteraction(int actionId);
}
}
CameraActivity.class
// Storage for camera image URI components
private final static String CAPTURED_PHOTO_PATH_KEY = "mCurrentPhotoPath";
private final static String CAPTURED_PHOTO_URI_KEY = "mCapturedImageURI";
// Required for camera operations in order to save the image file on resume.
private String mCurrentPhotoPath = null;
private Uri mCapturedImageURI = null;
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
if (mCurrentPhotoPath != null) {
savedInstanceState.putString(CAPTURED_PHOTO_PATH_KEY, mCurrentPhotoPath);
}
if (mCapturedImageURI != null) {
savedInstanceState.putString(CAPTURED_PHOTO_URI_KEY, mCapturedImageURI.toString());
}
super.onSaveInstanceState(savedInstanceState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
if (savedInstanceState.containsKey(CAPTURED_PHOTO_PATH_KEY)) {
mCurrentPhotoPath = savedInstanceState.getString(CAPTURED_PHOTO_PATH_KEY);
}
if (savedInstanceState.containsKey(CAPTURED_PHOTO_URI_KEY)) {
mCapturedImageURI = Uri.parse(savedInstanceState.getString(CAPTURED_PHOTO_URI_KEY));
}
super.onRestoreInstanceState(savedInstanceState);
}
/**
* Getters and setters.
*/
public String getCurrentPhotoPath() {
return mCurrentPhotoPath;
}
public void setCurrentPhotoPath(String mCurrentPhotoPath) {
this.mCurrentPhotoPath = mCurrentPhotoPath;
}
public Uri getCapturedImageURI() {
return mCapturedImageURI;
}
public void setCapturedImageURI(Uri mCapturedImageURI) {
this.mCapturedImageURI = mCapturedImageURI;
}
}
SectionsPagerAdapater.class
public class SectionsPagerAdapter extends FragmentPagerAdapter {
protected Context mContext;
public SectionsPagerAdapter(Context context,FragmentManager fm) {
super(fm);
mContext = context;
}
@Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a InboxFragment (defined as a static inner class below).
switch (position){
case 0:
return new InboxFragment();
case 1:
return new CameraFragment();
case 2:
return new FeedsFragment();
}
return null;
}
@Override
public int getCount() {
// Show 3 total pages.
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return mContext.getString(R.string.title_section1).toUpperCase();
case 1:
return mContext.getString(R.string.title_section2).toUpperCase();
case 2:
return mContext.getString(R.string.title_section3).toUpperCase();
}
return null;
}
}
MainActvity.class调用SectionsPagerAdapter.class
public class MainActivity extends FragmentActivity {
// private SmsPrefManager pref;
/**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {@link FragmentPagerAdapter} derivative, which will keep every
* loaded fragment in memory. If this becomes too memory intensive, it
* may be best to switch to a
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {@link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;
SmsPrefManager pref;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(this,
getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
AndroidManifest.xml Permissions:
<!-- Accessing Camera Hardware -->
<uses-permission android:name="android.hardware.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="true"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-feature android:name="android.hardware.camera.flash"/>
<uses-feature android:name="android.hardware.location"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
布局XML fragment_camera
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
<RelativeLayout
android:id="@+id/innerRelativeLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" >
<Button
android:id="@+id/button_capture"
android:text="@string/btn_cam"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_margin="10dp"
android:layout_gravity="bottom"
/>
</RelativeLayout>
</RelativeLayout>
对于在我的设备上运行的应用程序API23和我的Emulator API19,Logcat不会返回任何运行时错误。请帮我解决这个问题已经遭遇了很多Stackoverflow查询,但没有找到解决方案。提前谢谢!