AndroidGenericFrameworkTemplate
Android通用框架模板
Install / Use
/learn @TanJiaJunBeyond/AndroidGenericFrameworkTemplateREADME
本文章已授权微信公众号郭霖(guolin_blog)转载。
本文章讲解的内容是Android Studio自定义模板——一键生成框架模板代码。
框架GitHub地址:
Dagger2版本:Dagger2
Koin版本:Koin
为了快速使用Android通用框架开发项目,我配置了一套属于它的模板,可以一键生成框架模板代码。
模板GitHub地址:AndroidGenericFrameworkTemplate
使用方法
将模板下载回来,目录如下图所示:

- TanJiaJunActivityForDagger2:用于生成Dagger2版本的Activity对应的xml、Activity和ViewModel。
- TanJiaJunFragmentForDagger2:用于生成Dagger2版本的Fragment对应的xml、Fragment和ViewModel。
- TanJiaJunActivityForKoin:用于生成Koin版本的Activity对应的xml、Activity和ViewModel。
- TanJiaJunFragmentForKoin:用于生成Koin版本的Fragment对应的xml、Fragment和ViewModel。
然后把TanJiaJunActivityForDagger2和TanJiaJunActivityForKoin放到Activity模板目录下,把TanJiaJunActivityForKoin和TanJiaJunFragmentForKoin放到Fragment模板目录下。
Activity模板目录地址:/Applications/Android Studio.app/Contents/plugins/android/lib/templates/activities,如下图所示:

Fragment模板目录地址:/Applications/Android Studio.app/Contents/plugins/android/lib/templates/fragments,如下图所示:

最后重启Android Studio,然后就可以使用这些模板了,如下图所示:
Activity:

Fragment:

创建面板界面如下图所示:

下面用TanJiaJunActivityForDagger2来描述目录结构。
目录结构
目录结构如下图所示:

globals.xml.ftl
用于定义全局变量,代码如下所示:
<?xml version="1.0"?>
<globals>
<#include "../common/common_globals.xml.ftl" />
<global id="hasNoActionBar" type="boolean" value="false" />
<global id="simpleLayoutName" value="${layoutName}" />
<global id="excludeMenu" type="boolean" value="true" />
<global id="generateActivityTitle" type="boolean" value="false" />
<global id="nativeSrcOut" value="${escapeXmlAttribute(projectOut)}/src/main/cpp" />
</globals>
recipe.xml.ftl
该文件可以定义如下常用的标签:
- copy:复制文件到目标目录,可以用于将图标复制到项目的文件夹。
- merge:合并,可以用于将文件和项目中现有的文件合并。
- instantiate:通过FreeMarker将ftl文件中的变量都转换成对应的值,并且生成我们想要的文件。
- open:在代码生成后,打开指定的文件。
FreeMarker是一个模板引擎,它可以用来生成输出文本(例如:HTML网页、电子邮件、配置文件、源代码等)的通用工具,如下图所示:

FreeMarker的工作原理,如下图所示:

代码如下所示:
<?xml version="1.0"?>
<#import "root://activities/common/kotlin_macros.ftl" as kt>
<recipe>
<@kt.addAllKotlinDependencies />
<instantiate
from="root/res/layout/activity_tan_jia_jun_for_dagger2.xml.ftl"
to="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />
<instantiate
from="root/src/app_package/TanJiaJunActivityForDagger2.kt.ftl"
to="${escapeXmlAttribute(srcOut)}/ui/${businessName}/activity/${activityName}.kt" />
<instantiate
from="root/src/app_package/TanJiaJunViewModelForDagger2.kt.ftl"
to="${escapeXmlAttribute(srcOut)}/ui/${businessName}/viewmodel/${viewModelName}.kt" />
<open file="${escapeXmlAttribute(srcOut)}/ui/${businessName}/activity/${activityName}.kt" />
</recipe>
我解释下代码的逻辑:在指定的目录下,用activity_tan_jia_jun_for_dagger2.xml.ftl文件生成**${layoutName}.xml文件,用TanJiaJunActivityForDagger2.kt.ftl文件生成${activityName}.kt文件,用TanJiaJunViewModelForDagger2.kt.ftl文件生成${viewModelName}.kt文件,最后打开${activityName}.kt**文件。
root
存放ftl文件,也就是模板代码,代码如下所示:
activity_tan_jia_jun_for_dagger2.xml.ftl:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="${kotlinEscapedPackageName}.ui.${businessName}.viewmodel.${viewModelName}" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_color">
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
TanJiaJunActivityForDagger2.kt.ftl:
package ${kotlinEscapedPackageName}.ui.${businessName}.activity
import android.os.Bundle
import androidx.activity.viewModels
import ${applicationPackage}.R
import ${applicationPackage}.databinding.Activity${objectKind}Binding
import com.tanjiajun.androidgenericframework.ui.BaseActivity
import ${kotlinEscapedPackageName}.ui.${businessName}.viewmodel.${viewModelName}
class ${activityName} : BaseActivity<Activity${objectKind}Binding, ${viewModelName}>() {
override val layoutRes: Int = R.layout.${layoutName}
override val viewModel by viewModels<${viewModelName}> { viewModelFactory }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
}
TanJiaJunViewModelForDagger2.kt.ftl:
package ${kotlinEscapedPackageName}.ui.${businessName}.viewmodel
import com.tanjiajun.androidgenericframework.ui.BaseViewModel
import javax.inject.Inject
class ${viewModelName} @Inject constructor() : BaseViewModel() {
}
template_blank_activity.png
展示模板界面的缩略图,如下图所示:

template.xml
用于定义创建面板的控件,代码如下所示:
<?xml version="1.0"?>
<template
format="8"
revision="8"
name="TanJiaJun Activity For Dagger2"
minApi="9"
minBuildApi="26"
description="Creates a new activity of Android Generic Framework For Dagger2.">
<category value="Activity" />
<formfactor value="Mobile" />
<parameter
id="packageName"
name="Package Name"
type="string"
constraints="package"
default="com.tanjiajun.androidgenericframework" />
<parameter
id="businessName"
name="Business Name"
type="string"
constraints="nonempty"
default="main" />
<parameter
id="objectKind"
name="Object Kind"
type="string"
constraints="nonempty"
default="TanJiaJun" />
<parameter
id="activityName"
name="Activity Name"
type="string"
constraints="class|unique|nonempty"
suggest="${extractLetters(objectKind)}Activity"
default="TanJiaJunActivity"
help="The name of the activity class to create." />
<parameter
id="layoutName"
name="Layout Name"
type="string"
constraints="layout|unique|nonempty"
suggest="${activityToLayout(activityName)}"
default="activity_tan_jia_jun"
help="The name of the layout to create for the activity." />
<parameter
id="viewModelName"
name="ViewModel Name"
type="string"
constraints="class|unique|nonempty"
suggest="${extractLetters(objectKind)}ViewModel"
default="TanJiaJunViewModel"
help="The name of the viewModel class to create." />
<!-- 128x128 thumbnails relative to template.xml -->
<thumbs>
<!-- default thumbnail is required -->
<thumb>template_blank_activity.png</thumb>
</thumbs>
<globals file="globals.xml.ftl" />
<execute file="recipe.xml.ftl" />
</template>
- packageName:包名,默认值是com.tanjiajun.androidgenericframework。
- businessName:业务名称,默认值是main。
- objectKind:对象类型,默认值是TanJiaJun。
- activityName:Activity名称,默认值是TanJiaJunActivity。
- layoutName:布局名称,默认值是activity_tan_jia_jun。
- viewModelName:ViewModel名称,默认值是TanJiaJunViewModel。
每一个parameter对应创建面板的一个控件,控件的id可以得到用户输入的值,用于渲染ftl文件。
下面以TanJiaJunAcitivityForDagger2为例生成相应的代码。
生成代码
activity_tan_jia_jun.xml,代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.tanjiajun.androidgenericframework.ui.ui.main.viewmodel.TanJiaJunViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_color">
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
TanJiaJunActivity.kt,代码如下所示:
package com.tanjiajun.androidgenericframework.ui.ui.m
Related Skills
node-connect
352.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
111.3kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
352.5kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
352.5kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
