Studio Mainstream Plug-ins

We know that Android Studio is an IDE environment based on Intellij. Intellij itself provides a plug-in development environment for developers, greatly improving development efficiency and IDE configuration. There are many mature plug-ins for Studio. Let’s take a look at some of the major Studio plugins out there that cover almost all of your needs: juejin.cn/post/684490…

Basically, the functions of plug-ins can be divided into the following categories:

1. Solve repetitive tasks:

The low technical content and high repeatability of studio work are replaced by plug-in forms.

The plug-in name Plug-in function
GsonFormat (jsonString automatically generates JavaBean classes)
ButterKnife Zelezny (XML automatically generates annotation code for ButterKnife)
Code Generator (XML automatically generates activity fragments)
AndroidProguardPlugin (Generate proGuard files based on dependent third-party libraries)
Exynap (More extended, the molding, fixed code segment, automatically generated)
MVPHelper (Automatically generate M V P to different folders)
2. Integrate features not included in Studio:

For the convenience of development, the studio itself does not have the function to introduce, expand the IDE function, to avoid studio and the third party switching back and forth and data transmission trouble.

The plug-in name Plug-in function
EventBus3 Intellij (Help index EventBus from SUBSCRIBE to POST, improve readability of EventBus)
GradleDependenciesHelperPlugin (Gradle relies on auto-complete)
SQLScout (Debug SQLite)
FindBugs-IDEA (FindBugs plug-in)
Android Methods Count (Preview the number of methods in the dependent library and judge the number of methods exceeding the limit in advance)

The development and use of plug-ins is very mature, most of them are free and open source, and the activity is very high. Because the utilization rate of Studio is very high, and the IntelliJ IDE itself is rich in plug-in resources, there are many direct reference plug-ins, so that the threshold of plug-in development is greatly reduced. We also recommend plug-ins when we encounter repetitive tasks or third-party functions that need to be embedded.

How to install the plug-in

Plugins-browse repositories for jetBrains Many plugins are free and open source repositories. We can use the beta version of the plugins, or do our own secondary development of the open source plug-in, in which case we need to install the local plug-in:

3, Preferences -plugins-install plugin from disk

In this article, I will take a secondary development of my own plugin as an example to document the basic flow of plugin development and notable pitfalls.


Plug-in development

Studio is a secondary development IDE based on IntelliJ, so plugins are actually plug-ins for IntelliJ. IntelliJ IDE itself can be used to develop plugins. Download the free version of IntelliJ, download the official website, and use the community version. No further elaboration.

Create and import projects

New project a lot of articles have, don’t go, you can refer to: www.jianshu.com/p/336a07b9d… Basically, configure the IntelliJ SDK, create the Plugin project, and then configure the plug-in in plugin.xml

Focusing on the import project, if you are secondary developing a plug-in, it is necessary to import an existing project on Github. Take GsonFormat as an example (github.com/zzz40500/Gs… Github project, divided into two branches master and dev_1.2.2 dev development branch can be directly used for secondary development. (The master branch directly imports as project, which requires a lot of IDE configuration)

Dev branch project configuration steps

  1. Import project from Existing code import project from Existing code import project from Existing code import project from Existing code import project from Existing code import project from Existing code One step has put the code under SRC into project as module, generating gsonformat.iml.
  2. In gsonformat. iml, module type is JAVA_MODULE instead of PLUGIN_MODULE. (The module setting of the project is very important to determine whether the project will compile properly.) A sign of successful configuration is the appearance of the RUN and DEBUG buttons in the IDE. If not, go to the button in the upper right corner of the IDE and enter the Project Structure for configuration
  3. To compile the Plugin properly, you need to configure the project properties in Edit Configuration, as shown in Figure 2. Create a new Plugin Configuration. In the Use classpath of module area on the right, select GsonFormat as PLUGIN_MODULE.
  4. At this point, you can either run debug or Prepare Plugin Module For Deployment(producing the local Plugin JAR).

Analysis of Plugin project

Now that the import is successful, what does the Plugin project look like? The following three types of files are common in the Plugin project, which are also unique to the plugin project:

  1. Action acts as the entry class of the entire plug-in, and its entry mode and name are defined in plugin.xml. ActionPerformed acts as the entry method in the Action, initializes the current class and package, and passes it into the dialog

  2. JsonDialog is the entry Dialog, FieldsDialog is the display Dialog after parsing jsonString. SettingDialog is a configuration dialog

  3. GUI Forms are similar to XML layout files in Android, except that swing drag-and-drop controls pair the Form with the Dialog, and their relationship is in the Form configuration.

GsonFormat code architecture

Taking GsonFormat Plugin as an example, the composition and realization principle of plugin project are explained in detail. First step: popup: Enter the jsonString you want to convert, here can also be configured with the Setting

How code (classes) are organized

The MainAction is the MainAction, and as the entry to the plugin you can see it launches the popover JsonDialog. Several dialogs are maintained in the project (including Java files and form files), which correspond to all popovers in the plug-in’s work and are placed in the UI folder.

  1. The DataWriter class is responsible for writing the last step of GsonFormat to the class file,
  2. The config folder maintains the plug-in’s Settings property (which can be configured by the user in SettingsDialog),
  3. Inside the Entity folder are the entity classes, and classes like classEntity fieldEntity are the entity classes that maintain the field and innerClass in the final generated class.
  4. In the process folder are the processing classes, jsonString parsing, javaBean encapsulation and other specific operations are completed in these classes, which are the core classes of the plug-in.
Processing flow

The code logic for the process is streaming, starting from the MainAction entry and then, after clicking OK in the JsonDialog, parsing the jsonString. The JsonUtilsDialog class uses the response function for the click event as an entry:

editTP.addKeyListener(new KeyAdapter() {
    @Override
    public void keyReleased(KeyEvent keyEvent) {
        super.keyReleased(keyEvent);
        if(keyEvent.getKeyCode() == KeyEvent.VK_ENTER) { onOK(); }}});Copy the code

JsonSTR onOK (); ConvertBridge; jsonSTR onOK ();

private void onOK() {// omit: get PsiClass generateClass: new ConvertBridge( this, errorLB, jsonSTR, mFile, mProject, generateClass, mClass, generateClassName).run(); }Copy the code

2. The Run method of the ConvertBridge class starts parsing jsonString using the parseJson method.

    public void parseJson(JSONObject json) {
        if(config.getInstant ().isvirgomode ()) {// Assembly mGenerateEntity object / / createFields parsing jsonString core method mGenerateEntity. SetFields (createFields (json, fieldList, mGenerateEntity)); FieldsDialog fieldsDialog = new FieldsDialog(mJsonUtilsDialog, mGenerateEntity, mFactory, mGeneratClass, currentClass, mFile, project, generateClassName); }else{ mGenerateEntity.setFields(createFields(json, fieldList, mGenerateEntity)); WriterUtil writerUtil = new WriterUtil(null, null, mFile, project, mGeneratClass); writerUtil.mInnerClassEntity = mGenerateEntity; writerUtil.execute(); }}Copy the code

Divided into Virgo mode and non-Virgo mode (default Virgo mode) : Virgo mode starts FieldsDialog, which is the second window we see, and the user modifies the fields definition. Non-virgo mode is easier, skip dialog and write fields to class. Virgo is generally used unless the Settings themselves define it. You can see that the createFields method is called with or without Virgo mode, the only difference being whether FieldsDialog is displayed.

3. Take a closer look at what the createFields method does.

for (int i = 0; i < list.size(); i++) {
    String key = list.get(i);
    Object type = json.get(key);
    if (typeInstanceof JSONArray) {// Add JSONArray to listEntityList listentitylist.add (key);continue;
    }
    FieldEntity fieldEntity = createFiled(parentClass, key, type);
    fieldEntityList.add(fieldEntity);
}
for(int i = 0; i < listEntityList.size(); I ++) {String key = listEntitylist.get (I); Objecttype = json.get(key);

    FieldEntity fieldEntity = createFiled(parentClass, key, type);
    fieldEntityList.add(fieldEntity);
}
Copy the code

The createFields method puts the field into the FieldEntity, and the DataWriter writes the field to the class according to the Contents of the FieldEntity.

JavaBean (JSONObject); JavaBean (JSONObject); JavaBean (JSONObject); JavaBean (JSONObject);

private FieldEntity typeByValue(InnerClassEntity parentClass, String key, Object type) {
        if (type instanceof JSONObject) {
            InnerClassEntity classEntity = checkInnerClass((JSONObject) type);
            ifClassEntity == null {// omit code}else {
                FieldEntity fieldEntity = new FieldEntity();
                fieldEntity.setKey(key);
                fieldEntity.setTargetClass(classEntity);
                fieldEntity.setType("%s"); nodeBean = fieldEntity; }}Copy the code

The createFields method calls the createField method for each fieldEntity in turn, the createFiled method calls the typeByValue method, The createFields method is applied to the child JSON again in createInnnerClass, recursively. Completed a layer of Javabean parsing work. You can say that a Class contains a FieldEntry, and FieldEntry itself contains multiple child fieldentries. FieldEntry can be set to a basic type or ClassEntity.

5. Finally, write FieldEntry to the class file by WriterUtil class to complete the plug-in function.

Part of secondary development

Problems encountered during development

Due to code confusion, normal debug code is often encountered in the development. In the case of release package, the network data cannot be properly parsed, because the field in the Javabean class is not the original defined name after confusion. And this problem is most likely to occur at the pass of raising measurement. To solve this problem, you must ensure that Javabeans are not confused in packaging. How not to be confused, different vendors have different solutions (specifications) :

  1. Place them in a single folder (or folder with a fixed name) and ignore them when confused. However, this approach is not perfect, for one thing, folders are easy to change names after refactoring, and there is no guarantee that everyone will comply with the team development. Handle code with the folder name on the string.
  2. All JavaBean extends Serializable such that the ProGuard file ensures that all subclasses of Seriallizable are not confused. And javabeans can be used directly when the Bundle passes parameters. However, there is a drawback to this approach: the need to ensure that everyone complies with the convention makes it impossible to regulate this step.

Our solution:

In general, mock jsonString can be generated in our interface management system. The client development will directly use SGsonFormat plug-in to convert jsonString directly into JavaBean. Therefore, based on the secondary development of GsonFormat function, Serializable can be inherited from all JavaBean classes for ease of use and uniformity.

Secondary development of GsonFormat:

Unified inherit Serializable logic, should be put into the process written by DataWriter, analysis can be obtained: The process method in the ClassProcessor actually writes the String content of the classContent to the class file via the PsiElementFactory, so you can modify the String classContent.

protected void generateClass(PsiElementFactory factory, ClassEntity classEntity, PsiClass parentClass, IProcessor visitor) {

    onStartGenerateClass(factory, classEntity, parentClass, visitor);
    PsiClass generateClass = null;
    if (classEntity.isGenerate()) {
        if(Config.getInstant().isSplitGenerate()) { try { generateClass = PsiClassUtil.getPsiClass( parentClass.getContainingFile(), parentClass.getProject(), classEntity.getQualifiedName()); } catch (Throwable throwable) { throwable.printStackTrace(); }}else{// Create class String classContent = according to classContent"public static class " + classEntity.getClassName() + " implements Serializable" + "{}";
            generateClass = factory.createClassFromText(classContent, null).getInnerClasses()[0];
        }

        if(generateClass ! = null) {// Recursive call to create inner classfor (ClassEntity innerClass : classEntity.getInnerClasss()) {
                generateClass(factory, innerClass, generateClass, visitor);
            }
            if(! Config.getInstant().isSplitGenerate()) { generateClass = (PsiClass) parentClass.add(generateClass); } // Create internal variablesfor(FieldEntity fieldEntity : classEntity.getFields()) { generateField(factory, fieldEntity, generateClass, classEntity); } // Create the internal getter setter method generateGetterAndSetter(Factory, generateClass, classEntity); generateConvertMethod(factory, generateClass, classEntity); } } onEndGenerateClass(factory, classEntity, parentClass, generateClass, visitor);if(Config.getInstant().isSplitGenerate()) { formatJavCode(generateClass); }}Copy the code

The plug-in download address: (the plug-in has been submitted to the repository) plugins.jetbrains.com/plugin/1110… Or simply search for SGsonFormat to use install

conclusion

The secondary development changes are not big, but the Studio plugin development environment and process is familiar with a time, plugin plug-in development can be said that you can use Java to get started, but his custom file type and organization need to be familiar with. Creating a new plugin is a great way to increase productivity if needed.