方式:
調用camera api 自定義相機
調用系統相機
由于需求不同,是以選擇的方案固然也不同,至于第二種調用系統相機,這裡就不過多講解了,使用intent對象設定一個action動作即可,跳轉時使用startactivityforresult,然後在onactivityresult處理相關資料便可,關鍵代碼:
intent.setaction("android.media.action.still_image_camera");
至于使用,較常見的一般是應用中使用者上傳頭像的時候調用,然後傳回處理圖像資料。
而第一種自定義相機的方式使用也十分普遍,但是要做好這個子產品,相對來說還是有一定難度的,之前分享過一個github上的開源相機的項目,項目由美國的一個團隊開發,集 拍照、攝影、各種特效動畫 等功能與一身,本人之前研究了下,發現功能比較全面也很強大,摳出來單獨拍照那一個子產品,我滴媽呀,真tm費勁!相機不管是預覽還是拍攝圖像都還是很清晰的,自己當時也寫了一個,比較操蛋,隻能怪自己對這一塊的優化了解淺顯吧!特别是預覽的時候,聚焦完成後,焦點周邊會出現很多白色的噪點,密密麻麻,特别嚴重,頭疼的很。不過也總算解決了,灰常感謝usa的那個什麼什麼團隊的開源相機程式。經過自己改造後的預覽效果圖:
下面說說在android中調用camera來定義相機的最基本步驟:
打開相機 —— 調用camera的open()方法。
擷取拍照參數 —— 調用camera的getparameters()方法,傳回camera.parameters對象。
拍照參數設定 —— 調用camera.parameters對象。
拍照參數控制 —— 調用camera的setparameters(),并将camera.parameters對象作為參數傳入。注:android2.3.3之後不用設定。
預覽取景 —— 調用camera的startpreview()方法,在之前注意調用camera的setpreviewdisplay(surfaceholder holder)設定使用哪個surfaceview來顯示取得的圖檔。
拍照 —— 調用camera的takepicture()
停止預覽 —— 調用camera的stoppreview()方法
資源釋放 —— camera.release()
開啟和關閉預覽的聯系如下:camera
---- surfaceholder ------ surfaceview
關于surfaceholder.callback必須實作的3個方法:
surfacecreated() 該方法在surfaceview被create時調用
surfacechanged() 該方法是當surfaceview發生改變後調用
surfacedestroyed() 這個不用說了,銷毀時調用
surfaceholder通過addcallback()方法将響應的接口綁定
注:必要camera權限,例如:
<uses-permission android:name="android.permission.mount_unmount_filesystems"/>
<uses-permission android:name="android.permission.camera"/>
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.write_external_storage" />
關于camera下的parameters類,其中封裝了我們需要的大部分功能,下面做個簡單介紹:
setpictureformat() 方法用于設定相機照片的格式,其參數是一個字元型參數,位于pixelformat類中,如:pixelformat.jpeg。
setscenemode() 方法用于設定相機場景類型,其參是是一個字元型參數,位于parameters類中,以scene_mode_開頭。
setzoom() 方法用于設定相機焦距,其參數是一個整型的參數,該參數的範圍是0到camera.getparameters().getmaxzoom()。
setpicturesize() 方法用于設定相機照片的大小,參數為整型。
setwhitebalance() 方法用于設定相機照片白平衡,其參數是一個字元型,位于parameters類中,以white_balance開頭。
setjpegquality() 方法用于設定相機照片的品質,其參數是一個整型參數,取值範圍為1到100。
setflashmode() 方法用于設定閃光燈的類型,其參數是一個字元型參數,位于parameters類中,以flash_mode_開頭。
setcoloreffect() 方法用于設定照片顔色特效的類型,其參數是一個字元型參數,位于parameters類中,以effect_開頭。
下面分享本篇blog的示例相機子產品,此功能子產品并非上面開源項目中的剝離出來的,看下效果圖咯:
效果看着還可以吧(不點贊也太不給面子了吧 - . - ),下面個出主界面的布局代碼:
<?xml version="1.0" encoding="utf-8"?>
<framelayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- 預覽畫布 -->
<surfaceview
android:id="@+id/surfaceview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- 閃光燈、前置攝像頭、後置攝像頭、聚焦 -->
<relativelayout
android:layout_height="match_parent" >
<org.gaochun.camera.cameragrid
android:id="@+id/camera_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignparenttop="true" />
<view
android:id="@+id/focus_index"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@drawable/camera_focus"
android:visibility="invisible" />
<imageview
android:id="@+id/flash_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignparentleft="true"
android:onclick="onclick"
android:padding="15dp"
android:scaletype="centercrop"
android:src="@drawable/camera_flash_off" />
android:id="@+id/camera_flip_view"
android:layout_alignparentright="true"
android:src="@drawable/camera_flip" />
<!-- 底部按鈕 -->
<relativelayout
android:layout_width="fill_parent"
android:layout_height="70dp"
android:layout_alignparentbottom="true"
android:background="#a0000000"
android:padding="5dp" >
<button
android:id="@+id/search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginleft="30dp"
android:background="@null"
android:drawablepadding="3dp"
android:drawabletop="@drawable/ic_search_selector"
android:onclick="onclick"
android:text="搜圖"
android:textcolor="@drawable/row_selector_text" />
<imageview
android:id="@+id/action_button"
android:layout_centerinparent="true"
android:clickable="true"
android:src="@drawable/btn_shutter_photo" />
android:id="@+id/takephoto"
android:layout_alignparentright="true"
android:layout_marginright="30dp"
android:drawabletop="@drawable/ic_takephoto_selector"
android:text="拍照"
</relativelayout>
</relativelayout>
</framelayout>
下面是核心子產品 camerapreview 類:
public class camerapreview extends viewgroup implements surfaceholder.callback, camera.autofocuscallback {
private surfaceview msurfaceview;
private surfaceholder mholder;
private size mpreviewsize;
private size adaptersize;
//private list<size> msupportedpreviewsizes;
private camera mcamera;
private boolean issupportautofocus = false;
private camera.parameters parameters = null;
private context mcontext;
//private int mcurrentcameraid = 0;
private int screenwidth;
private int screenheight;
camerapreview(context context, surfaceview sv) {
super(context);
mcontext = context;
msurfaceview = sv;
mholder = msurfaceview.getholder();
mholder.addcallback(this);
mholder.settype(surfaceholder.surface_type_push_buffers);
mholder.setkeepscreenon(true);
issupportautofocus = context.getpackagemanager().hassystemfeature(
packagemanager.feature_camera_autofocus);
displaymetrics dm = new displaymetrics();
((activity) mcontext).getwindowmanager().getdefaultdisplay().getmetrics(dm);
screenwidth = dm.widthpixels;
screenheight = dm.heightpixels;
}
public void setcamera(camera camera) {
mcamera = camera;
initcamera();
public void initcamera() {
if (mcamera != null) {
camera.parameters params = mcamera.getparameters();
//msupportedpreviewsizes = mcamera.getparameters().getsupportedpreviewsizes();
requestlayout();
if (mpreviewsize == null) {
mpreviewsize = findbestpreviewresolution();
}
if (adaptersize == null) {
adaptersize = findbestpictureresolution();
if (adaptersize != null) {
params.setpicturesize(adaptersize.width, adaptersize.height);
if (mpreviewsize != null) {
params.setpreviewsize(mpreviewsize.width, mpreviewsize.height);
params.setpictureformat(pixelformat.jpeg);
list<string> focusmodes = params.getsupportedfocusmodes();
if (focusmodes.contains(camera.parameters.focus_mode_auto)) {
// set the focus mode
params.setfocusmode(camera.parameters.focus_mode_auto);
// set camera parameters
mcamera.setparameters(params);
setdispaly(params, mcamera);
//setcameradisplayorientation((activity) mcontext, mcurrentcameraid, mcamera);
mcamera.setparameters(params);
}
//控制圖像的正确顯示方向
private void setdispaly(camera.parameters parameters, camera camera) {
if (build.version.sdk_int >= 8) {
setdisplayorientation(camera, 90);
} else {
parameters.setrotation(90);
//實作的圖像的正确顯示
private void setdisplayorientation(camera camera, int i) {
method downpolymorphic;
try {
downpolymorphic = camera.getclass().getmethod("setdisplayorientation",
new class[]{int.class});
if (downpolymorphic != null) {
downpolymorphic.invoke(camera, new object[]{i});
} catch (exception e) {
e.printstacktrace();
public static void setcameradisplayorientation(activity activity,
int cameraid, android.hardware.camera camera) {
android.hardware.camera.camerainfo info =
new android.hardware.camera.camerainfo();
android.hardware.camera.getcamerainfo(cameraid, info);
int rotation = activity.getwindowmanager().getdefaultdisplay()
.getrotation();
int degrees = 0;
switch (rotation) {
case surface.rotation_0:
degrees = 0;
break;
case surface.rotation_90:
degrees = 90;
case surface.rotation_180:
degrees = 180;
case surface.rotation_270:
degrees = 270;
int result;
if (info.facing == camera.camerainfo.camera_facing_front) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
camera.setdisplayorientation(result);
@override
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
final int width = resolvesize(getsuggestedminimumwidth(), widthmeasurespec);
final int height = resolvesize(getsuggestedminimumheight(), heightmeasurespec);
setmeasureddimension(width, height);
// if (msupportedpreviewsizes != null) {
// mpreviewsize = getoptimalpreviewsize(msupportedpreviewsizes, width, height);
// }
protected void onlayout(boolean changed, int l, int t, int r, int b) {
if (changed && getchildcount() > 0) {
final view child = getchildat(0);
final int width = r - l;
final int height = b - t;
int previewwidth = width;
int previewheight = height;
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.
if (mcamera != null) {
mcamera.setpreviewdisplay(holder);
} catch (ioexception e) {
if (null != mcamera) {
mcamera.release();
mcamera = null;
public void surfacechanged(surfaceholder holder, int format, int w, int h) {
if (holder.getsurface() == null) {
return;
camera.parameters parameters = mcamera.getparameters();
parameters.setpreviewsize(mpreviewsize.width, mpreviewsize.height);
mcamera.setparameters(parameters);
try {
} catch (ioexception e) {
e.printstacktrace();
mcamera.startpreview();
reautofocus();
public void surfacedestroyed(surfaceholder holder) {
// surface will be destroyed when we return, so stop the preview.
mcamera.stoppreview();
/**
* 最小預覽界面的分辨率
*/
private static final int min_preview_pixels = 480 * 320;
* 最大寬高比差
private static final double max_aspect_distortion = 0.15;
* 找出最适合的預覽界面分辨率
*
* @return
private camera.size findbestpreviewresolution() {
camera.parameters cameraparameters = mcamera.getparameters();
camera.size defaultpreviewresolution = cameraparameters.getpreviewsize();
list<camera.size> rawsupportedsizes = cameraparameters.getsupportedpreviewsizes();
if (rawsupportedsizes == null) {
return defaultpreviewresolution;
// 按照分辨率從大到小排序
list<camera.size> supportedpreviewresolutions = new arraylist<camera.size>(rawsupportedsizes);
collections.sort(supportedpreviewresolutions, new comparator<size>() {
@override
public int compare(camera.size a, camera.size b) {
int apixels = a.height * a.width;
int bpixels = b.height * b.width;
if (bpixels < apixels) {
return -1;
}
if (bpixels > apixels) {
return 1;
return 0;
});
stringbuilder previewresolutionsb = new stringbuilder();
for (camera.size supportedpreviewresolution : supportedpreviewresolutions) {
previewresolutionsb.append(supportedpreviewresolution.width).append('x').append(supportedpreviewresolution.height)
.append(' ');
// 移除不符合條件的分辨率
double screenaspectratio = (double) screenwidth
/ screenheight;
iterator<size> it = supportedpreviewresolutions.iterator();
while (it.hasnext()) {
camera.size supportedpreviewresolution = it.next();
int width = supportedpreviewresolution.width;
int height = supportedpreviewresolution.height;
// 移除低于下限的分辨率,盡可能取高分辨率
if (width * height < min_preview_pixels) {
it.remove();
continue;
// 在camera分辨率與螢幕分辨率寬高比不相等的情況下,找出差距最小的一組分辨率
// 由于camera的分辨率是width>height,我們設定的portrait模式中,width<height
// 是以這裡要先交換然preview寬高比後在比較
boolean iscandidateportrait = width > height;
int maybeflippedwidth = iscandidateportrait ? height : width;
int maybeflippedheight = iscandidateportrait ? width : height;
double aspectratio = (double) maybeflippedwidth / (double) maybeflippedheight;
double distortion = math.abs(aspectratio - screenaspectratio);
if (distortion > max_aspect_distortion) {
// 找到與螢幕分辨率完全比對的預覽界面分辨率直接傳回
if (maybeflippedwidth == screenwidth
&& maybeflippedheight == screenheight) {
return supportedpreviewresolution;
// 如果沒有找到合适的,并且還有候選的像素,則設定其中最大比例的,對于配置比較低的機器不太合适
if (!supportedpreviewresolutions.isempty()) {
camera.size largestpreview = supportedpreviewresolutions.get(0);
return largestpreview;
// 沒有找到合适的,就傳回預設的
return defaultpreviewresolution;
private camera.size findbestpictureresolution() {
list<camera.size> supportedpicresolutions = cameraparameters.getsupportedpicturesizes(); // 至少會傳回一個值
stringbuilder picresolutionsb = new stringbuilder();
for (camera.size supportedpicresolution : supportedpicresolutions) {
picresolutionsb.append(supportedpicresolution.width).append('x')
.append(supportedpicresolution.height).append(" ");
camera.size defaultpictureresolution = cameraparameters.getpicturesize();
// 排序
list<camera.size> sortedsupportedpicresolutions = new arraylist<camera.size>(
supportedpicresolutions);
collections.sort(sortedsupportedpicresolutions, new comparator<camera.size>() {
double screenaspectratio = screenwidth
/ (double) screenheight;
iterator<camera.size> it = sortedsupportedpicresolutions.iterator();
// 是以這裡要先交換然後在比較寬高比
// 如果沒有找到合适的,并且還有候選的像素,對于照片,則取其中最大比例的,而不是選擇與螢幕分辨率相同的
if (!sortedsupportedpicresolutions.isempty()) {
return sortedsupportedpicresolutions.get(0);
return defaultpictureresolution;
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)
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 reautofocus() {
if (issupportautofocus) {
mcamera.autofocus(new camera.autofocuscallback() {
@override
public void onautofocus(boolean success, camera camera) {
});
public list<size> getresolutionlist() {
return mcamera.getparameters().getsupportedpreviewsizes();
public camera.size getresolution() {
camera.parameters params = mcamera.getparameters();
camera.size s = params.getpreviewsize();
return s;
/*public void setcurrentcameraid(int current) {
mcurrentcameraid = current;
}*/
//定點對焦的代碼
public void pointfocus(motionevent event) {
mcamera.cancelautofocus();
parameters = mcamera.getparameters();
if (build.version.sdk_int >= build.version_codes.ice_cream_sandwich) {
//showpoint(x, y);
focusontouch(event);
mcamera.setparameters(parameters);
autofocus();
//實作自動對焦
public void autofocus() {
new thread() {
public void run() {
try {
sleep(100);
} catch (interruptedexception e) {
e.printstacktrace();
if (mcamera == null) {
return;
mcamera.autofocus(new camera.autofocuscallback() {
@override
public void onautofocus(boolean success, camera camera) {
if (success) {
initcamera();//實作相機的參數初始化
}
}
});
};
@targetapi(build.version_codes.ice_cream_sandwich)
private void showpoint(int x, int y) {
if (parameters.getmaxnummeteringareas() > 0) {
list<camera.area> areas = new arraylist<camera.area>();
windowmanager wm = (windowmanager) getcontext()
.getsystemservice(context.window_service);
//xy變換了
int recty = -x * 2000 / wm.getdefaultdisplay().getwidth() + 1000;
int rectx = y * 2000 / wm.getdefaultdisplay().getheight() - 1000;
int left = rectx < -900 ? -1000 : rectx - 100;
int top = recty < -900 ? -1000 : recty - 100;
int right = rectx > 900 ? 1000 : rectx + 100;
int bottom = recty > 900 ? 1000 : recty + 100;
rect area1 = new rect(left, top, right, bottom);
areas.add(new camera.area(area1, 800));
parameters.setmeteringareas(areas);
parameters.setfocusmode(camera.parameters.focus_mode_continuous_picture);
public void focusontouch(motionevent event) {
rect focusrect = calculatetaparea(event.getrawx(), event.getrawy(), 1f);
rect meteringrect = calculatetaparea(event.getrawx(), event.getrawy(), 1.5f);
camera.parameters parameters = mcamera.getparameters();
parameters.setfocusmode(camera.parameters.focus_mode_auto);
if (parameters.getmaxnumfocusareas() > 0) {
list<camera.area> focusareas = new arraylist<camera.area>();
focusareas.add(new camera.area(focusrect, 1000));
parameters.setfocusareas(focusareas);
list<camera.area> meteringareas = new arraylist<camera.area>();
meteringareas.add(new camera.area(meteringrect, 1000));
parameters.setmeteringareas(meteringareas);
mcamera.autofocus(this);
* convert touch position x:y to {@link camera.area} position -1000:-1000 to 1000:1000.
private rect calculatetaparea(float x, float y, float coefficient) {
float focusareasize = 300;
int areasize = float.valueof(focusareasize * coefficient).intvalue();
int centerx = (int) (x / getresolution().width * 2000 - 1000);
int centery = (int) (y / getresolution().height * 2000 - 1000);
int left = clamp(centerx - areasize / 2, -1000, 1000);
int right = clamp(left + areasize, -1000, 1000);
int top = clamp(centery - areasize / 2, -1000, 1000);
int bottom = clamp(top + areasize, -1000, 1000);
return new rect(left, top, right, bottom);
private int clamp(int x, int min, int max) {
if (x > max) {
return max;
if (x < min) {
return min;
return x;
public void onautofocus(boolean success, camera camera) {
public void setnull() {
adaptersize = null;
mpreviewsize = null;
}
以下是cameraactivity類:
public class cameraactivity extends activity implements view.ontouchlistener,onclicklistener {
public static final string camera_path_value1 = "photo_path";
public static final string camera_path_value2 = "path";
public static final string camera_type = "camera_type";
public static final string camera_return_path = "return_path";
private int photo_size_w = 2000;
private int photo_size_h = 2000;
public static final int camera_type_1 = 1;
public static final int camera_type_2 = 2;
private final int process = 1;
private camerapreview preview;
private camera camera;
private view focusindex;
private imageview flashbtn;
private int mcurrentcameraid = 0; // 1是前置 0是後置
private cameragrid mcameragrid;
private int type = 1; //引用的矩形框
private button mbtnsearch;
private button mbtntakephoto;
public void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
mcontext = this;
//requestwindowfeature(window.feature_no_title);
//getwindow().addflags(windowmanager.layoutparams.flag_fullscreen);//全屏
//getwindow().addflags(windowmanager.layoutparams.flag_keep_screen_on);//拍照過程螢幕一直處于高亮
setcontentview(r.layout.camera_home);
type = getintent().getintextra(camera_type, camera_type_2);
initview();
initdata();
private void initview() {
focusindex = (view) findviewbyid(r.id.focus_index);
flashbtn = (imageview) findviewbyid(r.id.flash_view);
msurfaceview = (surfaceview) findviewbyid(r.id.surfaceview);
mcameragrid = (cameragrid) findviewbyid(r.id.camera_grid);
mbtnsearch = (button) findviewbyid(r.id.search);
mbtntakephoto = (button) findviewbyid(r.id.takephoto);
private void initdata() {
preview = new camerapreview(this, msurfaceview);
preview.setlayoutparams(new layoutparams(layoutparams.match_parent,
layoutparams.match_parent));
((framelayout) findviewbyid(r.id.layout)).addview(preview);
preview.setkeepscreenon(true);
msurfaceview.setontouchlistener(this);
mcameragrid.settype(type);
private handler handler = new handler();
private void takephoto() {
camera.takepicture(shuttercallback, rawcallback, jpegcallback);
} catch (throwable t) {
t.printstacktrace();
toast.maketext(getapplication(), "拍照失敗,請重試!", toast.length_long)
.show();
camera.startpreview();
} catch (throwable e) {
protected void onresume() {
super.onresume();
int numcams = camera.getnumberofcameras();
if (numcams > 0) {
mcurrentcameraid = 0;
camera = camera.open(mcurrentcameraid);
preview.setcamera(camera);
preview.reautofocus();
} catch (runtimeexception ex) {
toast.maketext(mcontext, "未發現相機", toast.length_long).show();
protected void onpause() {
if (camera != null) {
camera.stoppreview();
preview.setcamera(null);
camera.release();
camera = null;
preview.setnull();
super.onpause();
private void resetcam() {
camera.startpreview();
preview.setcamera(camera);
shuttercallback shuttercallback = new shuttercallback() {
public void onshutter() {
};
picturecallback rawcallback = new picturecallback() {
public void onpicturetaken(byte[] data, camera camera) {
picturecallback jpegcallback = new picturecallback() {
new saveimagetask(data).execute();
resetcam();
public boolean ontouch(view v, motionevent event) {
if (build.version.sdk_int >= build.version_codes.ice_cream_sandwich) {
preview.pointfocus(event);
relativelayout.layoutparams layout = new relativelayout.layoutparams(
focusindex.getlayoutparams());
layout.setmargins((int) event.getx() - 60, (int) event.gety() - 60, 0,0);
focusindex.setlayoutparams(layout);
focusindex.setvisibility(view.visible);
scaleanimation sa = new scaleanimation(3f, 1f, 3f, 1f,
scaleanimation.relative_to_self, 0.5f,
scaleanimation.relative_to_self, 0.5f);
sa.setduration(800);
focusindex.startanimation(sa);
handler.postattime(new runnable() {
focusindex.setvisibility(view.invisible);
}, 800);
return false;
public void onclick(view v) {
switch (v.getid()) {
/*case r.id.camera_back:
setresult(0);
finish();
break;*/
case r.id.camera_flip_view:
switchcamera();
case r.id.flash_view:
turnlight(camera);
case r.id.action_button:
takephoto();
case r.id.search: //處理選中狀态
mbtnsearch.setselected(true);
mbtntakephoto.setselected(false);
case r.id.takephoto: //處理選中狀态
mbtntakephoto.setselected(true);
mbtnsearch.setselected(false);
private static string getcamerapath() {
calendar calendar = calendar.getinstance();
stringbuilder sb = new stringbuilder();
sb.append("img");
sb.append(calendar.get(calendar.year));
int month = calendar.get(calendar.month) + 1; // 0~11
sb.append(month < 10 ? "0" + month : month);
int day = calendar.get(calendar.date);
sb.append(day < 10 ? "0" + day : day);
int hour = calendar.get(calendar.hour_of_day);
sb.append(hour < 10 ? "0" + hour : hour);
int minute = calendar.get(calendar.minute);
sb.append(minute < 10 ? "0" + minute : minute);
int second = calendar.get(calendar.second);
sb.append(second < 10 ? "0" + second : second);
if (!new file(sb.tostring() + ".jpg").exists()) {
return sb.tostring() + ".jpg";
stringbuilder tmpsb = new stringbuilder(sb);
int indexstart = sb.length();
for (int i = 1; i < integer.max_value; i++) {
tmpsb.append('(');
tmpsb.append(i);
tmpsb.append(')');
tmpsb.append(".jpg");
if (!new file(tmpsb.tostring()).exists()) {
break;
tmpsb.delete(indexstart, tmpsb.length());
return tmpsb.tostring();
//處理拍攝的照片
private class saveimagetask extends asynctask<void, void, string> {
private byte[] data;
saveimagetask(byte[] data) {
this.data = data;
@override
protected string doinbackground(void... params) {
// write to sd card
string path = "";
showprogressdialog("進行中");
path = savetosdcard(data);
} catch (filenotfoundexception e) {
} finally {
return path;
protected void onpostexecute(string path) {
super.onpostexecute(path);
if (!textutils.isempty(path)) {
log.d("demolog", "path=" + path);
dismissprogressdialog();
intent intent = new intent();
intent.setclass(cameraactivity.this, photoprocessactivity.class);
intent.putextra(camera_path_value1, path);
startactivityforresult(intent, process);
toast.maketext(getapplication(), "拍照失敗,請稍後重試!",
toast.length_long).show();
private alertdialog malertdialog;
private void dismissprogressdialog() {
this.runonuithread(new runnable() {
if (malertdialog != null && malertdialog.isshowing()
&& !cameraactivity.this.isfinishing()) {
malertdialog.dismiss();
malertdialog = null;
private void showprogressdialog(final string msg) {
if (malertdialog == null) {
malertdialog = new genericprogressdialog(
cameraactivity.this);
malertdialog.setmessage(msg);
((genericprogressdialog) malertdialog)
.setprogressvisiable(true);
malertdialog.setcancelable(false);
malertdialog.setoncancellistener(null);
malertdialog.show();
malertdialog.setcanceledontouchoutside(false);
* 将拍下來的照片存放在sd卡中
public string savetosdcard(byte[] data) throws ioexception {
bitmap croppedimage;
// 獲得圖檔大小
bitmapfactory.options options = new bitmapfactory.options();
options.injustdecodebounds = true;
bitmapfactory.decodebytearray(data, 0, data.length, options);
// photo_size = options.outheight > options.outwidth ? options.outwidth
// : options.outheight;
photo_size_w = options.outwidth;
photo_size_h = options.outheight;
options.injustdecodebounds = false;
rect r = new rect(0, 0, photo_size_w, photo_size_h);
croppedimage = decoderegioncrop(data, r);
string imagepath = "";
imagepath = savetofile(croppedimage);
croppedimage.recycle();
return imagepath;
private bitmap decoderegioncrop(byte[] data, rect rect) {
inputstream is = null;
system.gc();
bitmap croppedimage = null;
is = new bytearrayinputstream(data);
bitmapregiondecoder decoder = bitmapregiondecoder.newinstance(is,false);
croppedimage = decoder.decoderegion(rect,
new bitmapfactory.options());
} catch (illegalargumentexception e) {
} catch (throwable e) {
} finally {
matrix m = new matrix();
m.setrotate(90, photo_size_w / 2, photo_size_h / 2);
if (mcurrentcameraid == 1) {
m.postscale(1, -1);
bitmap rotatedimage = bitmap.createbitmap(croppedimage, 0, 0,
photo_size_w, photo_size_h, m, true);
if (rotatedimage != croppedimage)
croppedimage.recycle();
return rotatedimage;
// 儲存圖檔檔案
public static string savetofile(bitmap croppedimage)
throws filenotfoundexception, ioexception {
file sdcard = environment.getexternalstoragedirectory();
file dir = new file(sdcard.getabsolutepath() + "/dcim/camera/");
if (!dir.exists()) {
dir.mkdirs();
string filename = getcamerapath();
file outfile = new file(dir, filename);
fileoutputstream outputstream = new fileoutputstream(outfile); // 檔案輸出流
croppedimage.compress(bitmap.compressformat.jpeg, 70, outputstream);
outputstream.flush();
outputstream.close();
return outfile.getabsolutepath();
* 閃光燈開關 開->關->自動
* @param mcamera
private void turnlight(camera mcamera) {
if (mcamera == null || mcamera.getparameters() == null
|| mcamera.getparameters().getsupportedflashmodes() == null) {
string flashmode = mcamera.getparameters().getflashmode();
list<string> supportedmodes = mcamera.getparameters()
.getsupportedflashmodes();
if (camera.parameters.flash_mode_off.equals(flashmode)
&& supportedmodes.contains(camera.parameters.flash_mode_on)) {// 關閉狀态
parameters.setflashmode(camera.parameters.flash_mode_on);
flashbtn.setimageresource(r.drawable.camera_flash_on);
} else if (camera.parameters.flash_mode_on.equals(flashmode)) {// 開啟狀态
if (supportedmodes.contains(camera.parameters.flash_mode_auto)) {
parameters.setflashmode(camera.parameters.flash_mode_auto);
flashbtn.setimageresource(r.drawable.camera_flash_auto);
mcamera.setparameters(parameters);
} else if (supportedmodes
.contains(camera.parameters.flash_mode_off)) {
parameters.setflashmode(camera.parameters.flash_mode_off);
flashbtn.setimageresource(r.drawable.camera_flash_off);
} else if (camera.parameters.flash_mode_auto.equals(flashmode)
&& supportedmodes.contains(camera.parameters.flash_mode_off)) {
parameters.setflashmode(camera.parameters.flash_mode_off);
flashbtn.setimageresource(r.drawable.camera_flash_off);
// 切換前後置攝像頭
private void switchcamera() {
mcurrentcameraid = (mcurrentcameraid + 1) % camera.getnumberofcameras();
camera.setpreviewcallback(null);
camera = camera.open(mcurrentcameraid);
camera.setpreviewdisplay(msurfaceview.getholder());
preview.setcamera(camera);
camera.startpreview();
toast.maketext(mcontext, "未發現相機", toast.length_long).show();
public boolean onkeydown(int keycode, keyevent event) {
if (keycode == keyevent.keycode_back && event.getrepeatcount() == 0) {
setresult(0);
finish();
return true;
return super.onkeydown(keycode, event);
public void onactivityresult(int requestcode, int resultcode, intent data) {
if (requestcode == process) {
if (resultcode == result_ok) {
if (data != null) {
intent.putextra(camera_return_path,
data.getstringextra(camera_path_value2));
setresult(result_ok, intent);
finish();
file dir = new file(data.getstringextra(camera_path_value2));
if (dir != null) {
dir.delete();
總結
1、網上有些示例代碼,擔心相機初始化及開啟時間較長,将初始化及啟動工作單獨放在子線程中,偶爾出現黑屏的情況,但也不是經常出現。
導緻原因:由于單獨開辟了線程去初始化啟動相機,導緻相機的初始化和開啟工作已完成,而找不到畫布控件。若出現此情況,可調試或者将線程睡眠500毫秒。
2、按下home鍵後,再次進入時,為毛黑屏了,如何破?
導緻原因:在oncreate中find了surfaceview,按下home後程式再次進入時,找不到預覽的畫布了,可将find的工作放入onresume中,再就是别忘了在onpause中做如下操作:
@override
注:測試機-------> 小米2a、紅米、華為p8、華為榮耀3c,魅藍note2
附:有些小夥伴經常問手機gif動畫如何制作的,在此也分享下:
注:這代碼有些問題,我會在後面貼上最新的優化代碼,歡迎繼續支援