AndroidStudio-代码快捷键&模板

AS 快捷键

速查表列出了keymap快捷键的名称. 可以直接通过AS setting界面搜索keymap. 通过对应的快捷键名称来添加或者修改快捷键.

功能描述 keymap对应名字 Mac Win/Linux
提示错误解决方案 Show Intention Actions option + enter alt + enter
AS配置界面 Preferences command + , control+alt+S
工程项目配置界面 Project Structure command + ; Control+Alt+Shift+S
快速构成代码 Code Generate command + N alt + insert
代码提示 Completion/Basic control + space(mac会冲突, 手动修改) ctrl + 空格(win同样大部分和输入法冲突, 手动修改)
选择视图 select in any view option + F1 alt + F1
添加书签标识 Toggle Bookmark option + F3 ctrl + F11
显示书签 Show Bookmarks command + F3 shift + F11
添加书签 Toggle Bookmark F3 F11
向下移动一行 Move Line Down option + shift + Down alt + shift + Down
向上移动一行 Move Line Up option + shift + Up alt + shift + Up
注释代码 Comment with Line Comment command + / ctrl + /
用代码模板包裹代码 surround with Live Template command + option + J ctrl + alt + J
格式化代码 Reformat Code command + option + L ctrl + alt + L
Copy Reference Copy Reference command + option + shift + C ctrl + alt + shift + C
if/try等包裹代码 Surround With.. command + option + T ctrl + alt + T
查看声明 Declaration command + B ctrl + B
快捷向下复制行 Duplicate Line or Block command + D ctrl + D
删除行 Delete Line command + delete ctrl + Y
快捷最近打开 Recent Files command + E ctrl + E
查找 Edit/Find/Find command + F ctrl + F
全路径查找 Find in Path command + shift + F ctrl + shift + F
文件方法结构(类似eclipse中的Ctrl+O) File Structure command + F12 ctrl + F12
代码高亮向下查找 Move To Next Occurrence command + G F3
代码高亮向上查找 Move To Previous Occurrence command + shift + G shift + F3
按照模板生成代码 Insert Live Template command + J ctrl + J
定位到行 Navigate/Line command + L ctrl + G
快速到行首/尾 Move Caret to Line Start/End command + Left/Right ctrl + Left/Right
代码折叠/展开 Collapse/Expand command + 减号/加号 ctrl + 减号/加号
查找类 Navigate/Class command + O ctrl + N
多行注释 **Code/Comment ** command + option + / ctrl + alt + /
格式化代码 Reformat Code command + option + L ctrl + alt + L
提示参数类型 Parameter Info command + P ctrl + P
查找替换 Replace command + R ctrl + R
查找命令 Find Action command + shift + A ctrl + shift + A
拷贝文件路径 Copy Paths command + shift + C ctrl + shift + C
移动代码块 Move Statement Up/Down command + shift + down/up ctrl + shift + down/up
代码补全 Complete Current Statement command + shift + enter ctrl + shift + enter
代码高亮 Highlight Usages in File command + shift + F7 alt + J
窗口内所有代码折叠/展开 Collapse/Expand All command + shift + 减号/加号 ctrl + shift + 减号/加号
查找文件 Navigate/File command + shift + O ctrl + shift + N
全路径中替换 Replace in Path command + shift + R ctrl + shift + R
大小写转换 Toggle Case command + shift + U ctrl + shift + U
显示粘贴版历史 Paste from History command + shift + V ctrl + shift + V
快速查找定义 command + space ctrl + shift + I
粘贴 Paste command + V ctrl + V
复制 Copy command + C ctrl + C
去除无效包引用 Optimize Imports control + option + O ctrl + alt + O
显示类关系继承体系 Type Hierarchy control + H ctrl + H
快速覆写方法 override Methods control + O ctrl + O
查找调用的位置 Call hierarchy control + option + H ctrl + alt + H
扩大缩小选中范围 Extend Selection/Shrink Selection option + UP/Down ctrl + W + shift + W
跳转到父类 Super method command + U ctrl + U
关闭当前tab标签 Editor Tabs / Close command + W ctrl + shift + a
关闭除编辑窗口的其余窗口 Hide All Tool Windows command + shift + F12 ctrl + shift + F12
预览方法定义 Quick Definition command + Y ctrl + shift + I
返回光标最后编辑位置 Last Edit Location command + shift + delete control + shift + Backspace
调到代码块首部/尾部 Move Caret To Code Block Option + Command + [ 或者 ] Control+[ 或者 ]
重命名 Rename shift + F6 shift + F6
抽取方法 Extract Method command + option + M control+alt+M
抽取变量 Extract Variable command + option + V control+alt+V
抽取字段 Extract Field command + option + F control+alt+F
抽取常量 Extract Constant command + option + C control+alt+C
抽取参数 Extract Parameter command + option + P control+alt+P
重构入口 Refactor This control + T ctrl + alt + shift + T
打开文件 双击Shift 双击Shift
撤销 Command+Z Ctrl+Z
前进 Command+Shift+Z Ctrl+Shift+Z

Idea的Structure(View–Tool Windows–Structure)类似于eclipse中的outline

代码中快捷键(Live Templates)

1
C:\Users\monecity\.AndroidStudio3.6\config\templates
1
C:\Users\monecity\.AndroidStudio3.6\config\fileTemplates

注意,上面的路径在AS4.1之后变了,具体可以这么找AS>File>Manage IDE Settings>Restore Default Settings...在弹出框中可以看到新的路径(已经没有了configsystem这俩目录)

1
2
C:\Users\Administrator\AppData\Roaming\Google\AndroidStudio4.1\templates
C:\Users\Administrator\AppData\Roaming\Google\AndroidStudio4.1\fileTemplates

shenbh

* 方法注释

1
2
3
4
5
6
7
8
* <pre>
* @desc : $cursor$
* @Param : $PARAM$
* @Return : $RETURN$
* @Author : shenbh
* @Date : $DATE$ $TIME$
* </pre>
*/

idea增加方法注释模板.png

使用的时候 “/**+Tab”

add “增加”注释

1
2
//region add by shenbh on $DATE$ $END$
//endregion add

anno annotation添加方法注释

1
2
3
4
5
6
/**
* <pre>
* desc : $END$
* author : shenbh
* </pre>
*/

db 添加switch的默认项

1
2
default:
break;

doublesingleton 双重锁定创建单例模式,开销较大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static $CLASS_NAME$ getInstance(){
if (singleton == null){
synchronized ($CLASS_NAME$.class){
if (singleton == null){
singleton = new $CLASS_NAME$();
}
}
}
return singleton;
}

private static volatile $CLASS_NAME$ singleton = null;

private $CLASS_NAME$(){
}

doubleSingleWithContext 双重锁定创建单例模式,带Context

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static $CLASS_NAME$ getInstance(Context context){
if (singleton == null){
synchronized ($CLASS_NAME$.class){
if (singleton == null){
singleton = new $CLASS_NAME$(context);
}
}
}
return singleton;
}

private static volatile $CLASS_NAME$ singleton = null;

private WeakReference<Context> wf;
private $CLASS_NAME$(Context context){
wf = new WeakReference<Context>(context);
}

hand 创建自己的Handler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private class MyHandler extends Handler {
private WeakReference<$CLASS_NAME$> actWeakReference;

public MyHandler($CLASS_NAME$ activity) {
actWeakReference = new WeakReference<$CLASS_NAME$>(activity);
}

@Override
public void handleMessage(Message msg) {
$CLASS_NAME$ act = actWeakReference.get();
if (act != null) {
$END$
}
}
}

mdf “修改”注释

1
2
//region modify by shenbh on $DATE$ $END$
//endregion modify

newFragment 创建fragment

1
2
3
4
5
6
7
8
9
10
11
12
13
public $CLASS_NAME$(){}
public static $CLASS_NAME$ newInstance(Map<String, Object> map) {
$CLASS_NAME$ fragment = new $CLASS_NAME$();
if (map != null) {
Bundle args = new Bundle();
args.putInt("key", (int) map.get("key"));
args.putParcelable("key", (Uri) map.get("key"));
args.putBoolean("key", (boolean) map.get("key"));
args.putString("key",(String) map.get("key"));
fragment.setArguments(args);
}
return fragment;
}

note 类注释

1
2
3
4
5
6
/**
* $END$
* @author shenbh
* time $DATE$ $TIME$
* 维护者
*/

staticClassSingleton 静态内部类单例,无法传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static final String TAG = "$CLASS_NAME$".class.getName();

private $CLASS_NAME$(){}

public static $CLASS_NAME$ getInstance(){
return $CLASS_NAME$Holder.singleton;
}

/**
* 单例模式->静态内部类<br/>
* 多线程情况下,使用合理一些,推荐
*/
static class $CLASS_NAME$Holder {
private static $CLASS_NAME$ singleton = new $CLASS_NAME$();
}

ma “Module annotations模块注释”

1
2
//region ******$END$*******
//endregion ******$END$******

psv “public static void”

1
public static void $END$

sw “switch”

1
2
3
4
5
6
7
8
9
10
switch(view.getId()){
case $END$:

break;
case $END$:

break;
default:
break;
}

todo 添加 // TODO

1
//TODO: shenbh $date$ $todo$

try “creat try-catch”

1
2
3
4
5
try {
$END$
} catch (Exception e) {
e.printStackTrace();
}

u1city

layout “create layout res id const”

1
2
3
4
5
6
@LayoutRes
private static final int PAGE_LAYOUT_RES_ID = R.layout.activity_xxx;
@LayoutRes
private static final int ITEM_LAYOUT_RES_ID = R.layout.item_xxx;
@LayoutRes
private static final int EMPTY_VIEW_RES_ID = R.layout.empty_xxx;

lth “get thumbnail and set”

1
2
MonCityImageLoader.getInstance().loadImage(PictureSpaceCenter.getHandledUrl(App.getContext(), picUrl,_SIZE),
(ImageView) helper.getView(R.id.XXX));

mrx “MVP中 m层 RxRequest”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public Observable<String> $name$(final int indexPage, final int pageSize) {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(final Subscriber<? super String> subscriber) {
StandardCallback callback = new StandardCallback(mContext, true) {
@Override
public void onResult(BaseAnalysis analysis) throws Exception {
subscriber.onNext(analysis.getResult());
subscriber.onCompleted();
}

@Override
public void onError(int type) {
}
};

RequestApi.getInstance()
.$name$(indexPage, pageSize, callback);
}
});
}

ob

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
if (pIsLoadByRefresh) {
resetPage();
}
Observable.create(new Observable.OnSubscribe<BEAN>() {

@Override
public void call(final Subscriber<? super BEAN> subscriber) {
RequestApi.getInstance().$name$(new StandardCallback(mContext) {
@Override
public void onResult(BaseAnalysis analysis) throws Exception {
try {
if (analysis.success()) {
BEAN bean = JsonAnalysis.getInstance().fromJson(analysis.getResult(), BEAN.class);
subscriber.onNext(bean);
}
subscriber.onCompleted();
} catch (Exception e) {
e.printStackTrace();
onError(StandardCallback.TYPE_RESULT_ERROR);
subscriber.onError(e);
}
}

@Override
public void onError(int type) {

}

@Override
public void onError(BaseAnalysis baseAnalysis) {
super.onError(baseAnalysis);
subscriber.onError(new Throwable(baseAnalysis.msg()));
}
});
}
}).compose(RxSchedulers.<BEAN>request((RxAppCompatActivity) mContext, getView(), showLoading))
.subscribe(new RxSubscriber<BEAN>(getView()) {
@Override
public void _onNext(BEAN bean) {
getView().__getDataSuccess(pIsLoadByRefresh, bean);
addPage();
}

@Override
public void _onError(Throwable error) {

}
});

prx “MVP中 p层Rx请求”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public void $name$(final boolean pIsLoadByRefresh){
if (mModel == null) {
return;
}
if (pIsLoadByRefresh) {
resetPage();
}
mModel.$name$(getIndexPage(), getPageSize())
.map(new Func1<String, BEAN>() {
@Override
public BEAN call(String s) {
BEAN bean = JsonAnalysis.getInstance().fromJson(s, BEAN.class);
return bean;
}
})
.compose(RxSchedulers.<BEAN>request((RxAppCompatActivity) mContext))
.subscribe(new RxSubscriber<BEAN>(getView()) {
@Override
public void _onNext(BEAN bean) {
getView().__getDataSuccess(pIsLoadByRefresh, bean);
addPage();
}

@Override
public void _onError(Throwable error) {
getView().showToast(error.getMessage());
}
});
}

rxrequest “p层使用。do request by rx”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
if (pIsLoadByRefresh) {
resetPage();
}
RxRequest.rxRequest(mContext, new Observable.OnSubscribe<BaseAnalysis>() {
@Override
public void call(final Subscriber<? super BaseAnalysis> subscriber) {
RequestApi.getInstance().$name$(getIndexPage(), getPageSize(), new StandardCallback(mContext, true, true) {
@Override
public void onResult(BaseAnalysis analysis) throws Exception {
subscriber.onNext(analysis);
subscriber.onCompleted();
}

@Override
public void onError(int type) {
}

@Override
public void onError(BaseAnalysis baseAnalysis) {
super.onError(baseAnalysis);
subscriber.onError(new Throwable(baseAnalysis.msg()));
}
});
}
}).compose(RxSchedulers.<BaseAnalysis>request((RxAppCompatActivity) mContext, getView()))
.subscribe(new RxSubscriber<BaseAnalysis>(getView()) {
@Override
public void _onNext(BaseAnalysis analysis) {
try {
if (analysis.success()) {
$BEAN$ bean = JsonAnalysis.getInstance().fromJson(analysis.getResult(), $BEAN$.class);
getView().__getDataSuccess(pIsLoadByRefresh, bean);
addPage();
}
} catch (Exception e) {
e.printStackTrace();
onError(e);
}
}

@Override
public void _onError(Throwable error) {
getView().__getDataFail();
}
});

rgc “get Color from resource”

1
ContextCompat.getColor(mContext, R.color.$END$)

rgd “get a Drawable from resources”

1
ContextCompat.getDrawable(mContext, R.drawable.$END$)

rgs “get String from resource”

1
ContextCompat.getString(mContext, R.string.$END$)

rv “init RecyclerView”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(linearLayoutManager);
__itemAdapter = new __ItemAdapter(R.layout.item_store_hot_news)
__itemAdapter.setEmptyView(DEFAULT_EMPTY_VIEW, mRecyclerView);
__itemAdapter.isUseEmpty(false);
// 点击跳转
__itemAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
// TODO Item click biz
}
});
// 加载更多
__itemAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
@Override
public void onLoadMoreRequested() {
// TODO load more data
}
}, mRecyclerView);
mRecyclerView.setAdapter(__itemAdapter);

srl “init SmartRefreshLayout”

1
2
3
4
5
6
7
8
mSmartRefreshLayout.setEnableHeaderTranslationContent(false);
mSmartRefreshLayout.setDisableContentWhenRefresh(true);
mSmartRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(RefreshLayout refreshlayout) {
// TODO load data
}
});

ArmsMVP

armsContract MVPArms的Contract

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import android.app.Activity;

import com.jess.arms.mvp.IModel;
import com.jess.arms.mvp.IView;

import java.util.List;
import io.reactivex.Observable;

public interface $name$Contract {
//对于经常使用的关于UI的方法可以定义到IView中,如显示隐藏进度条,和显示文字消息
interface View extends IView {
void startLoadMore();

void endLoadMore();

Activity getActivity();

}

//Model层定义接口,外部只需关心Model返回的数据,无需关心内部细节,如是否使用缓存
interface Model extends IModel {
Observable<List<$name$>> get$name$s(int lastIdQueried, boolean update);
}
}

armsmrx MVPArms的M层Rx请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public Observable<List<$name$>> get$name$s(int lastIdQueried, boolean update) {
//使用rxcache缓存,上拉刷新则不读取缓存,加载更多读取缓存
return Observable.just(mRepositoryManager
.obtainRetrofitService($name$Service.class)
.get$name$s(lastIdQueried, Constants.PER_PAGE_SIZE))
.flatMap((Function<Observable<List<$name$>>, ObservableSource<List<$name$>>>) listObservable -> mRepositoryManager.obtainCacheService(CommonCache.class)
.get$name$s(listObservable
, new DynamicKey(lastIdQueried)
, new EvictDynamicKey(update))
.map(listReply -> listReply.getData()));

}

@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
void onPause() {
Timber.d("Release Resource");
}

armsprx MVPArms的P层Rx请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
@Inject
List<$name$Bean> m$name$s;
@Inject
$name$Adapter mAdapter;
private int lastId = 1;
private boolean isFirst = true;
private int preEndIndex;

@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void onCreate() {
request$name$sFromModel(true);//打开 App 时自动加载列表
}

public void request$name$sFromModel(final boolean pullToRefresh) {
if (pullToRefresh) {
lastId = 1;//下拉刷新默认只请求第一页
}

//关于RxCache缓存库的使用请参考 http://www.jianshu.com/p/b58ef6b0624b
boolean isEvictCache = pullToRefresh;//是否驱逐缓存,为ture即不使用缓存,每次下拉刷新即需要最新数据,则不使用缓存

if (pullToRefresh && isFirst) {//默认在第一次下拉刷新时使用缓存
isFirst = false;
isEvictCache = false;
}

mModel.get$name$s(lastId, isEvictCache)
.subscribeOn(Schedulers.io())
.retryWhen(new RetryWithDelay(3, 2))//遇到错误时重试,第一个参数为重试几次,第二个参数为重试的间隔
.doOnSubscribe(disposable -> {
if (pullToRefresh) {
mRootView.showLoading();//显示下拉刷新的进度条
} else {
mRootView.startLoadMore();//显示上拉加载更多的进度条
}
}).subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.doFinally(() -> {
if (pullToRefresh) {
mRootView.hideLoading();//隐藏下拉刷新的进度条
} else {
mRootView.endLoadMore();//隐藏上拉加载更多的进度条
}
})
.compose(RxLifecycleUtils.bindToLifecycle(mRootView))//使用 Rxlifecycle,使 Disposable 和 Activity 一起销毁
.subscribe(new ErrorHandleSubscriber<List<$name$Bean>>(mErrorHandler) {
@Override
public void onNext(List<$name$Bean> items) {
lastId = items.get(items.size() - 1).getId();//记录最后一个id,用于下一次请求
if (pullToRefresh) {
m$name$s.clear();//如果是下拉刷新则清空列表
}
preEndIndex = m$name$s.size();//更新之前列表总长度,用于确定加载更多的起始位置
m$name$s.addAll(items);
if (pullToRefresh) {
mAdapter.notifyDataSetChanged();
} else {
mAdapter.notifyItemRangeInserted(preEndIndex, items.size());
}
}
});
}

@Override
public void onDestroy() {
super.onDestroy();
this.mAdapter = null;
this.m$name$s = null;
this.mErrorHandler = null;
this.mAppManager = null;
this.mImageLoader = null;
this.mApplication = null;
}

tmpdata 临时数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// TODO: 2020/6/1
if (pullToRefresh){
mDatas.clear();
}
for (int i = 0; i < 5; i++) {
WeakReference<$name$Bean> wf = new WeakReference<>(new $name$Bean());
wf.get().setTitle("蒙牛伊利酸奶蒙牛伊利酸奶蒙牛伊利酸奶" + i);
mDatas.add(wf.get());
}
if (pullToRefresh){
mAdapter.notifyDataSetChanged();
} else {
// mAdapter.notifyItemRangeInserted(preEndIndex, mDatas.size());
}

xm597

gerenActivity 创建个人Activity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import com.xm597.app.R;
import com.xm597.app.databinding.Activity$entityName$Binding;
import com.xm597.app.project.ui.base.activity.GeRenBaseActivity;
import com.xm597.app.project.ui.city.presenter.ISimpleRvSearchContract;
import com.xm597.app.project.ui.city.presenter.SimpleRvSearchPresenter;
import com.xm597.common.widget.ktoolbar.KCustomToolbar;

public class $entityName$Activity extends GeRenBaseActivity<Activity$entityName$Binding, $entityName$Presenter>
implements I$entityName$Contract.I$entityName$UI{
private static final String KEY_TITLE = "keyTitle";

private String mTitle;

public static void start(Context context, String $entityName$Title) {
Intent intent = new Intent(context, $entityName$Activity.class);
intent.putExtra(KEY_TITLE, $entityName$Title);
context.startActivity(intent);
}

@Override
protected int setLayoutResID() {
// todo
return null;
}

@Override
protected void onCreated(Bundle savedInstanceState) {
parseIntentData();
}

@Override
protected void onStart() {
super.onStart();
mPresenter.start();
}

@Override
protected $entityName$Presenter setPresenter() {
return new $entityName$Presenter(this, this);
}

@Override
protected boolean setToolbar() {
// todo 需要toolbar则返回true;如果不需要 toolbar,则直接删除setToolbar()
mToolbar.setBackgroundColor(getResources().getColor(R.color.colorWhite));
mToolbar.setLeftIcon(R.drawable.icon_arrow_left_1);
mToolbar.setTitle(getPageTitle());

mToolbar.setKToolbarClickListener(new KCustomToolbar.KToolbarClickListener() {
@Override
public void onToolBarLeftButtonClick(int position) {
finish();
}

@Override
public void onToolBarRightButtonClick(int position) {
//TODO: toolbar右侧按钮点击事件
}
});
return true;
}

private void parseIntentData() {
Intent intent = getIntent();
if(intent != null){
mTitle = intent.getStringExtra(KEY_TITLE);
}
}

public String getPageTitle() {
return mTitle;
}

}

gerenBean 创建个人Bean

1
2
3
public class $entityName$Bean extends GeRenBaseBean {

}

gerenContract 创建个人Contract

1
2
3
4
5
6
7
import com.xm597.app.project.ui.base.presenter.IBaseUI;

public interface I$entityName$Contract {
interface I$entityName$UI extends IBaseUI {

}
}

gerenFragment 创建个人Fragment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class $entityName$Fragment extends BaseFragment<Fragment$entityName$Binding, $entityName$Presenter>
implements I$entityName$Contract.I$entityName$FragmentUI{
public $entityName$Fragment(){}

public static $entityName$Fragment newInstance(Map<String, Object> map){
$entityName$Fragment fragment = new $entityName$Fragment();
if(map != null){
Bundle args = new Bundle();
args.putInt("key", (int) map.get("key"));
args.putParcelable("key", (Uri) map.get("key"));
args.putBoolean("key", (boolean) map.get("key"));
args.putString("key",(String) map.get("key"));
fragment.setArguments(args);
}
return fragment;
}

@Override
protected int setLayoutResID() {
//todo
return null;
}

@Override
protected $entityName$Presenter setPresenter() {
return new $entityName$Presenter(this, this);
}

@Override
protected String setPageTitle() {
//TODO: 返回当前Fragment页面的标题
return null;
}

@Override
protected void onViewCreate(@NonNull View view, @Nullable Bundle savedInstanceState) {
//TODO: 一些实例化操作

}

@Override
protected boolean isRegisterEventBus() {
//TODO: 如果需要注册注销EventBus,需要改成return true
return false;
}
}

其中的构造方法必须是public,在某些API中(好像是安卓10)用的是反射,私有的反射不出来,会有找不到构造方法的异常。

gerenParams 创建个人Params

1
2
3
4
5
6
7
8
9
10
public class $entityName$Params extends GeRenBaseParams {

//创建类变量


public $entityName$Params(){
// 类变量实例化

}
}

gerenPresenter 创建个人Presenter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import androidx.lifecycle.LifecycleOwner;

import com.xm597.app.project.ui.base.presenter.BasePresenter;

public class $entityName$Presenter extends BasePresenter<I$entityName$Contract.I$entityName$UI> {
public $entityName$Presenter(LifecycleOwner lifeCycleOwner, I$entityName$Contract.I$entityName$UI view) {
super(lifeCycleOwner, view);
}

@Override
public void start() {
//TODO:
}

}

gerenRequest 创建个人Request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import com.xm597.app.project.api.base.request.GeRenBaseRequest;
import com.xm597.common.api.url.BaseApiUrlsConstants;

public class $entityName$Request extends GeRenBaseRequest<$entityName$Bean, $entityName$Params> {
//TODO: 此处添加类变量,表示要传递的参数

//TODO: 添加入参,并赋值给类变量
public $entityName$Request(){

}

@Override
protected $entityName$Params setRequestParams() {
//TODO: 把类变量传递给 $entityName$Params 的构造方法
return new $entityName$Params();
}

@Override
public String apiPath() {
return BaseApiUrlsConstants.$entityName$;
}
}

gerenXML 创建个人XML

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data>

</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

ob xm597 persenter内某方法的请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//TODO:改成调用BasePresenter内的方法(传对应的参数)
request$entityName$(id).observe(mLifecycleOwner, new GeRenApiResponseObserver<$entityName$Bean, HttpResponse<$entityName$Bean>>(mView) {
@Override
protected boolean onSuccess(int code, $entityName$Bean bean) {
//TODO: 改成功回调逻辑
String retMsg = bean.getMsg();
if (TextUtils.isEmpty(retMsg)){
//TODO: 这个文案提示要改
retMsg = "短信验证码已发送";
}
mView.onMobileChecked(true, retMsg);
return false;
}

@Override
protected boolean onFailed(int code, String error) {
//TODO: 改失败回调逻辑
mView.onMobileChecked(false, error);
return false;
}
});

创建类时的类型(File and Code Templates)

java类型

DoubleCheckSingleton

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#parse("File Header.java")
public final class ${NAME}{
//单例模式->双重检查模式
private static final String TAG = "${NAME}";
//volatile表示去掉虚拟机优化代码,但是会消耗少许性能,可忽略
private volatile static ${NAME} sInstance = null;

public static ${NAME} getInstance() {
if (sInstance == null) {
//同步代码块
synchronized (${NAME}.class) {
if (sInstance == null) {
sInstance = new ${NAME}();
}
}
}
return sInstance;
}

private ${NAME}() {
}
}

u1city

LdyActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import android.support.annotation.LayoutRes;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.Toolbar;
import android.widget.TextView;

import com.baidu.mobstat.StatService;
import com.u1city.androidframe.customView.PagerSlidingTabStrip;
import com.umeng.analytics.MobclickAgent;

import xxx.xxx.R;
import xxx.xxx.api.RequestApi;
import xxx.xxx.base.LdyBaseActivity;
import xxx.xxx.center.StringConstantUtils;
import xxx.xxx.core.Constants;
import butterknife.Bind;

//这个页面带多个tab,内容是嵌套多个fragment,可切换

#parse("File Header.java")
public class ${pageName}Activity extends LdyBaseActivity {

@LayoutRes
private static final int PAGE_LAYOUT_RES_ID = R.layout.activity_${layoutName};
@Bind(R.id.toolbar)
Toolbar mToolbar;
@Bind(R.id.${layoutName}_tabstrip)
PagerSlidingTabStrip mPagerSlidingTabStrip;
@Bind(R.id.${layoutName}_viewpager)
ViewPager mViewPager;
@Bind(R.id.${layoutName}_return_goods_tv)
TextView mReturnGoodsTv;
@Bind(R.id.${layoutname}_refund_tv)
TextView refundTv;

//todo 更改fragment的tab标签名称
private String[] titles = new String[]{"退货", "退款"};
//todo 添加自己常量
private int[] dataTypes = new int[]{StringConstantUtils., StringConstantUtils.};

@Override
public boolean openImmersion() {
return true;
}

@Override
public void setImmersion() {
getImmersion().setImmersionDarkFont(mToolbar, true);
}

@Override
protected int setLayoutResId() {
return PAGE_LAYOUT_RES_ID;
}

@Override
protected void onCreate() {
setImmersion();
setU1cityBaseToolBar(mToolbar, "售后");

${pageName}PagerAdapter pageAdapter = new ${pageName}PagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(pageAdapter);
mPagerSlidingTabStrip.setViewPager(mViewPager);

boolean shouldOpenRefundList = getIntent().getBooleanExtra(StringConstantUtils.ACTION_OPEN_REFUND_LIST, false);
if (shouldOpenRefundList) {
mViewPager.setCurrentItem(1);
}
}



/**
* 适配器
*/
private class ${pageName}PagerAdapter extends FragmentPagerAdapter {

public ${pageName}PagerAdapter(FragmentManager fm) {
super(fm);
}

@Override
public CharSequence getPageTitle(int position) {
return titles[position];
}

@Override
public Fragment getItem(int i) {
return ${pageName}.newInstance(dataTypes[i]);
}

@Override
public int getCount() {
return titles == null ? 0 : titles.length;
}
}

@Override
protected void onPause() {
super.onPause();
MobclickAgent.onPause(this);
StatService.onPageEnd(this, "售后");
}

@Override
protected void onDestroy() {
super.onDestroy();
RequestApi.getInstance().cancleAll(this);
}

@Override
protected void onResume() {
super.onResume();
MobclickAgent.onResume(this);
StatService.onPageStart(this, "售后");

if (Constants.cust == null) {
Constants.getCustomer();
}
}
}

LdyFragments

包含多个子Fragment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.trello.rxlifecycle.components.support.RxFragment;
import com.u1city.androidframe.common.baseData.ListUtils;
import com.u1city.androidframe.customView.NoScrollViewPager;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import xxx.xxx.R;
import xxx.xxx.base.LdyBaseFragment;
import xxx.xxx.model.javabean.custompage.TabListBean;
import butterknife.Bind;
import butterknife.ButterKnife;

/**
* @author shenbh
* time ${DATE} ${TIME} ${DAY_NAME_FULL}
* email shenbh@qq.com
* description (包含多个子fragment)
* 维护者
*/
public class ${pageName}Fragment extends LdyBaseFragment {

@LayoutRes
private static final int PAGE_LAYOUT_RES_ID = R.layout.fragment_${layoutName};

@Bind(R.id.${layoutName}_tl)
TabLayout mainTl;
@Bind(R.id.${layoutName}_vp)
NoScrollViewPager mainVp;

//这是多个子fragment切换的适配器
private ${pageName}PagerAdapter pagerAdapter;

//TODO 改成自己的tab名称
private String[] tabNames = new String[]{"帖子", "社群分类"};

public static ${pageName}Fragment newInstance(Map<String, Object> map) {
${pageName}Fragment fragment = new ${pageName}Fragment();
//TODO:可以传一些值进来
if (map != null) {
Bundle args = new Bundle();
args.putInt("key", (int) map.get("key"));
args.putParcelable("key", (Uri) map.get("key"));
args.putBoolean("key", (boolean) map.get("key"));
args.putString("key", (String) map.get("key"));
fragment.setArguments(args);
}
return fragment;
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// TODO 取出一些参数
try {
xxx = getArguments().getString(Key);
} catch (Exception e) {
e.printStackTrace();
}
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
ButterKnife.bind(this, super.onCreateView(inflater, container, savedInstanceState));
return super.onCreateView(inflater, container, savedInstanceState);
}

@Override
protected void onViewCreated() {
initParams();
initView();
}

/**
* 初始化一些基本的参数
*/
private void initParams() {

}

private void initView() {
initTab();
}

@Override
protected int setLayoutResId() {
return PAGE_LAYOUT_RES_ID;
}

@Override
protected void lazyLoadData() {

}

//初始化多个子tab
private void initTab() {
pagerAdapter = new ${pageName}PagerAdapter(getChildFragmentManager());
mainVp.setAdapter(pagerAdapter);
mainVp.setCanScroll(true);

ArrayList<TabListBean> tabs = new ArrayList<>();
for (int i = 0, size = tabNames.length; i < size; i++) {
WeakReference<TabListBean> wf = new WeakReference<>(new TabListBean());
wf.get().setTabName(tabNames[i]);
tabs.add(wf.get());
}

if (pagerAdapter != null) {
pagerAdapter.setData(tabs);
}

mainTl.setupWithViewPager(mainVp);
}

@Override
public void onDestroyView() {
super.onDestroyView();
ButterKnife.unbind(this);
}

class ${pageName}PagerAdapter extends FragmentStatePagerAdapter {

private List<TabListBean> mTabListBeans = new ArrayList<>();
private List<RxFragment> mRxFragments = new ArrayList<>();
private FragmentManager mFragmentManager;

public void setData(@NonNull List<TabListBean> data) {
mTabListBeans = data;
FragmentTransaction ft = mFragmentManager.beginTransaction();//获得FragmentTransaction 事务
for (RxFragment fragment : mRxFragments) {
ft.remove(fragment);
}
ft.commitAllowingStateLoss();
ft = null;
mFragmentManager.executePendingTransactions();//提交事务
mRxFragments.clear();
//TODO:改成自己的子fragment
// for (int i = 0; i < mTabListBeans.size(); i++) {
// mRxFragments.add(pageType == 0 ?
// CommunitySpaceSearchResultPostFragment.newInstance(null) :
// PageFragment.newInstance(mTabListBeans.get(i).getTemplateId()));
// }

mRxFragments.add(${pageName}ChildFragment.newInstance(null));
mRxFragments.add(${pageName}ChildFragment.newInstance(null));

notifyDataSetChanged();
}

public List<TabListBean> getList() {
return mTabListBeans;
}

public ${pageName}PagerAdapter(FragmentManager fm) {
super(fm);
mFragmentManager = fm;
}

@Override
public Fragment getItem(int position) {
return mRxFragments.get(position);
}

@Override
public int getCount() {
return ListUtils.isEmpty(mTabListBeans) ? 0 : mTabListBeans.size();
}

@Override
public CharSequence getPageTitle(int position) {
return mTabListBeans.get(position).getTabName();
}

@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// super.destroyItem(container, position, object);
}

public void releaseFragment(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
}
}

MvpBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

#if (${IMPORT_BLOCK} != "")${IMPORT_BLOCK}
#end
import java.io.Serializable;

#parse("File Header.java")
@Keep
public class ${beanName} implements Serializable{
// TODO 只是一个模板。如果有Json字符串,直接GsonFormat自动生成
private String total;
private List<${childBeanName}>data;

public static class ${childBeanName}{
// TODO
}

public void setTotal(String total) {
this.total = total;
}

public String getTotal() {
return total;
}

public void setData(List<${childBeanName}>pData) {
this.data = pData;
}

public List<${childBeanName}> getData() {
return data;
}

}

MvpContract

1
2
3
4
5
6
7
8
9
10
11
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
import com.u1city.androidframe.framework.v1.support.MvpView;

#parse("File Header.java")
public interface ${pageName}Contract {
interface View extends MvpView{
// TODO View层的方法,先生成模板函数,在Activity生存之后再根据业务修改合适的函数名
void __getDataSuccess(boolean pIsLoadByRefresh, ${beanName} p${beanName});
void __getDataFail();
}
}

MvpDgActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
import java.util.List;

import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.scwang.smartrefresh.layout.SmartRefreshLayout;
import com.scwang.smartrefresh.layout.api.RefreshLayout;
import com.scwang.smartrefresh.layout.listener.OnRefreshListener;
import com.u1city.androidframe.common.baseData.BaseParser;
import com.u1city.androidframe.common.baseData.ListUtils;

import yyy.yyy.R;
import yyy.yyy.base.DgBaseMvpActivity;
import yyy.yyy.view.recycler.CustomCommonLoadMoreView;
import butterknife.Bind;

#parse("File Header.java")
public class ${pageName}Activity extends DgBaseMvpActivity<${pageName}Contract.View,${pageName}Presenter>
implements ${pageName}Contract.View {
@LayoutRes
private static final int PAGE_LAYOUT_RES_ID = R.layout.activity_${layoutName};
@LayoutRes
private static final int ITEM_LAYOUT_RES_ID = R.layout.item_${layoutName};
@LayoutRes
private static final int EMPTY_VIEW_RES_ID = R.layout.empty_${layoutName};

@Bind(R.id.toolbar)
Toolbar mToolbar;

@Bind(R.id.${layoutName}_srl)
SmartRefreshLayout mSmartRefreshLayout;
@Bind(R.id.${layoutName}_rv)
RecyclerView mRecyclerView;

// TODO 替换自己的ItemAdapter
private ${pageName}ItemAdapter mItemAdapter;

@Override
protected void onCreateMvp() {
// TODO 是否可以去除Activity的背景
// getWindow().setBackgroundDrawable(null);
setImmersion();
initView();
mSmartRefreshLayout.autoRefresh();
}

@Override
protected void onDestroy() {
super.onDestroy();
ButterKnife.unbind(this);
}

@Override
protected int setLayoutResId() {
return PAGE_LAYOUT_RES_ID;
}

@NonNull
@Override
public ${pageName}Presenter createPresenter() {
return new ${pageName}Presenter(this);
}

@Override
public void setImmersion() {
getImmersion().setImmersionDarkFont(mToolbar, false);
}

private void initView() {
initToolbar();
initSrl();
initRv();
}

private void initToolbar() {
// TODO 设置Toolbar
}

private void initSrl() {
mSmartRefreshLayout.setEnableHeaderTranslationContent(false);
mSmartRefreshLayout.setDisableContentWhenRefresh(true);
mSmartRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(RefreshLayout refreshlayout) {
loadData(true);
}
});
}

private void initRv() {
// TODO 根据实际进行调整
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);

mRecyclerView.setLayoutManager(linearLayoutManager);

mItemAdapter = new ${pageName}ItemAdapter(ITEM_LAYOUT_RES_ID);
mItemAdapter.setEmptyView(getEmptyView());
mItemAdapter.isUseEmpty(false);
// TODO 是否需要设置自定义的LoadMoreView
mItemAdapter.setLoadMoreView(new CustomCommonLoadMoreView());
// TODO 是否有分割线需要设置
// 点击跳转
mItemAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
// TODO Item的点击事件
}
});
// 加载更多
mItemAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
@Override
public void onLoadMoreRequested() {
loadData(false);
}
}, mRecyclerView);

mRecyclerView.setAdapter(mItemAdapter);
}

private void loadData(boolean pIsLoadByRefresh) {
// 网络异常直接提示网络异常
if (!NetUtil.isNetworkConnected(getActivity())) {
ToastUtil.showNotNetToast(getActivity());
return;
}

if (pIsLoadByRefresh) {
getPresenter().resetPage();
}
// TODO 根据业务修改函数名以及内部的P层调用
}

private View getEmptyView() {
View emptyView = LayoutInflater.from(this).inflate(EMPTY_VIEW_RES_ID, null);
// TODO 空态页是否有额外的操作
return emptyView;
}

@Override
public void __getDataSuccess(boolean pIsLoadByRefresh,${beanName} pT) {
mSmartRefreshLayout.finishRefresh();
mSmartRefreshLayout.setEnableRefresh(true);
mItemAdapter.isUseEmpty(true);
List<${beanName}.${childBeanName}>dataList = pT.getData();
if (pIsLoadByRefresh) {
mItemAdapter.setNewData(dataList);
} else {
mItemAdapter.addData(dataList);
}
if (!ListUtils.isEmpty(dataList)) {
checkLoadMore(false, mItemAdapter, BaseParser.parseInt(pT.getTotal()), getPresenter().getPageSize());
} else {
mItemAdapter.loadMoreEnd();
}
}

@Override
public void __getDataFail() {
mSmartRefreshLayout.finishRefresh();
mSmartRefreshLayout.setEnableRefresh(true);
mItemAdapter.isUseEmpty(true);
}
}

MvpItemAdapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;

#parse("File Header.java")
public class ${pageName}ItemAdapter extends BaseQuickAdapter<${beanName}.${childBeanName}, BaseViewHolder>{
public ${pageName}ItemAdapter(int layoutResId) {
super(layoutResId);
}
@Override
protected void convert(BaseViewHolder helper, ${beanName}.${childBeanName} item) {
// TODO Item的展示
}

}

MvpLdyActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
import java.util.List;

import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.scwang.smartrefresh.layout.SmartRefreshLayout;
import com.scwang.smartrefresh.layout.api.RefreshLayout;
import com.scwang.smartrefresh.layout.listener.OnRefreshListener;
import com.u1city.androidframe.common.baseData.BaseParser;
import com.u1city.androidframe.common.baseData.ListUtils;

import xxx.xxx.R;
import butterknife.Bind;
import butterknife.ButterKnife;

#parse("File Header.java")
public class ${pageName}Activity extends LdyBaseMvpActivity<${pageName}Contract.View,${pageName}Presenter>
implements ${pageName}Contract.View {
@LayoutRes
private static final int PAGE_LAYOUT_RES_ID = R.layout.activity_${layoutName};
@LayoutRes
private static final int ITEM_LAYOUT_RES_ID = R.layout.item_${layoutName};
@LayoutRes
private static final int EMPTY_VIEW_RES_ID = R.layout.empty_${layoutName};

@Bind(R.id.toolbar)
Toolbar mToolbar;
@Bind(R.id.toolbar_iv_left)
ImageView mToolbarIvLeft;
@Bind(R.id.toolbar_title)
TextView mToolbarTitle;

@Bind(R.id.${layoutName}_srl)
SmartRefreshLayout mSmartRefreshLayout;
@Bind(R.id.${layoutName}_rv)
RecyclerView mRecyclerView;

// TODO 替换自己的ItemAdapter
private ${pageName}ItemAdapter mItemAdapter;

@Override
protected void onCreateMvp() {
// TODO 是否可以去除Activity的背景
// getWindow().setBackgroundDrawable(null);
setImmersion();
initView();
mSmartRefreshLayout.autoRefresh();
}

@Override
protected void onDestroy() {
super.onDestroy();
ButterKnife.unbind(this);
}

@Override
protected int setLayoutResId() {
return PAGE_LAYOUT_RES_ID;
}

@NonNull
@Override
public ${pageName}Presenter createPresenter() {
return new ${pageName}Presenter(this);
}

@Override
public void setImmersion() {
getImmersion().setImmersionDarkFont(mToolbar, false);
}

private void initView() {
initToolbar();
initSrl();
initRv();
}

private void initToolbar() {
// TODO 设置Toolbar
mToolbarTitle.setText("改成自己的标题");

mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finishAnimation();
}
});
}

private void initSrl() {
mSmartRefreshLayout.setEnableHeaderTranslationContent(false);
mSmartRefreshLayout.setDisableContentWhenRefresh(true);
mSmartRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(RefreshLayout refreshlayout) {
loadData(true);
}
});
}

private void initRv() {
// TODO 根据实际进行调整
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);

mRecyclerView.setLayoutManager(linearLayoutManager);

mItemAdapter = new ${pageName}ItemAdapter(ITEM_LAYOUT_RES_ID);
mItemAdapter.setEmptyView(getEmptyView());
mItemAdapter.isUseEmpty(false);
// TODO 是否需要设置自定义的LoadMoreView
mItemAdapter.setLoadMoreView(new CustomCommonLoadMoreView());
// TODO 是否有分割线需要设置
// 点击跳转
mItemAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
// TODO Item的点击事件
}
});
// 加载更多
mItemAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
@Override
public void onLoadMoreRequested() {
loadData(false);
}
}, mRecyclerView);

mRecyclerView.setAdapter(mItemAdapter);
}

private void loadData(boolean pIsLoadByRefresh) {
// 网络异常直接提示网络异常
if (!NetUtil.isNetworkConnected(this)) {
ToastUtil.showNotNetToast(this);
return;
}

if (pIsLoadByRefresh) {
getPresenter().resetPage();
}

// TODO 根据业务修改函数名以及内部的P层调用

}

private View getEmptyView() {
View emptyView = LayoutInflater.from(this).inflate(EMPTY_VIEW_RES_ID, null);
// TODO 空态页是否有额外的操作
return emptyView;
}

@Override
public void __getDataSuccess(boolean pIsLoadByRefresh,${beanName} pT) {
mSmartRefreshLayout.finishRefresh();
mSmartRefreshLayout.setEnableRefresh(true);
mItemAdapter.isUseEmpty(true);
List<${beanName}.${childBeanName}>dataList = pT.getData();
if (pIsLoadByRefresh) {
mItemAdapter.setNewData(dataList);
} else {
mItemAdapter.addData(dataList);
}
if (!ListUtils.isEmpty(dataList)) {
checkLoadMore(false, mItemAdapter, BaseParser.parseInt(pT.getTotal()), getPresenter().getPageSize());
} else {
mItemAdapter.loadMoreEnd();
}
}

@Override
public void __getDataFail() {
mSmartRefreshLayout.finishRefresh();
mSmartRefreshLayout.setEnableRefresh(true);
mItemAdapter.isUseEmpty(true);
}


}

MvpLdyFragment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.scwang.smartrefresh.layout.SmartRefreshLayout;
import com.scwang.smartrefresh.layout.api.RefreshLayout;
import com.scwang.smartrefresh.layout.listener.OnRefreshListener;
import com.u1city.androidframe.common.baseData.BaseParser;
import com.u1city.androidframe.common.baseData.ListUtils;
import com.u1city.androidframe.common.network.NetUtil;
import com.u1city.androidframe.common.toast.ToastUtil;

import xxx.xxx.R;
import xxx.xxx.base.LdyBaseMvpFragment;
import butterknife.Bind;
import butterknife.ButterKnife;

#parse("File Header.java")
public class ${pageName}Fragment extends LdyBaseMvpFragment<${pageName}Contract.View,${pageName}Presenter>
implements ${pageName}Contract.View{

@LayoutRes
private static final int PAGE_LAYOUT_RES_ID = R.layout.fragment_${layoutName};
@LayoutRes
private static final int ITEM_LAYOUT_RES_ID = R.layout.item_${layoutName};
@LayoutRes
private static final int EMPTY_VIEW_RES_ID = R.layout.empty_${layoutName};

@Bind(R.id.${layoutName}_srl)
SmartRefreshLayout mSmartRefreshLayout;
@Bind(R.id.${layoutName}_rv)
RecyclerView mRecyclerView;

// TODO 替换自己的ItemAdapter
private ${pageName}ItemAdapter mItemAdapter;

public static ${pageName}Fragment newInstance(Map<String, Object> map) {
${pageName}Fragment fragment = new ${pageName}Fragment();
//TODO:可以传一些值进来
if (map != null) {
Bundle args = new Bundle();
args.putInt("key", (int) map.get("key"));
args.putParcelable("key", (Uri) map.get("key"));
args.putBoolean("key", (boolean) map.get("key"));
args.putString("key", (String) map.get("key"));
fragment.setArguments(args);
}
return fragment;
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// TODO 取出一些参数
try {
xxx = getArguments().getString(Key);
} catch (Exception e) {
e.printStackTrace();
}
}

@Override
public void __getDataSuccess(boolean pIsLoadByRefresh, ${beanName} pT) {
mSmartRefreshLayout.finishRefresh();
mSmartRefreshLayout.setEnableRefresh(true);
mItemAdapter.isUseEmpty(true);
List<${beanName}.${childBeanName}> dataList = pT.getData();
if (pIsLoadByRefresh) {
mItemAdapter.setNewData(dataList);
} else {
mItemAdapter.addData(dataList);
}
if (!ListUtils.isEmpty(dataList)) {
checkLoadMore(false, mItemAdapter, BaseParser.parseInt(pT.getTotal()), getPresenter().getPageSize());
} else {
mItemAdapter.loadMoreEnd();
}
}

@Override
public void __getDataFail() {
mSmartRefreshLayout.finishRefresh();
mSmartRefreshLayout.setEnableRefresh(true);
mItemAdapter.isUseEmpty(true);
}

@Override
protected void onViewCreatedMvp() {
initParams();
initView();
mSmartRefreshLayout.autoRefresh();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// TODO: inflate a fragment view
View rootView = super.onCreateView(inflater, container, savedInstanceState);
ButterKnife.bind(this, rootView);
return rootView;
}

@Override
public void onDestroyView() {
super.onDestroyView();
ButterKnife.unbind(this);
}

private void initView() {
initSrl();
initRv();
}

/**
* 初始化刷新控件
*/
private void initSrl() {
mSmartRefreshLayout.setEnableHeaderTranslationContent(false);
mSmartRefreshLayout.setDisableContentWhenRefresh(true);
mSmartRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(RefreshLayout refreshlayout) {
getChildModularData(true);
}
});
}

/**
* 初始化RecyclerView
*/
private void initRv() {
// TODO 根据实际进行调整
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());

mRecyclerView.setLayoutManager(linearLayoutManager);

mItemAdapter = new ${pageName}ItemAdapter(ITEM_LAYOUT_RES_ID);
mItemAdapter.setEmptyView(getEmptyView());
mItemAdapter.isUseEmpty(false);
// TODO 是否需要设置自定义的LoadMoreView
mItemAdapter.setLoadMoreView(new CustomCommonLoadMoreView());
// TODO 是否有分割线需要设置
// 点击跳转
mItemAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
// TODO Item的点击事件
}
});
// 加载更多
mItemAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
@Override
public void onLoadMoreRequested() {
getChildModularData(false);
}
}, mRecyclerView);

mRecyclerView.setAdapter(mItemAdapter);
}

private View getEmptyView() {
View emptyView = LayoutInflater.from(getContext()).inflate(EMPTY_VIEW_RES_ID, null);
// TODO 空态页是否有额外的操作
return emptyView;
}

/**
* 初始化一些基本的参数
*/
private void initParams() {

}

@Override
protected int setLayoutResId() {
return PAGE_LAYOUT_RES_ID;
}

@Override
protected void lazyLoadData() {
// 这里不用smartRefreshLayout的进度圈是因为显示的时机有点滞后
showRequestLoading();
getChildModularData(true);
}

/**
* 获取该模板id下各个模块的数据<br></br>
* <li>1.先从缓存获取显示</li>
* <li>2.如果网络异常,则显示提示;否则延迟500L毫秒刷新数据</li>
*/
private void getChildModularData(boolean pIsLoadByRefresh) {
// 网络异常直接提示网络异常
if (!NetUtil.isNetworkConnected(getActivity())) {
ToastUtil.showNotNetToast(getActivity());
return;
}

if (pIsLoadByRefresh) {
getPresenter().resetPage();
}

//网络请求数据

}

@NonNull
@Override
public ${pageName}Presenter createPresenter() {
return new ${pageName}Presenter(getContext());
}
}

MvpModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

#if (${IMPORT_BLOCK} != "")${IMPORT_BLOCK}
#end
#parse("File Header.java")
public class ${pageName}Model implements MvpModel {

private Context mContext;

public ${pageName}Model(Context context){
mContext = context;
}

@Override
public void onDestroy() {

}
}

MvpPresenter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
import android.content.Context;

import com.u1city.androidframe.framework.v1.support.impl.MvpBasePresenter;
#parse("File Header.java")
public class ${pageName}Presenter extends MvpBasePresenter<${pageName}Contract.View> {

private ${pageName}Model mModel;

public ${pageName}Presenter(Context context) {
super(context);
mModel = new ${pageName}Model(context);
}

@Override
public void destroy() {
mModel = null;
}
}

StaticClassSingleton

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#parse("File Header.java")
public class ${NAME} {

private static final String TAG = "${NAME}";

private ${NAME}(){

}

public static ${NAME} getInstance(){
return ${NAME}Holder.singleton;
}

/**
* 单例模式->静态内部类<br/>
* 多线程情况下,使用合理一些,推荐
*/
static class ${NAME}Holder {
private static ${NAME} singleton = new ${NAME}();
}
}

Arms

ArmsActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import android.content.Intent;
import androidx.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import com.jess.arms.base.BaseActivity;
import com.jess.arms.utils.ArmsUtils;


import static com.jess.arms.utils.Preconditions.checkNotNull;

/**
* 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同
* 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名
* 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component
* 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会
* 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可
* 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment
*/

#parse("File Header.java")

public class ${NAME}Activity extends BaseActivity<${NAME}Presenter> implements ${NAME}Contract.View {


@Override
public void setupActivityComponent(AppComponent appComponent) {
Dagger${NAME}Component
.builder()
.appComponent(appComponent)
.${NAME}Module(new ${NAME}Module(this)) //请将${NAME}Module()第一个首字母改为小写
.build()
.inject(this);
}

@Override
public int initView(Bundle savedInstanceState) {
return 0;
}

@Override
public void initData(Bundle savedInstanceState) {

}


@Override
public void showLoading() {

}

@Override
public void hideLoading() {

}

@Override
public void showMessage(@NonNull String message) {
checkNotNull(message);
ArmsUtils.snackbarText(message);
}

@Override
public void launchActivity(@NonNull Intent intent) {
checkNotNull(intent);
ArmsUtils.startActivity(intent);
}

@Override
public void killMyself() {
finish();
}


}

ArmsAdapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import android.content.Context;
import android.widget.TextView;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.jess.arms.di.component.AppComponent;
import com.jess.arms.utils.ArmsUtils;

import java.util.List;

import androidx.annotation.Nullable;

#parse("File Header.java")

public class ${NAME}Adapter extends BaseQuickAdapter<${NAME}Bean, BaseViewHolder> {

private AppComponent mAppComponent;
private Context mContext;

public ${NAME}Adapter(@Nullable List<${NAME}Bean> data, Context context) {
super(R.layout.item_${NAME}_recycleview, data);
this.mContext = context;
//可以从任何可以拿到Context的地方,拿到AppComponent,从而得到用Dagger管理的单例对象
this.mAppComponent = ArmsUtils.obtainAppComponentFromContext(context);
}

@Override
protected void convert(BaseViewHolder helper, ${NAME}Bean item) {
//todo: 页面逻辑

}
}

ArmsAutoView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.ViewGroup;

import com.zhy.autolayout.AutoLayoutInfo;
import com.zhy.autolayout.utils.AutoLayoutHelper;

/**
* 此Template用于生成AutoLayout需要的的Auto系列View,如需要使ScrollView适配,使用此Template输入ScrollView,即可生成
* AutoScrollView,使用此View即可自适应
*/



#parse("File Header.java")
public class Auto${NAME} extends ${NAME} {
private AutoLayoutHelper mHelper = new AutoLayoutHelper(this);

public Auto${NAME}(Context context) {
super(context);
}

public Auto${NAME}(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}

public Auto${NAME}(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!isInEditMode()){
mHelper.adjustChildren();
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}


@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
}


@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}


public static class LayoutParams extends ${NAME}.LayoutParams
implements AutoLayoutHelper.AutoLayoutParams {
private AutoLayoutInfo mAutoLayoutInfo;

public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
mAutoLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs);
}

@Override
public AutoLayoutInfo getAutoLayoutInfo() {
return mAutoLayoutInfo;
}


public LayoutParams(int width, int height) {
super(width, height);
}


public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}

public LayoutParams(MarginLayoutParams source) {
super(source);
}

}
}

ArmsComponent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import com.jess.arms.di.scope.ActivityScope;

import dagger.Component;

/**
* 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同
* 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名
* 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component
* 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会
* 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可
* 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment
*/

#parse("File Header.java")

@ActivityScope
@Component(modules = ${NAME}Module.class,dependencies = AppComponent.class)
public interface ${NAME}Component {
void inject(${NAME}Activity activity);
}

ArmsContract

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import android.app.Activity;

import com.jess.arms.mvp.IView;
import com.jess.arms.mvp.IModel;

/**
* 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同
* 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名
* 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component
* 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会
* 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可
* 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment
*/

#parse("File Header.java")

public interface ${NAME}Contract {
//对于经常使用的关于UI的方法可以定义到IView中,如显示隐藏进度条,和显示文字消息
interface View extends IView {
Activity getActivity();

}
//Model层定义接口,外部只需关心Model返回的数据,无需关心内部细节,即是否使用缓存
interface Model extends IModel{

}
}

ArmsFragment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import com.jess.arms.base.BaseFragment

import com.jess.arms.utils.ArmsUtils;

import butterknife.Bind;

import static com.jess.arms.utils.Preconditions.checkNotNull;

/**
* 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同
* 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名
* 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component
* 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会
* 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可
* 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment
*/

#parse("File Header.java")

public class ${NAME}Fragment extends BaseFragment<${NAME}Presenter> implements ${NAME}Contract.View{


public static ${NAME}Fragment newInstance() {
${NAME}Fragment fragment = new ${NAME}Fragment();
return fragment;
}

@Override
public void setupFragmentComponent(AppComponent appComponent) {
Dagger${NAME}Component
.builder()
.appComponent(appComponent)
.${NAME}Module(new ${NAME}Module(this))//请将${NAME}Module()第一个首字母改为小写
.build()
.inject(this);
}

@Override
public View initView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(layout_id, container, false);
}

@Override
public void initData(Bundle savedInstanceState) {

}

/**
* 此方法是让外部调用使fragment做一些操作的,比如说外部的activity想让fragment对象执行一些方法,
* 建议在有多个需要让外界调用的方法时,统一传Message,通过what字段,来区分不同的方法,在setData
* 方法中就可以switch做不同的操作,这样就可以用统一的入口方法做不同的事
*
* 使用此方法时请注意调用时fragment的生命周期,如果调用此setData方法时onCreate还没执行
* setData里却调用了presenter的方法时,是会报空的,因为dagger注入是在onCreated方法中执行的,然后才创建的presenter
* 如果要做一些初始化操作,可以不必让外部调setData,在initData中初始化就可以了
*
* @param data
*/

@Override
public void setData(Object data) {

}


@Override
public void showLoading() {

}

@Override
public void hideLoading() {

}

@Override
public void showMessage(@NonNull String message) {
checkNotNull(message);
ArmsUtils.snackbarText(message);
}

@Override
public void launchActivity(@NonNull Intent intent) {
checkNotNull(intent);
ArmsUtils.startActivity(intent);
}

@Override
public void killMyself() {

}

}

ArmsModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import android.app.Application;
import com.google.gson.Gson;
import com.jess.arms.integration.IRepositoryManager;
import com.jess.arms.mvp.BaseModel;

import static com.jess.arms.utils.Preconditions.checkNotNull;
import com.jess.arms.di.scope.ActivityScope;
import javax.inject.Inject;

/**
* 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同
* 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名
* 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component
* 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会
* 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可
* 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment
*/

#parse("File Header.java")

@ActivityScope
public class ${NAME}Model extends BaseModel implements ${NAME}Contract.Model{
private Gson mGson;
private Application mApplication;

@Inject
public ${NAME}Model(IRepositoryManager repositoryManager, Gson gson, Application application) {
super(repositoryManager);
this.mGson = gson;
this.mApplication = application;
}

@Override
public void onDestroy() {
super.onDestroy();
this.mGson = null;
this.mApplication = null;
}

}

ArmsModule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import com.google.gson.Gson;
import android.app.Application;
import com.jess.arms.di.scope.ActivityScope;

import dagger.Module;
import dagger.Provides;

/**
* 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同
* 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名
* 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component
* 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会
* 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可
* 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment
*/

#parse("File Header.java")

@Module
public class ${NAME}Module {
private ${NAME}Contract.View view;

/**
* 构建${NAME}Module时,将View的实现类传进来,这样就可以提供View的实现类给presenter
* @param view
*/
public ${NAME}Module(${NAME}Contract.View view) {
this.view = view;
}

@ActivityScope
@Provides
${NAME}Contract.View provide${NAME}View(){
return this.view;
}

@ActivityScope
@Provides
${NAME}Contract.Model provide${NAME}Model(${NAME}Model model){
return model;
}
}

ArmsPresenter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import android.app.Application;
import com.jess.arms.integration.AppManager;
import com.jess.arms.di.scope.ActivityScope;
import com.jess.arms.mvp.BasePresenter;
import com.jess.arms.http.imageloader.ImageLoader;
import me.jessyan.rxerrorhandler.core.RxErrorHandler;
import javax.inject.Inject;


/**
* 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同
* 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名
* 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component
* 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会
* 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可
* 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment
*/



#parse("File Header.java")

@ActivityScope
public class ${NAME}Presenter extends BasePresenter<${NAME}Contract.Model, ${NAME}Contract.View> {
private RxErrorHandler mErrorHandler;
private Application mApplication;
private ImageLoader mImageLoader;
private AppManager mAppManager;

@Inject
public ${NAME}Presenter (${NAME}Contract.Model model, ${NAME}Contract.View rootView
, RxErrorHandler handler, Application application
, ImageLoader imageLoader, AppManager appManager) {
super(model, rootView);
this.mErrorHandler = handler;
this.mApplication = application;
this.mImageLoader = imageLoader;
this.mAppManager = appManager;
}

@Override
public void onDestroy() {
super.onDestroy();
this.mErrorHandler = null;
this.mAppManager = null;
this.mImageLoader = null;
this.mApplication = null;
}

}

升级版ArmsComponent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import com.jess.arms.di.component.AppComponent;
import com.jess.arms.di.scope.ActivityScope;

import dagger.BindsInstance;
import dagger.Component;

/**
* 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同
* 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名
* 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component
* 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会
* 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可
* 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment
*/

#parse("File Header.java")

@ActivityScope
@Component(modules = ${NAME}Module.class,dependencies = AppComponent.class)
public interface ${NAME}Component {
void inject(${NAME}Activity activity);

@Component.Builder
interface Builder {
@BindsInstance
${NAME}Component.Builder view(${NAME}Contract.View view);
${NAME}Component.Builder appComponent(AppComponent appComponent);
${NAME}Component build();
}
}

升级版ArmsModule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;

import com.jess.arms.di.scope.ActivityScope;

import java.util.ArrayList;
import java.util.List;

/**
* 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同
* 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名
* 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component
* 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会
* 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可
* 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment
*/

#parse("File Header.java")

@Module
public abstract class ${NAME}Module {
//记得provides的方法要用static
/*@ActivityScope
@Provides
static RxPermissions provideRxPermissions(${NAME}Contract.View view) {
return new RxPermissions((FragmentActivity) view.getActivity());
}*/

@ActivityScope
@Provides
static RecyclerView.LayoutManager provideLayoutManager(${NAME}Contract.View view){
return new LinearLayoutManager(view.getActivity());
}

@ActivityScope
@Provides
static List<${NAME}Bean> provideList(){
return new ArrayList<>();
}

@ActivityScope
@Provides
static ${NAME}Adapter provideAdapter(List<${NAME}Bean> list, ${NAME}Contract.View view){
return new ${NAME}Adapter(list, view.getActivity());
}

@Binds
abstract ${NAME}Contract.Model provide${NAME}Model(${NAME}Model model);
}

升级版ArmsActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import android.app.Activity;
import android.content.Intent;

import androidx.annotation.NonNull;

import android.os.Bundle;

import com.jess.arms.base.BaseActivity;
import com.jess.arms.base.DefaultAdapter;
import com.jess.arms.di.component.AppComponent;
import com.jess.arms.utils.ArmsUtils;
import com.paginate.Paginate;

import javax.inject.Inject;

import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import butterknife.BindView;
import timber.log.Timber;

import static com.jess.arms.utils.Preconditions.checkNotNull;

/**
* 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同
* 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名
* 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component
* 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会
* 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可
* 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment
*/

#parse("File Header.java")

public class ${NAME}Activity extends BaseActivity<${NAME}Presenter> implements ${NAME}Contract.View,
SwipeRefreshLayout.OnRefreshListener {

@BindView(R.id.recyclerView)
RecyclerView mRecyclerView;
@BindView(R.id.swipeRefreshLayout)
SwipeRefreshLayout mSwipeRefreshLayout;

@Inject
RecyclerView.LayoutManager mLayoutManager;
@Inject
SimplePaddingDecoration simplePaddingDecoration;
@Inject
${NAME}Adapter mAdapter;

private Paginate mPaginate;
private boolean isLoadingMore;

@Override
public void setupActivityComponent(AppComponent appComponent) {
Dagger${NAME}Component
.builder()
.appComponent(appComponent)
.view(this)
.build()
.inject(this);
}

@Override
public int initView(Bundle savedInstanceState) {
//todo:如果你不需要框架帮你设置
return 0;
}

@Override
public void initData(Bundle savedInstanceState) {
setToolbar();
initRecyclerView();
mRecyclerView.addItemDecoration(simplePaddingDecoration);
mRecyclerView.setAdapter(mAdapter);
initPaginate();
setClickListener();
}

private void setClickListener() {
mAdapter.setOnItemClickListener(((adapter, view, position) -> {
// TODO: 2020/6/3 传参
//launchActivity(intent);
}));

}

private void setToolbar(){

}

private void initPaginate(){
if (mPaginate == null) {
Paginate.Callbacks callbacks = new Paginate.Callbacks() {
@Override
public void onLoadMore() {
mPresenter.request${NAME}sFromModel(false);
}

@Override
public boolean isLoading() {
return isLoadingMore;
}

@Override
public boolean hasLoadedAllItems() {
return false;
}
};
mPaginate = Paginate.with(mRecyclerView, callbacks)
.setLoadingTriggerThreshold(0)
.build();
mPaginate.setHasMoreDataToLoad(false);
}
}

private void initRecyclerView(){
mSwipeRefreshLayout.setOnRefreshListener(this);
ArmsUtils.configRecyclerView(mRecyclerView, mLayoutManager);
}


@Override
public void showLoading() {
Timber.tag(TAG).w("showLoading");
mSwipeRefreshLayout.setRefreshing(true);
}

@Override
public void hideLoading() {
Timber.tag(TAG).w("hideLoading");
mSwipeRefreshLayout.setRefreshing(false);
}

@Override
public void showMessage(@NonNull String message) {
checkNotNull(message);
ArmsUtils.snackbarText(message);
}

@Override
public void launchActivity(@NonNull Intent intent) {
checkNotNull(intent);
ArmsUtils.startActivity(intent);
}

@Override
public void killMyself() {
finish();
}

@Override
public Activity getActivity() {
return this;
}

@Override
public void startLoadMore() {
isLoadingMore = true;
}

@Override
public void endLoadMore() {
isLoadingMore = false;
}

@Override
public void onRefresh() {
mPresenter.request${NAME}sFromModel(true);
}

@Override
protected void onDestroy() {
//super.onDestroy()之后会unbind,所有view被置为null,所以必须在之前调用
DefaultAdapter.releaseAllHolder(mRecyclerView);
super.onDestroy();
this.mPaginate = null;
}
}

xml类型

mvp 的 activity_${layoutname}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/${layoutname}_srl"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v7.widget.RecyclerView
android:id="@+id/${layoutname}_rv"
android:layout_width="match_parent"
android:layout_marginLeft="@dimen/dp_10"
android:layout_marginTop="@dimen/dp_10"
android:layout_height="match_parent" />
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
</android.support.constraint.ConstraintLayout>

LdyFragment的布局文件 fragment_${layoutname}

fragment带多个子fragment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<!--fragment带多个子fragment的布局-->
<android.support.design.widget.TabLayout
app:tabTextAppearance="@android:style/TextAppearance.Widget.TabWidget"
android:id="@+id/${layoutname}_tl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="@android:color/white"
app:tabIndicatorColor="@color/main_color"
app:tabSelectedTextColor="@color/main_color"
app:tabTextColor="@color/dark_text_color" />

<View style="@style/ViewBoldSolidLine"/>

<com.u1city.androidframe.customView.NoScrollViewPager
android:id="@+id/${layoutname}_vp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

AS自己写模板

(在AS 4.0以下可用)

AS安装插件 TemplateBuilder

module级模板

  • Windows 路径:D:\Android\AS3.6.2\plugins\android\lib\templates\gradle-projects\NewArmsModule

  • Mac 路径:

    /Applications/Android\ Studio.app/Contents/plugins/android/lib/templates/gradle-projects/NewAndroidProject

Activity级模板

  • Windows路径:D:\Android\AS3.6.2\plugins\android\lib\templates\activities\MVPArmsTemplat

  • Windows 路径:

    D:\Android\AndroidStudio\plugins\android\lib\templates\activities\U1LdyMvpActivity

  • Mac 路径:

    /Applications/Android\ Studio.app/Contents/plugins/android/lib/templates/activities/U1LdyMvpActivity

定义模板

首先创建一个MVP的Activity,将动态的属性声明为变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package ${packageName};

import android.os.Bundle;
import com.blackbox.medicalpension.common.mvp.base.BaseCommonActivity;
import com.blackbox.medicalpension.common.mvp.mvp.BasePresenter;

import org.jetbrains.annotations.Nullable;

import java.util.List;

public class ${activityClass} extends BaseCommonActivity{

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.${layoutName});
initTitleWithBack("${titleName}");
}

@Nullable
@Override
public List<BasePresenter<?>> createPresenter() {
return null;
}
}

创建对应的Layout布局文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
android:background="@color/white">

<include
android:id="@+id/include_layout"
layout="@layout/lin_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

生成模板

选中两个模板文件,点击【ALT + T】,弹出【Configure Template Data】窗口。定义activityClass、layoutName、titleName三个变量,并【Finish】,生成模板。

AS生成模板.png

模板文件存放在…\Android Studio\plugins\android\lib\templates下

属性说明:

  • Template Category 对应模板的分类,对应选择导入模板时的模板分类,这里默认值是电脑的用户名。
  • Template Name 对应模板名称,对应选择导入模板时的模板名称,默认值是当前的Project名称。
  • Template Description 对应模板描述信息,对应导入模板时弹出的导入界面的文字描述,默认为空。
  • Template Folder 对应生成模板所存放的位置,如果是Mac操作系统则默认为/Applications/Android Studio.app/Contents/plugins/android/lib/templates, Windows系统的话由于差异比较大,就默认为空了,可以自行配置[Android Studio安装目录]/plugins/android/lib/templates(这里只需要配置一次即可,插件将自动保存该位置)。
  • Input data 配置模板变量
    在【Configure Template Data】下点击【add】配置刚才模板中定义的变量,配置完毕后点击【Finish】。

AS生成模板-配置变量.png

重启Studio后就可使用该自定义模板。

关于Input data的使用,先解释下每个属性对应的含义

  • id 变量名,必须和模板中使用的变量名对应,必填
  • name 变量简介,必填
  • type 变量类型,string和boolean两种,通过下拉框选择,必填
  • default 变量对应的默认值,选填
  • help 添加该变量时的提示信息,选填

模板文件后缀名都是以【.ftl】结尾。

globals.xml.ftl 全局变量文件 存放的是一些全局变量
recipe.xml.ftl 配置要引用的模板路径以及生成文件的路径
template.xml 模板的配置信息,以及要输入的参数.定义了模板的流程框架 基本结构
template_blank_activity.png 显示的缩略图(只是展示用)
LinActivity.java.ftl Activity模板文件

修改template.xml文件

为方便用户输入Activity名称或Layout名称,自动提示Layout或Activity名称,需要在文件中添加两个属性:
constraints=”class|unique|nonempty”
suggest=”${layoutToActivity(layoutName)}”
suggest=”${activityToLayout(activityClass)}”

修改AndroidManifest.xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="${packageName}">

<application>
<#if isNewModule>
<activity android:name="${ativityPackageName}.${activityClass}">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<#else>
<activity android:name="${packageName}.${activityClass}" />
</#if>
</application>
</manifest>

增加Kotlin模板

AS4.1上写模板【新方式】

(AS4.+以上可用。在AS 2020.3.1【这个得改】上用不了)

参考链接1-写给bigademo框架的MVVM

参考链接2-

别人写给MVPArms的模板

本文源码

步骤:

  1. 打开https://github.com/JetBrains/intellij-platform-plugin-template,点击绿色按钮“Use this template”就会fork一份代码到你自己的仓库。然后通过git工具clone到电脑上,用AS4.1+打开

  2. 修改包名、修改MyProjectManagerListener.kt、修改build.gradle.kts、修改gradle.properties

  3. src/main/kotlin/下新增个文件夹other,用来放自己写的具体模板

  4. 还要在src/main/resources/META-INF/plugin.xml中添加以下内容,才能让自己写的具体模板内容生效

    1
    2
    3
    4
    5
    <extensions defaultExtensionNs="com.android.tools.idea.wizard.template">
    <!-- <wizardTemplateProvider implementation="other.temparms.ArmsPluginTemplateProviderImpl" />-->
    <!-- <wizardTemplateProvider implementation="other.xm597.Xm597PluginTemplateProviderImpl" />-->
    <wizardTemplateProvider implementation="other.mvvm.SamplePluginTemplateProviderImpl" />
    </extensions>
  5. 在Terminal上输入 gradlew buildPlugin来生成模板jar文件(在项目的build/libs下)

  6. AS导入模板(File》Settings》Plugins》Install Plugin from Disk...

注意:

  1. gradle-wrapper.properties中gradle版本与build.gradle.kts中配置的版本是对应的

  2. gradle.propertiesplatformVersion的值为2020.2.4AS4.1.2AS4.1.3上无法正常编译模板,需要在AS4.2-Beta5上才行。所以在AS4.1.2上这个值改成了2020.1.4

    1
    2
    3
    4
    pluginVerifierIdeVersions =  2020.1.4 , 2020.2.4, 2020.3.2, 2021.1

    platformType = IC
    platformVersion = 2020.1.4

代码结构截图

AS4.1以上写模板

完整代码(动过的):

配置相关

src/main/kotlin/com/xml597/app/template/listeners/MyProjectManagerListener.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.xm597.app.template.listeners

import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManagerListener
import com.xm597.app.template.services.MyProjectService

internal class MyProjectManagerListener : ProjectManagerListener {

override fun projectOpened(project: Project) {
projectInstance = project
project.getService(MyProjectService::class.java)
}
override fun projectClosing(project: Project) {
projectInstance = null
super.projectClosing(project)
}

companion object {
var projectInstance: Project? = null
}
}

build.gradle.kts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import io.gitlab.arturbosch.detekt.Detekt
import org.jetbrains.changelog.closure
import org.jetbrains.changelog.markdownToHTML
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
// Java support
id("java")
// Kotlin support
id("org.jetbrains.kotlin.jvm") version "1.4.30"
// gradle-intellij-plugin - read more: https://github.com/JetBrains/gradle-intellij-plugin
id("org.jetbrains.intellij") version "0.6.5"
// gradle-changelog-plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin
id("org.jetbrains.changelog") version "1.1.2"
// detekt linter - read more: https://detekt.github.io/detekt/gradle.html
id("io.gitlab.arturbosch.detekt") version "1.15.0"
// ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle
id("org.jlleitschuh.gradle.ktlint") version "10.0.0"
}

// Import variables from gradle.properties file
val pluginGroup: String by project
// `pluginName_` variable ends with `_` because of the collision with Kotlin magic getter in the `intellij` closure.
// Read more about the issue: https://github.com/JetBrains/intellij-platform-plugin-template/issues/29
val pluginName_: String by project
val pluginVersion: String by project
val pluginSinceBuild: String by project
val pluginUntilBuild: String by project
val pluginVerifierIdeVersions: String by project

val platformType: String by project
val platformVersion: String by project
val platformPlugins: String by project
val platformDownloadSources: String by project

group = pluginGroup
version = pluginVersion

// Configure project's dependencies
repositories {
mavenCentral()
jcenter()
google()
}
dependencies {
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.15.0")
compileOnly(files("lib/wizard-template.jar"))
}

// Configure gradle-intellij-plugin plugin.
// Read more: https://github.com/JetBrains/gradle-intellij-plugin
intellij {
pluginName = pluginName_
version = platformVersion
type = platformType
downloadSources = platformDownloadSources.toBoolean()
updateSinceUntilBuild = true

// Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file.
setPlugins(*platformPlugins.split(',').map(String::trim).filter(String::isNotEmpty).toTypedArray())
}

// Configure gradle-changelog-plugin plugin.
// Read more: https://github.com/JetBrains/gradle-changelog-plugin
changelog {
version = pluginVersion
}

// Configure detekt plugin.
// Read more: https://detekt.github.io/detekt/kotlindsl.html
detekt {
config = files("./detekt-config.yml")
buildUponDefaultConfig = true

reports {
html.enabled = false
xml.enabled = false
txt.enabled = false
}
}

tasks {
// Set the compatibility versions to 1.8
withType<JavaCompile> {
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
}
withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}

withType<Detekt> {
jvmTarget = "1.8"
}

patchPluginXml {
version(pluginVersion)
sinceBuild(pluginSinceBuild)
untilBuild(pluginUntilBuild)

// Extract the <!-- Plugin description --> section from README.md and provide for the plugin's manifest
pluginDescription(
closure {
File("./README.md").readText().lines().run {
val start = "<!-- Plugin description -->"
val end = "<!-- Plugin description end -->"

if (!containsAll(listOf(start, end))) {
throw GradleException("Plugin description section not found in README.md:\n$start ... $end")
}
subList(indexOf(start) + 1, indexOf(end))
}.joinToString("\n").run { markdownToHTML(this) }
}
)

// Get the latest available change notes from the changelog file
changeNotes(
closure {
changelog.getLatest().toHTML()
}
)
}

runPluginVerifier {
ideVersions(pluginVerifierIdeVersions)
}

publishPlugin {
dependsOn("patchChangelog")
token(System.getenv("PUBLISH_TOKEN"))
// pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3
// Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more:
// https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel
channels(pluginVersion.split('-').getOrElse(1) { "default" }.split('.').first())
}
}

gradle.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# IntelliJ Platform Artifacts Repositories
# -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html

pluginGroup = com.xm597.qpp.template
pluginName_ = xm597 Plugin Template
pluginVersion = 1.0.0

# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html#intellij-platform-based-products-of-recent-ide-versions
# for insight into build numbers and IntelliJ Platform versions.
pluginSinceBuild = 201
pluginUntilBuild = 203.*

# Plugin Verifier integration -> https://github.com/JetBrains/gradle-intellij-plugin#plugin-verifier-dsl
# See https://jb.gg/intellij-platform-builds-list for available build versions
pluginVerifierIdeVersions = 2020.1.4 , 2020.2.4, 2020.3.2, 2021.1

platformType = IC
platformVersion = 2020.1.4
platformDownloadSources = true
# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
platformPlugins = java, com.intellij.java, org.jetbrains.android, android, org.jetbrains.kotlin

# Opt-out flag for bundling Kotlin standard library.
# See https://kotlinlang.org/docs/reference/using-gradle.html#dependency-on-the-standard-library for details.
kotlin.stdlib.default.dependency = false

settings.gradle.kts

1
rootProject.name = "xm597 Plugin Template"

src/main/resources/META-INF/plugin.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<idea-plugin>
<id>com.xm597.app</id>
<name>xm597 Plugin Template</name>
<vendo>shenbh</vendo>

<!-- Product and plugin compatibility requirements -->
<!-- https://plugins.jetbrains.com/docs/intellij/plugin-compatibility.html -->
<depends>org.jetbrains.android</depends>
<depends>org.jetbrains.kotlin</depends>
<depends>com.intellij.modules.java</depends>
<depends>com.intellij.modules.platform</depends>

<description>Integrates Volume Snapshot Service W10</description>
<change-notes>Initial release of the plugin.</change-notes>


<version>1.0.0</version>
<extensions defaultExtensionNs="com.intellij">
<applicationService serviceImplementation="com.xm597.app.template.services.MyApplicationService"/>
<projectService serviceImplementation="com.xm597.app.template.services.MyProjectService"/>
</extensions>

<applicationListeners>
<listener class="com.xm597.app.template.listeners.MyProjectManagerListener"
topic="com.intellij.openapi.project.ProjectManagerListener"/>
</applicationListeners>

<extensions defaultExtensionNs="com.android.tools.idea.wizard.template">
<!-- <wizardTemplateProvider implementation="other.temparms.ArmsPluginTemplateProviderImpl" />-->
<!-- <wizardTemplateProvider implementation="other.xm597.Xm597PluginTemplateProviderImpl" />-->
<wizardTemplateProvider implementation="other.mvvm.SamplePluginTemplateProviderImpl" />
</extensions>
</idea-plugin>

具体模板详情

src/main/kotlin/other/mvvm为例

src/main/kotlin/other/mvvm/SamplePluginTemplateProviderImpl.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package other.mvvm


import com.android.tools.idea.wizard.template.Template
import com.android.tools.idea.wizard.template.WizardTemplateProvider
import other.mvvm.activity.mvvmActivityTemplate
//import other.mvvm.fragment.mvvmFragmentTemplate
class SamplePluginTemplateProviderImpl : WizardTemplateProvider() {

override fun getTemplates(): List<Template> = listOf(
// activity的模板
mvvmActivityTemplate,
// fragment的模板
// mvvmFragmentTemplate
)
}

src/main/kotlin/other/mvvm/activity/mvvmActivityTemplate.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package other.mvvm.activity

import com.android.tools.idea.wizard.template.*
import com.android.tools.idea.wizard.template.impl.activities.common.MIN_API
import com.android.tools.idea.wizard.template.impl.defaultPackageNameParameter


val mvvmActivityTemplate
get() = template {
revision = 1
name = "MVVM Activity"
description = "适用于BigaDemoMVVM框架的Activity"
minApi = MIN_API
minBuildApi = MIN_API

category = Category.Other
formFactor = FormFactor.Mobile
screens = listOf(WizardUiContext.ActivityGallery, WizardUiContext.MenuEntry, WizardUiContext.NewProject, WizardUiContext.NewModule)

lateinit var layoutName: StringParameter
val activityClass = stringParameter {
name = "Activity Name"
default = "Main"
help = "只输入名字,不要包含Activity"
constraints = listOf(Constraint.NONEMPTY)
}

layoutName = stringParameter {
name = "Layout Name"
default = "activity_main"
help = "请输入布局名字"
constraints = listOf(Constraint.LAYOUT, Constraint.UNIQUE, Constraint.NONEMPTY)
suggest = {"${activityToLayout(activityClass.value.toLowerCase())}"}
}

val packageName = defaultPackageNameParameter

widgets(
TextFieldWidget(activityClass),
TextFieldWidget(layoutName),
PackageNameWidget(packageName)
)
//thumb{File("logo.png")}
recipe = { data: TemplateData ->
mvvmActivityRecipe(
data as ModuleTemplateData,
activityClass.value,
layoutName.value,
packageName.value
)
}
}

val defaultPackageNameParameter
get() = stringParameter {
name = "Package Name"
visible = {!isNewModule}
default = "com.mycompany.myapp"
constraints = listOf(Constraint.PACKAGE)
suggest = {packageName}
}

src/main/kotlin/other/mvvm/activity/mvvmActivityRecipe.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package other.mvvm.activity

import com.android.tools.idea.wizard.template.ModuleTemplateData
import com.android.tools.idea.wizard.template.RecipeExecutor
import other.mvvm.activity.res.layout.mvvmActivityXml
import other.mvvm.activity.src.app_package.mvvmActivityKt
import other.mvvm.activity.src.app_package.mvvmRepository
import other.mvvm.activity.src.app_package.mvvmViewModel

fun RecipeExecutor.mvvmActivityRecipe(
moduleData: ModuleTemplateData,
activityClass: String,
layoutName: String,
packageName: String
){
val (projectData, srcOut, resOut) = moduleData
val ktOrJavaExt = projectData.language.extension
// generateManifest(
// moduleData = moduleData,
// activityClass = "${activityClass}Activity",
// activityTitle = activityClass,
// packageName = packageName,
// isLauncher = false,
// hasNoActionBar = false,
// generateActivityTitle = true,
// requireTheme = false,
// useMaterial2 = false
// )

val mvvmActivity = mvvmActivityKt(projectData.applicationPackage, activityClass, layoutName, packageName)
//保存Activity
save(mvvmActivity, srcOut.resolve("${activityClass}Activity.${ktOrJavaExt}"))
// 保存xml
save(mvvmActivityXml(packageName, activityClass), resOut.resolve("layout/${layoutName}.xml"))
// 保存viewmodel
save(mvvmViewModel(packageName, activityClass), srcOut.resolve("${activityClass}ViewModel.${ktOrJavaExt}"))
// 保存repository
save(mvvmRepository(packageName, activityClass), srcOut.resolve("${activityClass}Repository.${ktOrJavaExt}"))
}

src/main/kotlin/other/mvvm/activity/res/layout/mvvmActivityXml.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package other.mvvm.activity.res.layout

fun mvvmActivityXml(
packageName: String,
activityClass: String
) = """
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data>

</data>

<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context="${packageName}.${activityClass}Activity">
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
"""

src/main/kotlin/other/mvvm/activity/src/app_package/mvvmActivity.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package other.mvvm.activity.src.app_package

fun mvvmActivityKt(
applicationPackage:String?,
activityClass:String,
layoutName:String,
packageName:String
)="""
package ${packageName}
import android.os.Bundle
import com.bigademo.baselib.base.BaseActivity
import ${applicationPackage}.R
import ${applicationPackage}.BR;
import ${applicationPackage}.databinding.Activity${activityClass}Binding
class ${activityClass}Activity : BaseActivity<${activityClass}ViewModel, Activity${activityClass}Binding>() {
override fun getContentView(): Int {
return R.layout.${layoutName}
}

override fun init(savedInstanceState: Bundle?) {
super.init(savedInstanceState)
isShowTopBar = false
}

override fun initViewModel() {
viewModel = ${activityClass}ViewModel()
}
/**
* 监听数据的变化
*/
override fun observe() {

}

/**
* 控件的点击事件
*/
override fun onClick() {
}

override fun initData() {
super.initData()
}
override fun initVariableId(): Int {
TODO("Not yet implemented")
}
}
"""

src/main/kotlin/other/mvvm/activity/src/app_package/mvvmRepository.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package other.mvvm.activity.src.app_package

fun mvvmRepository(
packageName: String,
activityClass: String
)="""
package ${packageName}

import androidx.lifecycle.MutableLiveData
import com.shide.baselib.base.basemvvm.BaseRepository
import com.shide.baselib.base.basemvvm.BaseViewModel
import com.shide.baselib.net.exception.ShideApiException
import kotlinx.coroutines.CoroutineScope

class ${activityClass}Repository(
baseViewModel: BaseViewModel,
coroutineScope: CoroutineScope,
errorLiveData: MutableLiveData<ShideApiException>
) : BaseRepository(baseViewModel, coroutineScope, errorLiveData) {
}
"""

src/main/kotlin/other/mvvm/activity/src/app_package/mvvmViewModel.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
package other.mvvm.activity.src.app_package

fun mvvmViewModel(
packageName:String,
activityClass:String
)="""
package ${packageName}
import androidx.lifecycle.viewModelScope
import com.bigademo.baselib.base.basemvvm.BaseViewModel
class ${activityClass}ViewModel : BaseViewModel() {
private val repo by lazy { ${activityClass}Repository(this, viewModelScope, errorLiveData) }
}
"""