美文网首页Android Android技术知识Android Tech
打造更好用的 Android Studio:添加 Templat

打造更好用的 Android Studio:添加 Templat

作者: iamwent | 来源:发表于2015-11-25 21:19 被阅读5661次

    <b>对模板工程的改造有可能造成 Android Studio 更新失败!</b>*

    最近我从 1.5 -> 1.5.1 更新失败,就是对模板工程的改造造成了冲突!
    <p>

    中午 @drakeet 秀了一波他改造的两个小模板,另外还发了几张官方自带模板的本地位置图片,我也跟着改造了一把。

    添加自定义 Templates

    自定义的位置入口在这儿:

    edit.png

    然后,选择 Templates 按 + 就可以一步步操作啦。

    templates.png

    Description 处有些很有用的说明,这里指出了多个占位符号,可以在根据模板类生成具体的类时替换成合适的字符。

    • 静态内部类实现的单例。
    #if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
    #parse("File Header.java")
    public class ${NAME}{
        public static ${NAME} getInstance() {
            return ${NAME}Holder.sInstance;
        }
    
        private ${NAME}() {
        }
    
        private static class ${NAME}Holder {
            private static final ${NAME} sInstance = new ${NAME}();
        }
    }
    
    • BaseAdapter,引入 provideItemLayout() 方法是为了解决 R 文件引入的包名问题,ViewHolder.bind(Object) 可以将 UI 和数据绑定放在一起。
    #if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
    
    import android.content.Context;
    import android.support.annotation.LayoutRes;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    
    import java.util.List;
    
    #parse("File Header.java")
    public class ${NAME} extends BaseAdapter {
    
        private Context ctx;
        private List<Object> objects;
    
        public ${NAME}(Context ctx, List<Object> objects) {
            this.ctx = ctx;
            this.objects = objects;
        }
    
        private @LayoutRes int provideItemLayout() {
            // todo
            return 0;
        }
    
        @Override
        public int getCount() {
            return objects == null ? 0 : objects.size();
        }
    
        @Override
        public Object getItem(int position) {
            return objects.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            
            if (convertView == null) {
                convertView = LayoutInflater.from(ctx).inflate(provideItemLayout(), parent, false);
                
                holder = new ViewHolder(convertView);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            
            holder.bind(objects.get(position));
            
            return convertView;
        }
    
        public static class ViewHolder {
            
            public ViewHolder(View convertView) {
                // todo
            }
            
            public void bind(Object o) {
                // todo
            }
        }
    }
    
    • RecyclerView Adapter
    #if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
    
    import android.content.Context;
    import android.support.annotation.LayoutRes;
    import android.support.v7.widget.RecyclerView;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    import java.util.List;
    
    #parse("File Header.java")
    public class ${NAME} extends RecyclerView.Adapter<${NAME}.ViewHolder>  {
    
        private Context ctx;
        private List<Object> objects;
    
        public ${NAME}(Context ctx, List<Object> objects) {
            this.ctx = ctx;
            this.objects = objects;
        }
    
        private
        @LayoutRes
        int provideItemLayout() {
            // todo
            return 0;
        }
    
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(ctx).inflate(provideItemLayout(), parent, false);
            return new ViewHolder(view);
        }
    
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            holder.bind(objects.get(position));
        }
    
        @Override
        public int getItemCount() {
            return objects == null ? 0 : objects.size();
        }
    
        public static class ViewHolder extends RecyclerView.ViewHolder {
    
            public ViewHolder(View itemView) {
                super(itemView);
                //todo
            }
    
            public void bind(Object o) {
                // todo
            }
        }
    }
    

    改造 gradle-projects

    在添加了几个自定义的 Templates 之后,我想能不能去改造一下整个 project,让它自动帮我们创建更多的文件、配置更多的内容。

    我曾经想改造一下,但是没有 Google 到方法,然后我创建了一个工程,把必须要的依赖啊、包啊、类啊都配置好,想要以后再新建工程时直接 copy 一份然后修改包名就行了,后来我发现改包名太累,放弃了。

    以下就是手术过程。

    找到模板工程位置:

    AndroidStudio\plugins\android\lib\templates\gradle-projects

    这个下面有多个文件夹,一看名字就知道是干啥的。

    projects.png

    改造前请先备份!

    改造前请先备份!

    改造前请先备份!

    </p>

    先看 NewAndroidProject 有什么可以改造的没有

    研究了一下这个目录下的文件,我发现最重要的是recipe.xml.ftl 这个文件,它描述了工程创建过程应该做些什么,copy 操作是简单的复制,instantiate 操作是实例化,AS 除了生成一些变量替换掉占位符,还会插入一些内容。globals.xml.ftl 则定义了一些常量。据此,我们可以修改的文件是
    NewAndroidProject\root\project_ignoreNewAndroidProject\root\local.properties.ftl,前者是整个工程的 ignore 文件,可以在 https://www.gitignore.io 生成一份拷贝进去,后者我们可以定义一些密码之类的(要确保该文件不会加入版本控制系统)。

    接下来看看 NewAndroidModule 有什么可以改造的没有

    根据前面的经验,先研究一下 recipe.xml.ftl 这个文件,有以下发现:

    1. 第 4 行的 dependency 定义 appcompat-v7
    2. 第 14 行实例化了 build.gradle
    3. 第 19 行创建了 drawable 文件夹
    4. 第 33 行拷贝了 module 的 ignore
    5. 第 37 行生成了 proguard 文件
    6. 第 55 行生成了 res/value/strings.xml

    继续研究 NewAndroidModule\root 下的文件。

    1. build.gradle.ftl 是 module 的 build.gradle 模板,我想提前做点配置进去。我比较疑惑的是第 65 行的 <#if dependencyList?? > ,这里看起来是某个地方定义了一个依赖列表,但是并没有发现。回过头去看 recipe.xml.ftl ,它的第 4 行是 <dependency mavenUrl="com.android.support:appcompat-v7:${buildApi}.+"/> ,我猜测可能这就是定义的地方,于是在这后面仿写了一句 <dependency mavenUrl="com.jakewharton:butterknife:7.0.1"/> ,创建工程验证确实如我所猜测的那样。
    2. module_ignore 最简单,根据我们的需要再添加一些语句就行
    3. proguard-rules.txt.ftl 会被实例化到 proguard-rules.pro,可以根据对 build.gradle.ftl 的修改适当修改

    还可以继续改造的是:自动生成一些包,让程序架构更清晰,先把架子搭起来嘛。

    参考资料

    1. File and Code Templates
    2. 使用FreeMarker模板引擎自定义Android工程模板
    3. AndroidStudioTemplate

    相关文章

      网友评论

      • d0c4c240eadd:Hi,博主你好,不知道你有没有尝试过在gradle-projects下新增一个module模板过呢
      • changlg:不知道默认的dimens.xml是在哪里配置的,我想在里面自动生成点常用的
        changlg:@iamwent 目录下没有dimens.xml,不知道是在哪里构建出来的
        iamwent:@changlg 你参看 strings.xml 的生成方式找一找
      • 捡淑:66666
      • c26906a538a5:帮了大忙,谢谢
      • atomic_volatile:好文章竟然木有点赞,我先来一个!
        iamwent:@阿童木online 哈,肥皂家给我带来了一波读者

      本文标题:打造更好用的 Android Studio:添加 Templat

      本文链接:https://www.haomeiwen.com/subject/pnbltttx.html