如果觉得写mvp有点枯燥无味,我们可以做点 cool 的事情:做个 as 插件
help.png
Google官方安卓Mvp架构demo
https://github.com/googlesamples/android-architecture
- todo-mvp: 基础的MVP架构。
- todo-mvp-loaders:基于MVP架构的实现,在获取数据的部分采用了loaders架构。
- todo-mvp-databinding: 基于MVP架构的实现,采用了数据绑定组件。
- todo-mvp-clean: 基于MVP架构的clean架构的实现。
- todo-mvp-dagger2: 基于MVP架构,采用了依赖注入dagger2。
- dev-todo-mvp-contentproviders: 基于mvp-loaders架构,使用了ContenPproviders。
- dev-todo-mvp-rxjava: 基于MVP架构,对于程序的并发处理和数据层(MVP中的Model)的抽象。
因为对mvp的理解不同,会有很多种方式表达架构,所以插件要极简易读,可扩展性强,所以可以选择:
/**
* 通过模板生成类
* @param var1 文件生成路径
* @param var2 文件名
* @param var3 模板名
* @param var4 是否生产类
* @param var5 模板参数
*/
public abstract PsiClass createClass(@NotNull PsiDirectory var1, @NotNull String var2, @NotNull String var3, boolean var4, @NotNull Map<String, String> var5) throws IncorrectOperationException;
也就是只要定制不同的模板就可以实现扩展性
直接贴下步骤:
-
1: idea File - new - Project - IntelliJ Platform Plugin
dir.PNG
plugin.xml 插件配置信息:
<idea-plugin>
<id>com.your.company.unique.plugin.id</id>
<name>Plugin display name here</name>
<version>1.0</version>
<vendor email="support@yourcompany.com" url="http://www.yourcompany.com">YourCompany</vendor>
<description><![CDATA[
Enter short description for your plugin here.<br>
<em>most HTML tags may be used</em>
]]></description>
<change-notes><![CDATA[
Add change notes here.<br>
<em>most HTML tags may be used</em>
]]>
</change-notes>
<!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html for description -->
<idea-version since-build="145.0"/>
<!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
on how to target different products -->
<!-- uncomment to enable plugin in all products
<depends>com.intellij.modules.lang</depends>
-->
<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
</extensions>
<actions>
<action id="generateMVPField" class="actions.MvpGenerator" text="Generate MVP By String"
description="Generate MVP" icon="/icons/app_icon.png">
<add-to-group group-id="GenerateGroup" anchor="first"/>
<add-to-group group-id="NewGroup" anchor="last"/>
<keyboard-shortcut keymap="$default" first-keystroke="alt I"/>
</action>
</actions>
</idea-plugin>
action:
public class MvpGenerator extends AnAction implements MvpHandler.OnGenerateListener {
private AnActionEvent actionEvent;
private MvpHandler mvpHandler;
private Map<String, String> map = new HashMap<>();
@Override
public void actionPerformed(AnActionEvent anActionEvent) {
this.actionEvent = anActionEvent;
mvpHandler = new MvpHandler();
mvpHandler.setTitle("输入名称-生成MVP相关类");
mvpHandler.setOnGenerateListener(this);
mvpHandler.pack();
//设置对话框跟随当前windows窗口
mvpHandler.setLocationRelativeTo(WindowManager.getInstance().getFrame(anActionEvent.getProject()));
mvpHandler.setVisible(true);
}
@Override
public void onGenerate(String text) {
JavaDirectoryService directoryService = JavaDirectoryService.getInstance();
//当前工程
Project project = actionEvent.getProject();
map.put("NAME", text);
map.put("PACKAGE_NAME", Util.getPackageName(project));
//鼠标右键所选择的路径
IdeView ideView = actionEvent.getRequiredData(LangDataKeys.IDE_VIEW);
PsiDirectory directory = ideView.getOrChooseDirectory();
assert directory != null;
if (directory.getName().contains("contract") && directory.findFile(text + "Contract.java") == null) {
directoryService.createClass(directory, text + "Contract", "GenerateContractFile", true, map);
}
if (directory.getName().contains("model") && directory.findFile(text + "Model.java") == null) {
directoryService.createClass(directory, text + "Model", "GenerateModelFile", true, map);
}
if (directory.getName().contains("presenter") && directory.findFile(text + "Presenter.java") == null) {
directoryService.createClass(directory, text + "Presenter", "GeneratePresenterFile", true, map);
}
}
@Override
public void onCancel() {
mvpHandler.setVisible(false);
}
}
dialog: (action下,右键,new dialog)
public class MvpHandler extends JDialog {
private JPanel contentPane;
private JButton buttonOK;
private JButton buttonCancel;
private JTextArea textArea1;
private OnGenerateListener listener;
public void setOnGenerateListener(OnGenerateListener listener) {
this.listener = listener;
}
public MvpHandler() {
setContentPane(contentPane);
setModal(true);
getRootPane().setDefaultButton(buttonOK);
buttonOK.addActionListener(e -> listener.onGenerate(textArea1.getText().trim()));
buttonCancel.addActionListener(e -> listener.onCancel());
// call onCancel() when cross is clicked
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
listener.onCancel();
}
});
// call onCancel() on ESCAPE
contentPane.registerKeyboardAction(e -> listener.onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
}
public interface OnGenerateListener{
void onGenerate(String text);
void onCancel();
}
}
MvpHandler.form 拖动控件
dialog.PNG
Util:
public class Util {
/**
* AndroidManifest.xml 获取 app 包名
* @return
*/
public static String getPackageName(Project project) {
String package_name = "";
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(project.getBasePath() + "/app/src/main/AndroidManifest.xml");
NodeList nodeList = doc.getElementsByTagName("manifest");
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
Element element = (Element) node;
package_name = element.getAttribute("package");
}
} catch (Exception e) {
e.printStackTrace();
}
return package_name;
}
}
-
2: 定制模板:按需求定制
new - file - xxx.java.ft
GenerateContractFile.java.ft
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")
package ${PACKAGE_NAME};
#end
import base.IBaseModel;
import base.IBaseView;
import base.IPresenter;
public interface ${NAME}Contract{
interface I${NAME}View extends IBaseView{
}
interface I${NAME}Model extends IBaseModel{
}
interface I${NAME}Presenter extends IPresenter<I${NAME}View>{
}
}
GenerateModelFile.java.ft
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
import ${PACKAGE_NAME}.contract.${NAME}Contract;
import base.IBaseModel;
public class ${NAME}Model implements ${NAME}Contract.I${NAME}Model{
public static IBaseModel newInstance(){
return new ${NAME}Model();
}
}
GeneratePresenterFile.java.ft
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")
package ${PACKAGE_NAME}
;#end
import ${PACKAGE_NAME}.contract.${NAME}Contract;
import ${PACKAGE_NAME}.model.${NAME}Model;
import base.BasePresenter;
public class ${NAME}Presenter extends BasePresenter<${NAME}Contract.I${NAME}View,${NAME}Contract.I${NAME}Model> implements ${NAME}Contract.I${NAME}Presenter{
@Override
public ${NAME}Contract.I${NAME}Model bindModel(){
return (${NAME}Contract.I${NAME}Model)${NAME}Model.newInstance();
}
}
MVP:
BasePresenter:
public abstract class BasePresenter<T extends IBaseView,M extends IBaseModel> implements IPresenter<T> {
protected T mView;
protected M mModel;
protected CompositeDisposable mDisposable;
public BasePresenter() {
this.mModel = bindModel();
mDisposable = new CompositeDisposable();
}
public boolean isViewAttached() {
return mView != null;
}
public void checkViewAttached() {
if (!isViewAttached()) throw new RuntimeException("未注册View");
}
@Override
public void onAttach(T t) {
mView = t;
if (mModel == null) {
throw new NullPointerException("model没有绑定 不能使用");
}
}
/**
* return Model
*/
public abstract M bindModel();
@Override
public void onDetach() {
if (!mDisposable.isDisposed())
mDisposable.dispose();
mView = null;
}
}
IBaseModel:
package base;
/**
* Created by haoran on 2018/4/4.
*/
public interface IBaseModel {
}
IBaseView :
package base;
/**
* Created by haoran on 2017/10/30.
*/
public interface IBaseView {
void showLoading();
void hideLoading();
void onError(String message);
}
IPresenter:
package base;
/**
* Created by haoran on 2017/10/30.
*/
public interface IPresenter<T> {
void onAttach(T t);
void onDetach();
}
实现类:(引导页为例)... import 忽略
GuideContract:
public interface GuideContract {
interface IGuideView extends IBaseView{
void showGuideImages(List<GuideImgBean.PictureListBean> pictureListBeans);
void showGuideDefaultImage();
}
interface IGuideModel extends IBaseModel {
Observable<List<GuideImgBean.PictureListBean>> getGuideImages();
}
interface IGuidePresenter extends IPresenter<IGuideView> {
void getGuideImages();
}
}
GuideModel:
public class GuideModel implements GuideContract.IGuideModel {
public static IBaseModel newInstance() {
return new GuideModel();
}
public Observable<List<GuideImgBean.PictureListBean>> getGuideImages() {
return ApiHelper.get().getGuideImages(new JSONObject());
}
}
GuidePresenter:
public class GuidePresenter extends BasePresenter<GuideContract.IGuideView, GuideContract.IGuideModel> implements GuideContract.IGuidePresenter {
@Override
public void getGuideImages() {
checkViewAttached();
mDisposable.add(mModel.getGuideImages().subscribe(pictureList -> {
if (pictureList == null || pictureList.size() == 0) {
mView.showGuideDefaultImage();
} else {
mView.showGuideImages(pictureList);
}
}, throwable -> mView.showGuideDefaultImage()));
}
@Override
public GuideContract.IGuideModel bindModel() {
return (GuideContract.IGuideModel) GuideModel.newInstance();
}
}
根据自己实际的mvp实现类定制模板
-
3: 打包插件,as引入插件,使用插件(插件开发调试忽略)
打包:idea里 build - Prapare Pulgine Module 'xxx' for Developer
项目目录下的jar包
打开as -- setting pulgine import from disk : jar 包目录
重启as
选中目录(含contract , model ,presenter) alt + i(快捷键可在plugine.xml配置)
或 右键 - new - 点击插件图标
输入 名称(XXX)--- 生成 java 类
generate1.PNG
点击ok
generate2.PNG
感谢:)
网友评论