如何在不使用意图的片段中拍摄和保存图片?
Posted
技术标签:
【中文标题】如何在不使用意图的片段中拍摄和保存图片?【英文标题】:how to take and save pictures in fragment not using intent? 【发布时间】:2015-03-02 03:02:52 【问题描述】:您好,我正在尝试拍照并将该照片保存在片段中。 我的用户应该按下一个按钮并拍照并保存它,我的相机预览在我的片段中所以我认为这些事情也应该在片段中发生,所以我尝试在片段中引入按钮但我得到 NullPointerException 所以我试图得到位图并使用 [this]:Passing data between a fragment and its container activity 将其发送到活动,但它给了我类转换异常,我不知道该怎么做。 请记住,我想拍摄并保存照片,任何帮助都会很棒。谢谢 这是我在相机片段中的代码:
public class CameraFragment extends Fragment
private Preview mPreview;
Camera mCamera;
int mNumberOfCameras;
// The first rear facing camera
int mDefaultCameraId;
@Override
public void onCreate(Bundle savedInstanceState)
Log.d("aron", "we are in oncreate");
super.onCreate(savedInstanceState);
// Create a container that will hold a SurfaceView for camera previews
mPreview = new Preview(this.getActivity());
Log.d("aron", "we are in oncreate and we made preview successfuly");
public interface OnDataPass
public void onDataPass(Bitmap data);
OnDataPass dataPasser;
@Override
public void onAttach(Activity a)
super.onAttach(a);
Log.d("aron", "we are in onattach");
dataPasser = (OnDataPass) a;
public void passData()
Bitmap data=mPreview.getBitmap();
Log.d("aron", "we are in passdata");
dataPasser.onDataPass(data);
@Override
public void onActivityCreated(Bundle savedInstanceState)
super.onActivityCreated(savedInstanceState);
// Add an up arrow to the "home" button, indicating that the button will go "up"
// one activity in the app's Activity heirarchy.
// Calls to getActionBar() aren't guaranteed to return the ActionBar when called
// from within the Fragment's onCreate method, because the Window's decor hasn't been
// initialized yet. Either call for the ActionBar reference in Activity.onCreate()
// (after the setContentView(...) call), or in the Fragment's onActivityCreated method.
/* Activity activity = this.getActivity();
ActionBar actionBar = activity.getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);*/
Log.d("aron", "we are in onactivitycreated and we are done with it");
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
Log.d("aron", "we are in oncreateview");
return mPreview;
@Override
public void onResume()
super.onResume();
// Use mCurrentCamera to select the camera desired to safely restore
// the fragment after the camera has been changed
mCamera = Camera.open();
mPreview.setCamera(mCamera);
Log.d("aron", "we are in onresume");
@Override
public void onPause()
super.onPause();
// Because the Camera object is a shared resource, it's very
// important to release it when the activity is paused.
if (mCamera != null)
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
Log.d("aron", "we are in onpause");
/* @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
if (mNumberOfCameras > 1)
// Inflate our menu which can gather user input for switching camera
inflater.inflate(R.menu.main, menu);
else
super.onCreateOptionsMenu(menu, inflater);
@Override
public boolean onOptionsItemSelected(MenuItem item)
// Handle item selection
switch (item.getItemId())
case R.id.menu_switch_cam:
// Release this camera -> mCameraCurrentlyLocked
if (mCamera != null)
mCamera.stopPreview();
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
// Acquire the next camera and request Preview to reconfigure
// parameters.
mCurrentCamera = (mCameraCurrentlyLocked + 1) % mNumberOfCameras;
mCamera = Camera.open(mCurrentCamera);
mCameraCurrentlyLocked = mCurrentCamera;
mPreview.switchCamera(mCamera);
// Start the preview
mCamera.startPreview();
return true;
case android.R.id.home:
Intent intent = new Intent(this.getActivity(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
*/
// ----------------------------------------------------------------------
/**
* A simple wrapper around a Camera and a SurfaceView that renders a centered
* preview of the Camera to the surface. We need to center the SurfaceView
* because not all devices have cameras that support preview sizes at the same
* aspect ratio as the device's display.
*/
class Preview extends ViewGroup implements SurfaceHolder.Callback
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Bitmap cameraBitmap;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
boolean mSurfaceCreated = false;
Preview(Context context)
super(context);
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
public void setCamera(Camera camera)
mCamera = camera;
if (mCamera != null)
mSupportedPreviewSizes = mCamera.getParameters()
.getSupportedPreviewSizes();
if (mSurfaceCreated) requestLayout();
public void switchCamera(Camera camera)
setCamera(camera);
try
camera.setPreviewDisplay(mHolder);
catch (IOException exception)
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(),
widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null)
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width,
height);
if (mCamera != null)
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
if (getChildCount() > 0)
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null)
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth)
final int scaledChildWidth = previewWidth * height
/ previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
else
final int scaledChildHeight = previewHeight * width
/ previewWidth;
child.layout(0, (height - scaledChildHeight) / 2, width,
(height + scaledChildHeight) / 2);
public void surfaceCreated(SurfaceHolder holder)
// The Surface has been created, acquire the camera and tell it where
// to draw.
try
if (mCamera != null)
mCamera.setPreviewDisplay(holder);
catch (IOException exception)
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
if (mPreviewSize == null) requestLayout();
mSurfaceCreated = true;
public void surfaceDestroyed(SurfaceHolder holder)
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null)
mCamera.stopPreview();
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h)
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null)
return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes)
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff)
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null)
minDiff = Double.MAX_VALUE;
for (Size size : sizes)
if (Math.abs(size.height - targetHeight) < minDiff)
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
return optimalSize;
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
Log.d("aron", "we are in surface changed");
mCamera.setParameters(parameters);
mCamera.startPreview();
public Bitmap getBitmap()
@SuppressWarnings("unused")
PictureCallback pic=new PictureCallback()
@Override
public void onPictureTaken(byte[] data, Camera arg1)
Log.d("aron", "onPicturetaken");
cameraBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
;
return cameraBitmap;
它在进入时显示 ClassCastException
dataPasser = (OnDataPass) a;
请注意,由于我的项目的其他部分,我不想使用意图。 请帮帮我!!!
这是我的主持人活动:
public class MainActivity extends Activity
@Override
protected void onCreate(Bundle savedInstanceState)
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageButton capturebtn=(ImageButton)findViewById(R.id.capturebtn);
Log.d("aron", "Image button is created");
capturebtn.setOnClickListener(new OnClickListener()
@Override
public void onClick(View view)
@SuppressWarnings("unused")
OnDataPass bitmapPasser=new OnDataPass()
@Override
public void onDataPass(Bitmap cameraBitmap)
Log.d("aron","we are in act on click and in datapass got bitmap");
int wid = cameraBitmap.getWidth();
int hgt = cameraBitmap.getHeight();
Bitmap newImage = Bitmap.createBitmap(wid, hgt, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newImage);
canvas.drawBitmap(cameraBitmap, 0f, 0f, null);
Log.d("aron","bitmap and canvas are made");
FrameLayout frm = (FrameLayout)findViewById(R.id.frameLayout1);
frm.setDrawingCacheEnabled(true);
frm.buildDrawingCache();
Bitmap bitmap = frm.getDrawingCache();
canvas.drawBitmap(bitmap, 0f, 0f, null);
Log.d("aron","framelayout dorost shod");
;
);
如您所见,我实现了 OnDataPass。
【问题讨论】:
你的宿主Activity是否实现了OnDataPass接口? 你不能像那样将一个类转换为另一个类。创建一个以 Activity 对象为参数的构造函数。 大多数具有此功能的应用程序都使用标准 Intent 来实现它,而且它比您自己实现要容易得多。 是的,我确实实现了 OnDataPass @harism。 正如我所说,我不能使用意图,这并不是我不想@Egor。 【参考方案1】:所以过了一会儿我自己解决了问题,关键是可以使用
Camera.PictureCallback
我现在就这样做。像这样:
@Override
public void onActivityCreated(Bundle savedInstanceState)
super.onActivityCreated(savedInstanceState);
View myActivityView=(RelativeLayout)getActivity().findViewById(R.id.parentContainer);
ImageButton capturebtn=(ImageButton)myActivityView.findViewById(R.id.capturebtn);
capturebtn.setOnClickListener(new View.OnClickListener()
@SuppressWarnings("UnusedDeclaration")
@Override
public void onClick(View v)
Log.d("aron", "this is in fragment and this is a damned button say halelooya");
mPreview.TakePicture();
);
在onActivity的fragment中可以看到,我调用了fragment的父activity,调用了拍照方法。
【讨论】:
以上是关于如何在不使用意图的片段中拍摄和保存图片?的主要内容,如果未能解决你的问题,请参考以下文章
保存图片EXTRA_OUPUT为空onActivityResult