这篇文章介绍自定义Android 项目模板,分为两部分:

  • 修改 new Project 的默认设置,用于生成新项目的时候,添加自定义的目录、文件、内容。例如:asset文件、anim文件、arrays.xml等;
  • 修改 new xxx 的默认设置,用于已经存在的项目,生成模板代码,如图所示:
  • 修改 new Project 的默认设置

    用于生成新项目的时候,添加自定义的目录、文件、内容。

    进入 Android Studio 安装目录,依次进入 plugins --> android --> lib --> templates --> gradle-projects --> NewAndroidModule,然后用编辑器打开 recipe.xml.ftl 文件, recipe.xml.ftl 文件就是创建新项目的默认设置文件。

    增加默认生成目录

    一般我们创建新的项目的时候,默认都会生成如下的文件层次结构:

    MyProject/
        src/
            MyActivity.java
            drawable/
                graphic.png
            layout/
                main.xml
                info.xml
            mipmap/
                icon.png
            values/
                strings.xml
    复制代码

    但是一般项目开发只有这些是远远不够的,这时候我们就可以修改设置,默认生成我们所需要的资源文件,所有项目 res/ 目录中支持的资源目录有:

    需以原始形式保存的任意文件。如要使用原始 InputStream 打开这些资源,请使用资源 ID(即 R.raw.filename)调用 Resources.openRawResource()。但是,如需访问原始文件名和文件层次结构,则可以考虑将某些资源保存在 assets/ 目录(而非 res/raw/)下。assets/ 中的文件没有资源 ID,因此您只能使用 AssetManager 读取这些文件。 values/ 包含字符串、整型数和颜色等简单值的 XML 文件。

    如图在 recipe.xml.ftl 中加入如下代码,就可以默认生成

    代码如下:

        <mkdir at="${escapeXmlAttribute(projectOut)}/libs" />
        <mkdir at="${escapeXmlAttribute(resOut)}/drawable" />
        <mkdir at="${escapeXmlAttribute(resOut)}/drawable-hdpi" />
        <mkdir at="${escapeXmlAttribute(resOut)}/drawable-xhdpi" />
        <mkdir at="${escapeXmlAttribute(resOut)}/drawable-xxhdpi" />
        <mkdir at="${escapeXmlAttribute(resOut)}/anim" />
        <mkdir at="${escapeXmlAttribute(resOut)}/animator" />
        <mkdir at="${escapeXmlAttribute(resOut)}/color" />
        <mkdir at="${escapeXmlAttribute(resOut)}/menu" />
         <mkdir at="${escapeXmlAttribute(resOut)}/raw" />
        <mkdir at="${escapeXmlAttribute(resOut)}/xml" />
        <mkdir at="${escapeXmlAttribute(resOut)}/font" />
        <mkdir at="${escapeXmlAttribute(projectOut)}/assets" />
    复制代码

    mkdir 代表创建目录; projectOut 代表项目即 MyProject 目录下; resOut 代表 res 目录下。

    默认生成 values/ 目录下的xml文件

    values/ 目录下常用的xml文件如下:

  • arrays.xml:资源数组(类型数组)。
  • colors.xml:颜色值。
  • dimens.xml:尺寸值。
  • strings.xml:字符串值。
  • styles.xml:样式
  • attrs.xml:view属性
  • 进入 Android Studio 安装目录,依次进入 plugins --> android --> lib --> templates --> gradle-projects --> NewAndroidModule-->root-->res-->values目录下,在该目录下,创建 arrays.xml dimens.xml attrs.xml 。代码如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <resources> 
    </resources>
    复制代码

    然后在 recipe.xml.ftl 中设置默认创建这些文件,如图所示:

    代码如下:

       <instantiate from="root/res/values/arrays.xml"
                       to="${escapeXmlAttribute(resOut)}/values/arrays.xml" />               
        <instantiate from="root/res/values/dimens.xml"
                       to="${escapeXmlAttribute(resOut)}/values/dimens.xml" />
        <instantiate from="root/res/values/attrs.xml"
                       to="${escapeXmlAttribute(resOut)}/values/attrs.xml" />   
    复制代码

    instantiate 表示将 root/res/values/arrays.xml 目录下的 arrays.xml 复制到项目的 res 目录下。

    自定义xml文件

    strings.xml

    <!--常用的-->
    <string name="common_login">登录</string>
    <string name="common_register">注册</string>
    <string name="common_cancel">取消</string>
    <string name="common_sure">确定</string>
    <string name="common_share">分享</string>
    <string name="common_setting">设置</string>
    <string name="common_help">帮助</string>
    <string name="common_icon">头像</string>
    <string name="common_introduction">简介</string>
    <string name="common_edit">编辑</string>
    <string name="common_search">搜索</string>
    <string name="common_email">邮箱</string>
    <string name="common_phone">手机号</string>
    <string name="common_password">密码</string>
    <string name="common_recommend">推荐</string>
    <string name="common_nickname">昵称</string>
    <string name="common_user_name">用户名</string>
    <string name="common_about_us">关于我们</string>
    <string name="common_feedback_titlle">意见反馈</string>
    <string name="common_favourite">我的收藏</string>
    <string name="common_history">历史记录</string>
    <string name="common_out_of_login">退出登录</string>
    <string name="common_update">检查更新</string>
    <string name="common_forget_password">忘记密码</string>
    <string name="common_retrieve_password">找回密码</string>
    <string name="common_message">我的消息</string>
    
  • 登录注册相关
  • <!--登录注册相关-->
    <string name="login_error">登录失败</string>
    <string name="login_register_error">注册失败</string>
    <string name="login_error_reason">用户名或者密码错误</string>
    <string name="login_phone_format_error">手机格式有误</string>
    <string name="login_phone_not_empty">手机号不能为空</string>
    <string name="login_password_not_empty">密码不能为空</string>
    <string name="login_nickname_not_empty">昵称不能为空</string>
    <string name="login_user_name_not_empty">用户名不能为空</string>
    <string name="login_vertify_code_not_empty">验证码不能为空</string>
    <string name="login_verification_code">验证码</string>
    <string name="login_phone_not_available">手机号不可用</string>
    <string name="login_send_code_error">发送验证码失败</string>
    <string name="login_vertify_code_error">验证码有误</string>
    <string name="login_send_code_btn_normal_tip">发送验证码</string>
    
  • 视频播放相关
  • <!--视频播放相关-->
    <string name="video_loading">加载中…</string>
    <string name="video_downloaded">离线缓存</string>
    <string name="video_quality_medium">清晰</string>
    <string name="video_quality_smooth">流畅</string>
    <string name="video_quality_super">超清</string>
    <string name="video">视频</string>
    <string name="video_local">本地视频</string>
    <string name="video_short">短视频</string>
    <string
    
    
    
    
        
     name="video_care">关注</string>
    <string name="video_">视频</string>
    <string name="video_fans">粉丝</string>
    <string name="video_play">次播放</string>
    <string name="video_comment">评论</string>
    复制代码

    如图所示,打开strings.xml.ftl文件,并将上述代码复制到该文件中。

    styles.xml

  • 将默认的DarkActionBar改为NoActionBar
  • <resources>
        <!-- Base application theme. -->
        <style name="AppTheme" parent="Theme.AppCompat<#if
                minApiLevel gte 11>.Light</#if><#if
                minApiLevel gte 14>.NoActionBar</#if>"><!--这里将DarkActionBar改为NoActionBar-->
            <!-- Customize your theme here. -->
    <#if (buildApi gte 22) >
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
        </style>
    </resources>
    
  • 设置自定义的style
  • 我们可以设置自定义的style,在这里我添加有关欢迎页的style,用来解决app打开出现的白屏问题(具体的看Android冷启动白屏问题)以及Dialogstyle。代码如下:

    <resources>
    <!--设置欢迎页的style-->
    <style name="SplashStyle" parent="AppTheme">
        <item name="android:windowNoTitle">true</item>
        <item name="android:textAllCaps">false</item>
        <item name="windowActionBar">false</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowBackground">@color/colorAccent</item><!-- 设置欢迎页的背景,这里设置为颜色值 -->
    </style>
    <!--设置Dialog的style-->
    <style name="MyDialogStyle" parent="Theme.AppCompat.Light.NoActionBar">
            <item name="android:windowBackground">@android:color/transparent</item><!--背景透明-->
            <item name="android:windowFrame">@null</item><!--边框-->
            <item name="android:windowNoTitle">true</item><!--无标题-->
            <item name="android:windowIsFloating">true</item><!--是否浮现在activity之上-->
            <item name="android:windowIsTranslucent">true</item><!--半透明-->
            <item name="android:windowContentOverlay">@null</item><!--内容覆盖 -->
            <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item><!-- 窗口样式Dialog -->
            <item name="android:backgroundDimEnabled">true</item><!--模糊-->
        </style>
    </resources>
    复制代码

    其他文件,比如arrays.xmldimens.xmlattrs.xml等可以根据自己的需求自己设置,这里不再累述。

    添加默认依赖

    如图在recipe.xml.ftl文件中添加默认生成的依赖:

    <!--/** gson **/-->
    <dependency mavenUrl="com.google.code.gson:gson:2.8.5" />
    <!--/** okhttp **/-->
    <dependency mavenUrl="com.squareup.okhttp3:okhttp:3.14.1" />
    <!--/** glide **/-->
    <dependency mavenUrl="com.github.bumptech.glide:glide:4.9.0" />
    <!--/** rxjava **/-->
    <dependency mavenUrl="io.reactivex.rxjava2:rxjava:2.0.1" />
    <dependency mavenUrl="io.reactivex.rxjava2:rxandroid:2.0.1" />
    <!--/** retrofit**/-->
    <dependency mavenUrl="com.squareup.retrofit2:retrofit:2.1.0" />
    <dependency mavenUrl="com.squareup.retrofit2:converter-gson:2.0.2" />
    <dependency mavenUrl="com.squareup.retrofit2:adapter-rxjava:2.1.0" />
    复制代码

    其他依赖可根据自己的开发习惯自行添加。

    注意如果直接使用<dependency mavenUrl="com.google.code.gson:gson:2.8.5" />默认会生成implementation 'com.google.code.gson:gson:2.8.5';如果需要使用annotationProcessor,则要添加gradleConfiguration="annotationProcessor"属性,例如<dependency mavenUrl="xxxx" gradleConfiguration="annotationProcessor"/>

    修改AndroidManifest.xml的默认生成

    AndroidManifest.xml的配置文件为plugins --> android --> lib --> templates --> gradle-projects --> NewAndroidModule-->root中的shared_macros.ftl;

    添加默认生成的权限

    常用的权限有:

  • <uses-permission android:name="android.permission.INTERNET" /> :允许联网
  • <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> :获取sd卡的读写权限
  • <uses-permission android:name="android.permission.READ_PHONE_STATE" /> :获取手机状态
  • <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> : 获取网络状态信息
  • <uses-permission android:name="android.permission.WRITE_CALENDAR" /> :读写日历信息
  • <uses-permission android:name="android.permission.CAMERA" /> : 使用相机
  • <uses-permission android:name="android.permission.WRITE_CONTACTS" />: 允许编辑通讯录信息
  • <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />:获取精准的 (GPS) 位置
  • <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />:获取 (基于网络的) 大概位置
  • <uses-permission android:name="android.permission.RECORD_AUDIO" /> : 录音
  • <uses-permission android:name="android.permission.SEND_SMS" /> : 发送短信
  • 如图往shared_macros.ftl文件中添加权限:

    代码如下:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />`
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    复制代码

    允许http请求

    在Android P中默认不允许http请求,要求用https,但是图片的请求一般需要使用http,这个时候我们就可以通过往AndroidManifest.xml中添加android:usesCleartextTraffic="true"属性就可以使用http,如图所示:

    修改new xxx的默认设置

    进入 Android Studio 安装目录,依次进入 plugins --> android --> lib --> templates,如图创建了Easy_otherEasy_activities文件,用来存放自定义的生成模板。

    生成普通的Java类模板

    这里用生成FileUtil这个工具类为例。首先打开other文件夹,找到common文件夹和CustomView文件夹复制到Easy_other中,前者是通用的文件夹不需要更改,而后者是我们需要更改为FileUtil文件夹。

  • 第一步:将CustomView文件夹重命名为FileUtil
  • 第二步:编辑template.xml文件,参数说明见这里,代码如下
  • <?xml version="1.0"?>
    <template
        format="5"
        revision="3"
        name="FileUtil"//模板名
        description="文件操作工具类">//描述
        <category value="Easy" />//定义了模板所属的分类
        <parameter
            id="packageName"
            name="Package name"
            type="string"
            constraints="package"
            default="com.mycompany.myapp" />
        <parameter
            id="viewClass"
            name="FileUtil"
            type="string"
            constraints="class|unique|nonempty"
            default="FileUtil"
            help="类名" />
        <globals file="globals.xml.ftl" />
        <execute file="recipe.xml.ftl" />
    </template>
    
  • 第三步:编辑recipe.xml.ftl文件,删除生成布局文件的代码,结果如下:
  • <?xml version="1.0"?>
    <#import "root://activities/common/kotlin_macros.ftl" as kt>
    <recipe>
        <@kt.addAllKotlinDependencies />
        <instantiate from="root/src/app_package/CustomView.${ktOrJavaExt}.ftl"
                       to="${escapeXmlAttribute(srcOut)}/${viewClass}.${ktOrJavaExt}" />
        <open file="${escapeXmlAttribute(srcOut)}/${viewClass}.${ktOrJavaExt}" />
    </recipe>
    
  • 第四步:进入root-->src-->app_package,并编辑CustomView.java.ftl(如果使用kotlin就编辑CustomView.kt.ftl),代码如下:
  • package ${packageName};
    import android.util.Log;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.text.DecimalFormat;
     * 文件操作工具类
    public class FileUtil {
         * 在指定的位置创建指定的文件
         * @param filePath 完整的文件路径
         * @param
    
    
    
    
        
     mkdir 是否创建相关的文件夹
         * @throws Exception
        public static void mkFile(String filePath, boolean mkdir) throws Exception {
            File file = new File(filePath);
            file.getParentFile().mkdirs();
            file.createNewFile();
            file = null;
         * 在指定的位置创建文件夹
         * @param dirPath 文件夹路径
         * @return 若创建成功,则返回True;反之,则返回False
        public static boolean mkDir(String dirPath) {
            return new File(dirPath).mkdirs();
         * 删除指定的文件
         * @param filePath 文件路径
         * @return 若删除成功,则返回True;反之,则返回False
        public static boolean delFile(String filePath) {
            return new File(filePath).delete();
         * 删除指定的文件夹
         * @param dirPath 文件夹路径
         * @param delFile 文件夹中是否包含文件
         * @return 若删除成功,则返回True;反之,则返回False
        public static boolean delDir(String dirPath, boolean delFile) {
            if (delFile) {
                File file = new File(dirPath);
                if (file.isFile()) {
                    return file.delete();
                } else if (file.isDirectory()) {
                    if (file.listFiles().length == 0) {
                        return file.delete();
                    } else {
                        int zfiles = file.listFiles().length;
                        File[] delfile = file.listFiles();
                        for (int i = 0; i < zfiles; i++) {
                            if (delfile[i].isDirectory()) {
                                delDir(delfile[i].getAbsolutePath(), true);
                            delfile[i].delete();
                        return file.delete();
                } else {
                    return false;
            } else {
                return new File(dirPath).delete();
         * 复制文件/文件夹 若要进行文件夹复制,请勿将目标文件夹置于源文件夹中
         * @param source 源文件(夹)
         * @param target 目标文件(夹)
         * @param isFolder 若进行文件夹复制,则为True;反之为False
         * @throws Exception
        public static void copy(String source, String target, boolean isFolder)
                throws Exception {
            if (isFolder) {
                (new File(target)).mkdirs();
                File a = new File(source);
                String[] file = a.list();
                File temp = null;
                for (int i = 0; i < file.length; i++) {
                    if (source.endsWith(File.separator)) {
                        temp = new File(source + file[i]);
                    } else {
                        temp = new File(source + File.separator + file[i]);
                    if (temp.isFile()) {
                        FileInputStream input = new FileInputStream(temp);
                        FileOutputStream output = new FileOutputStream(target + "/" + (temp.getName()).toString());
                        byte[] b = new byte[1024];
                        int len;
                        while ((len = input.read(b)) != -1) {
                            output.write(b, 0, len);
                        output.flush();
                        output.close();
                        input.close();
                    if (temp.isDirectory()) {
                        copy(source + "/" + file[i], target + "/" + file[i], true);
            } else {
                int byteread = 0;
                File oldfile = new File(source);
                if (oldfile.exists()) {
                    InputStream inStream = new FileInputStream(source);
                    File file = new File(target);
                    file.getParentFile().mkdirs();
                    file.createNewFile();
                    FileOutputStream fs = new FileOutputStream(file);
                    byte[] buffer = new byte[1024];
                    while ((byteread = inStream.read(buffer)) != -1) {
                        fs.write(buffer, 0, byteread);
                    inStream.close();
                    fs.close();
     ...https://juejin.im/user/5a7cec9af265da4e7b449b50
    复制代码

    最后保存,就可以直接生成。

    Activity类模板

    这里用CameraActivity为例,具体关于自定义Camera可以看Android平台Camera开发实践指南.

    和上面创建FileUtil类似,首先打开activities文件夹,找到common文件夹和EmptyActivity文件夹复制到Easy_activities中,前者是通用的文件夹不需要更改,而后者是我们需要更改为CameraActivity文件夹。

  • 第一步:将EmptyActivity文件更改为CameraActivity文件
  • 第二步:编辑template.xml文件,参数说明见这里
  • 代码如下:

    <?xml version="1.0"?>
    <template
        format="5"
        revision="5"
        name="CameraActivity"  //模板名
        minApi="9"
        minBuildApi="14"
        description="创建CameraActivity">//描述
        <category value="Easy" /> //定义了模板所属的分类
        <formfactor value="Mobile" />
       ... //只需要更改上面就行
        <!-- 128x128 thumbnails relative to template.xml -->
        <thumbs> //预览图
            <!-- default thumbnail is required -->
            <thumb>template_blank_activity.png</thumb>
        </thumbs>
        <globals file="globals.xml.ftl" /> //指定了 global 文件
        <execute file="recipe.xml.ftl" /> //指定了 recipe 文件
    </template>
    
  • 修改recipe.xml.ftl文件,由于EmptyActivity使用默认的布局,所以我们需要修改该文件,使用我们自定义的布局
  • <?xml version="1.0"?>
    <#import "root://activities/common/kotlin_macros.ftl" as kt>
    <recipe>
        <#include "../common/recipe_manifest.xml.ftl" />
        <@kt.addAllKotlinDependencies />
    <!--需要删除的-->
    <!--<#if generateLayout>-->
    <!--    <#include "../common/recipe_simple.xml.ftl" />-->
    <!--    <open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />-->
    <!--</#if>-->
        <instantiate from="root/src/app_package/SimpleActivity.${ktOrJavaExt}.ftl"
                       to="${escapeXmlAttribute(srcOut)}/${activityClass}.${ktOrJavaExt}" />
        <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.${ktOrJavaExt}" />
        <!--增加的,这里的layoutName是上面template.xml中设置布局文件的id-->
        <instantiate from="root/res/layout/sample.xml.ftl"
                       to="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />
        <open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />     
    </recipe>
    
  • 第三步:在root文件下新建res目录,并在res目录下创建layout目录,在layout目录下创建sample.xml.ftl文件
  • 代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <SurfaceView
            android:id="@+id/camera_view"
            android:layout_gravity="center"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
        <ImageView
            android:layout_marginTop="20dp"
            android:id="@+id/camera"
            android:layout_gravity="end"
            android:layout_marginEnd="10dp"
            android:src="@drawable/camera"
            android:layout_width="35dp"
            android:layout_height="35dp" />
    </FrameLayout>
    
  • 第四步:编辑root-->src-->app_packge-->SimpleActivity.java.ftl文件
  • 代码(部分)如下

    package ${packageName};
    import ${superClassFqcn};
    import android.os.Bundle;
    import android.hardware.Camera;
    import android.view.SurfaceView;
    import com.easy.generaltool.common.SimpleException;
    import android.annotation.SuppressLint;
    import android.annotation.TargetApi;
    import android.content.Context;
    import android.graphics.ImageFormat;
    import android.hardware.camera2.CameraAccessException;
    import android.hardware.camera2.CameraCaptureSession;
    import android.hardware.camera2.CameraCharacteristics;
    import android.hardware.camera2.CameraDevice;
    import android.hardware.camera2.CameraManager;
    import android.hardware.camera2.CaptureFailure;
    import android.hardware.camera2.CaptureRequest;
    public class ${activityClass} extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    <#if generateLayout>
            setContentView(R.layout.${layoutName});
           <#include "../../../../common/jni_code_usage.java.ftl">
    <#elseif includeCppSupport!false>
            // Example of a call to a native method
            android.util.Log.d("${activityClass}", stringFromJNI());
    </#if>
    <#include "../../../../common/jni_code_snippet.java.ftl">
    //Camera的工具类,适用于android5以下
    class Camera1Helper{
       private int numberOfCameras;
       private int faceFrontCameraId;
       private int faceBackCameraId;
       private int faceBackCameraOrientation;
       private int faceFrontCameraOrientation;
       private int state;
       private Camera camera;
       private SurfaceView surfaceView;
       private boolean isTakeVideo = false;
       private Camera1RecorderUtils utils;
        Camera1Helper(int state, SurfaceView surfaceView) {
           this.state = state;
           this.surfaceView = surfaceView;
           utils = new Camera1RecorderUtils();
           init();
       private void init(){
           //有多少个摄像头
           numberOfCameras = Camera.getNumberOfCameras();
           for (int i = 0; i < numberOfCameras; ++i) {
               final Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
               Camera.getCameraInfo(i, cameraInfo);
               //后置摄像头
               if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                   faceBackCameraId = i;
                   faceBackCameraOrientation = cameraInfo.orientation;
               //前置摄像头
               else if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                   faceFrontCameraId = i;
                   faceFrontCameraOrientation = cameraInfo.orientation;
       public void change(){
           if (isTakeVideo)return;
           if (state == CameraHelper.CAMERA_BACK)
               state = CameraHelper.CAMERA_FRONT;
               state = CameraHelper.CAMERA_BACK;
           camera.stopPreview();
           camera.release();
           openCamera();
       public void openCamera(){
           camera = null;
           if (state == CameraHelper.CAMERA_BACK)
               camera = Camera.open(faceBackCameraId);
           else if (state == CameraHelper.CAMERA_FRONT)
               camera = Camera.open(faceFrontCameraId);
           else{
               throw new SimpleException("can not find what you need camera");
           try {
               camera.setPreviewDisplay(surfaceView.getHolder());
               camera.setDisplayOrientation(90);
               Camera.Parameters mParameters = camera.getParameters();
               mParameters.setPictureSize(720, 480);//设置图片尺寸
               mParameters.setPreviewSize(720, 480);//设置预览尺寸
               camera.setParameters(mParameters);
           } catch (IOException e) {
               e.printStackTrace();
           camera.startPreview();
       public void takePhoto(CameraHelper.OnTakePictureFinishCallback callback) {
           if (camera!=null)
               camera.takePicture(null, null, (data, camera) -> {
                   callback.finish(data);
                   camera.startPreview();
       public void startVideoRecord(String path, String name) {
           isTakeVideo = true;
           utils.create(surfaceView,Camera1RecorderUtils.WH_720X480,camera);
           utils.startRecord(path,name);
       public void stopVideoRecord() {
           utils.stopRecord();
           isTakeVideo = false;
       public void closeCamera(){
           if (camera==null)return;
           camera.stopPreview();
           camera.release();
           utils.destroy();
    复制代码

    最后保存,重启android studio即可通过new --> Easy --> CameraActivity生成指定的代码

    template.xml的参数说明

    来自大幅提高Android开发效率之Android项目模板化

  • template 标签,整个 xml 的根节点,其中 name属性为模板名称,description属性为模板的描述。
  • category标签,定义了模板所属的分类,即图四中的分类列表中的分类,分类名一样的模板会被归纳到同一目录下。
  • parameter 标签,定义了模板输入弹窗中的输入参数,每个 parameter 为一行。其中:
  • id 属性为参数唯一标识,我们可以在代码中通过 id来使用该参数。
  • name 属性为参数名称,显示在输入控件的前面或后面。
  • type属性为参数类型,根据该属性和constraints属性的值综合比较后参数会被渲染成不同的输入形式,比如 string 类型会显示输入框,而 boolean类型会显示一个选择框。
  • constraints属性为输入约束,常见的有class,代表类名;layout代表布局名;package 代表包路径; unique则是不能与现有的重复;nonemptye表示不能为空。
  • suggest 和 default标签,前者是建议名称,后者是默认名称,前者优先级高于后者。
  • help属性是参数输入提示,当该参数获取焦点后,对应的帮助信息会显示在对话框上。
  • thumbs标签定义了该目标的缩略图,这也就是template_blank_activity.png文件的作用了。
  • globals标签指定了 global 文件,用 global 标签定义了一系列的全局参数(这里的全局是指可以在其他模板文件中使用它们)供具体的模板文件使用,id为唯一标识,type为类型,value为参数值。
  • execute标签,跟字面上的意思一样,执行 recipe.xml.ftl文件的内容,将模板文件生成具体的可用文件。
  • 如果想看Android Studio Live Templates快捷键常用插件,可以看:

  • 让你变懒的 Android Studio Live Templates
  • Android Studio快速开发之道
  • Android Studio 推荐插件
  • 分类:
    阅读
    标签: