Android应用开发Camera系列(一):SurfaceView实现相机预览demo--新手上路

来源:互联网 发布:书林文学软件下载 编辑:程序博客网 时间:2024/06/04 18:13

    这是工作第一份任务。任务要求是用GLSurfaceView做相机预览,笔者只有那么一点安卓常识,完全不知道GLSurfaceView的存在,故用SurfaceView做好就交工了,才发现,搬砖之前要搞清楚搬哪块砖啊!

    进入正题。SurfaceView是一个类,类名是SurfaceView。它可以做很多事情,今天只拿来做视图!就是屏幕上你能看见的(这句话套用在Activity上也适用)。提醒:毫无基础从一看起,只要重点直接到四,括号内容可以忽略。

    开始流程:

    一、安卓程序运行是从AndroidMainfest.xml中查找MainActivity开始

/AndroidMainfest.xml

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="org.kintai.cameratest"    android:versionCode="1"    android:versionName="1.0" >    <uses-sdk        android:minSdkVersion="8"        android:targetSdkVersion="18" />    <uses-permission android:name="android.permission.CAMERA" />    <application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme" >        <activity            android:name="org.kintai.cameratest.MainActivity"            android:label="@string/app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>

   说明:这里要学的东西还是蛮多的,但基本上不用你学,会改就行(you know ,copy right?)。

    注意:包名(package)!!!要用相机当然要加使用相机的权限(permission)!!!还有你的SDK版本不对就自行修改一下。

    二、找到MainActivity.java之后呢,之后是执行onCreate方法

/src/org.kintai.cameratest/MainActivity.java

package org.kintai.cameratest;import android.os.Bundle;import android.app.Activity;import android.content.pm.ActivityInfo;import android.util.Log;import android.view.Window;public class MainActivity extends Activity {private static final String TAG = "Kintai";private MySurfaceView mView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);// 横屏requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题initUI();setContentView(R.layout.activity_main);}private void initUI() {Log.d(TAG, "initUI...");mView = (MySurfaceView) findViewById(R.id.mView);}}
    再次说明:

1.这个MainActivity和C/C++程序中main起的名字都很像,所以作用也很像。进来之后首先会在onCreate方法内执行相应代码,之前呢?之前会加载一些static库,一般NDK才有。有些情况需要注意代码的顺序 (比如在口袋里的钱包取钱这个动作,一般顺序:手——口袋——钱包——钱;非一般顺序:手——钱,能确定拿到的钱 数额 就是你要的么?不够再拿~.~)

2.initUI方法。这个是笔者写的,各式各样都有,名字要直观,就是初始化界面,用于当前Activity上加载视图SurfaceView,即这里的mView。有些小地方需要在程序调试过程中慢慢体验(横屏、去标题、log.d是有点多余的,不写也行,就是这里放放。这个都不知道,LogCat就更不用说了)

3.findViewById方法。传的参数是 R.id.mView ,与R相关的是自动生成的东西,它一般在xml中,只要写的合法就会自动生成,为什么要等它生成在R里面才能拿来用?安全起见,用不合规则的砖会把程序搞蹦跶呢。(很不幸每一个安卓初学者都要接触这个东西,用它找TextView然后贴上“HelloWorld”...)

    三、mView要在布局文件activity_main.xml中注册,findViewById才能找到它

/res/layout/activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity" >    <org.kintai.cameratest.MySurfaceView        android:id="@+id/mView"        android:layout_width="fill_parent"        android:layout_height="fill_parent" />    <Button        android:id="@+id/btn"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="点击" /></RelativeLayout>
    再次注意:

1.context对应的名字要写对,名字前面有个“.”这里是 .MainActivity 。

2.MySurfaceView在后面创建。(Button无关紧要,就是后面要拍照啊,要切换前后摄像头可能会用到,就先贴一个在这里)

    四、MySurfaceView.java非常关键,负责将相机看到的内容展示在屏幕上

/src/org.kintai.cameratest/MySurfaceView.java

package org.kintai.cameratest;import java.io.IOException;import android.content.Context;import android.hardware.Camera;import android.util.AttributeSet;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;public class MySurfaceView extends SurfaceView implementsSurfaceHolder.Callback {private static final String TAG = "Kintai";private static SurfaceHolder holder;private Camera mCamera;public MySurfaceView(Context context, AttributeSet attrs) {super(context, attrs);Log.i(TAG, "new View ...");holder = getHolder();//后面会用到!holder.addCallback(this);}@Overridepublic void surfaceCreated(SurfaceHolder arg0) {Log.i(TAG, "surfaceCreated...");if (mCamera == null) {mCamera = Camera.open();//开启相机,可以放参数 0 或 1,分别代表前置、后置摄像头,默认为 0try {mCamera.setPreviewDisplay(holder);//整个程序的核心,相机预览的内容放在 holder} catch (IOException e) {e.printStackTrace();}}}@Overridepublic void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {Log.i(TAG, "surfaceChanged...");mCamera.startPreview();//该方法只有相机开启后才能调用}@Overridepublic void surfaceDestroyed(SurfaceHolder arg0) {Log.i(TAG, "surfaceChanged...");if (mCamera != null) {mCamera.release();//释放相机资源mCamera = null;}}}

    讲解:MySurfaceView继承至SurfaceView,实现了SurfaceHolder.Callback接口

1.从构造器(方法名和类名一样的)开始就有不一样的味道,一般只有context参数,这里多了个AttributeSet参数。这是因为 SurfaceView写在布局xml,而要从xml中通过findViewById方法生成视图则有此 特定的要求,如果不写则无法生成MySurfaceView的实例.(onCreate中setContentView直接加载SurfaceView则不用)

2.构造器里的holder。一直不理解为什么会有这样的东西,后来想想。一个视图是很大一块内存,如果不给它起个名字或者取个地址,要用到的时候怎么传啊?使用getHolder就找到它了,同时还要添加一个回调addCallback,代表holder和this (即这个类的本体) 的一种关联。

3.Callback接口。要用接口就要实现其带来的功能,即方法。这里有三个SurfaceCreated、SurfaceChanged和SurfaceDestoryed,参数可以不用管先,暂时并不用在视图上做特殊操作,只要求把相机的预览呈现。

    SurfaceCreated:

                     View创建的时候调用,这里做了两个事情打开相机,设置预览显示;

                     预览显示当然需要界面,故有try~catch;

                     mCamera是相机实体,通过Camera.open指定该实体是后置摄像头,方便后续调用;

     SurfaceChanged:

                     View有变化的时候调用,其实它一直在变化...

                                   mCamera要用到了,startPreview开始预览;

   SurfaceDestoryed:

                                   View在销毁的时候调用,就是要随手关灯;

                                    mCamera又要用到了,release释放资源,mCamera不指定;

预览效果图:

源码地址:

-----------------------------------------------------------------------------------Kintai原创,欢迎转载

</pre><p></p><pre name="code" class="java">  
0 0
原创粉丝点击