为AndroidStudio开发mvp插件(MvpHelper)

如果觉得写mvp有点枯燥无味,我们可以做点 cool 的事情:做个 as 插件

为AndroidStudio开发mvp插件(MvpHelper)
文章图片
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)的抽象。
idea插件论坛
https://intellij-support.jetbrains.com/hc/en-us/community/topics/200366979-IntelliJ-IDEA-Open-API-and-Plugin-Development
因为对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 var5) throws IncorrectOperationException;

也就是只要定制不同的模板就可以实现扩展性
直接贴下步骤:
  • 1: idea File - new - Project - IntelliJ Platform Plugin
    为AndroidStudio开发mvp插件(MvpHelper)
    文章图片
    dir.PNG
    plugin.xml 插件配置信息:
com.your.company.unique.plugin.id Plugin display name here 1.0 YourCompany most HTML tags may be used ]]> most HTML tags may be used ]]>

action:
public class MvpGenerator extends AnAction implements MvpHandler.OnGenerateListener {private AnActionEvent actionEvent; private MvpHandler mvpHandler; private Map 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 拖动控件

为AndroidStudio开发mvp插件(MvpHelper)
文章图片
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}; #endimport 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{}}

GenerateModelFile.java.ft
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}; #endimport ${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} ; #endimport ${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 implements IPresenter {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 {void onAttach(T t); void onDetach(); }

实现类:(引导页为例)... import 忽略
GuideContract:
public interface GuideContract { interface IGuideView extends IBaseView{void showGuideImages(List pictureListBeans); void showGuideDefaultImage(); }interface IGuideModel extends IBaseModel { Observable> getGuideImages(); }interface IGuidePresenter extends IPresenter {void getGuideImages(); }}

GuideModel:
public class GuideModel implements GuideContract.IGuideModel {public static IBaseModel newInstance() { return new GuideModel(); }public Observable> getGuideImages() { return ApiHelper.get().getGuideImages(new JSONObject()); } }

GuidePresenter:
public class GuidePresenter extends BasePresenter 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 类
    为AndroidStudio开发mvp插件(MvpHelper)
    文章图片
    generate1.PNG
    点击ok
    为AndroidStudio开发mvp插件(MvpHelper)
    文章图片
    generate2.PNG
【为AndroidStudio开发mvp插件(MvpHelper)】感谢:)

    推荐阅读