ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Write an Android Studio Plugin Part 2: Persisting data

In the first part of this series we had a look at how to create a very basic plugin for Android Studio and we wrote our first action. In today’s article we will see how you can persist data in your plugin.

Remember that you can find all the code for this series on GitHub and you can also see the relevant code for each article on its own branch, this article’s code is in the branch Part2.

https://github.com/marcosholgado/plugin-medium

What are we going to do?

Today’s goal is persisting some data in our plugin. During that process we will learn what a component is and how we can use them to manage the lifecycle of our plugin. Just to get us started we are going to show a notification when Android Studio starts up and a new version of our plugin has been installed. You could use this feature in the future to show the users what’s new in your plugin.

What is a component?

Before we write any code we need to understand what a component is. Components are the fundamental concept of plugin integration, they are going to allow us to have control over their lifecycle and persist its state so it will be automatically saved and loaded.

There are three different types of components:

  • Application level components, created an initialized when the IDE (Android Studio) starts up.
  • Project level components, created for each project instance in the IDE.
  • Module level components, created for each module inside every project loaded in the IDE.

Step 1: Create a new component

The first thing we have to do is identify the type of component that we need. In our case we want to do something when Android Studio starts up so by looking at the different types of components we can clearly see that we are going to need an application component.

JetBrains documentation says that we may implement the ApplicationComponent interface, we don’t have to do it if we don’t want to but we will. The ApplicationComponent interface is going to give us those lifecycle methods mentioned before that we will use to do something when the IDE starts up. Those methods come from BaseComponent which ApplicationComponent extends.

Let’s write our component now, the first iteration is going to be pretty simple, we extend from ApplicationComponent and override initComponent to check if there is a new version.

Step 2: Implementing isANewVersion()

Here is where the fun begins. We are going to start by declaring two new fields: localVersion and version. The first one will store the latest version that we had installed, while the latter will be the actual version installed of our plugin.

We want to compare them to check if localVersion is behind version so we know we can show the user a notification because he just installed a new version of our plugin. We also have to update localVersion to have the same value as version so the next time the user launches Android Studio he/she won’t get the welcome message again.

To begin with, the user doesn’t have our plugin installed so we’ll give localVersion a value of "0.0" since our first version is "1.0-SNAPSHOT". You can change the version of your plugin in the build.gradle file but if you didn’t change it before it should be:

version '1.0-SNAPSHOT'

To implement isANewVersion we are going to do something simple. If you want you can change the method but the idea here is just to compare two versions that we can control so I’m going to avoid checking some edge cases.

First, we get rid of the -SNAPSHOT part of the version which I actually want to maintain on my versions. After that, we split each version using . as delimiter so we get a List<String> with all our major and minor numbers so we can compare them and return true or false. Is not the best algorithm you will see today but it works for our purpose. The assumptions with this algorithm are quite simple. Both versions have to have the same length and they have to follow the same naming convention “majorV.minorV”.

Step 3: Putting all together

Now is the time to move our isANewVersion method to our component along with our two new fields. You can get the version of your plugin using PluginManager and the id of your plugin, which you can find (and change) in the plugin.xml file. I would also recommend at this point to change the plugin name to something more meaningful like My awesome plugin.

<idea-plugin>
<id>myplugin.myplugin</id>
<name>My awesome plugin</name>
...

The whole implementation of the component is quite simple. We get the version from the PluginManager, check if there is a new version and, if there is, update the local version so the whole process is not triggered again the next time Android Studio is launched. Finally we show a simple notification to the user. All together it looks like this.

Step 4: Persisting the component state

We could now try to test our plugin and it won’t work for two reasons. First because we still have to register our component and secondly because we are not really persisting the state of the component yet. Every time that Android Studio is initialized localVersion will still have "0.0" as a value.

So, how do we do that? How can we save the state of the component? To do it we have to implement PersistentStateComponent. That means we have to override two new methods, getState and loadState. We also need to understand how PersistentStateComponent works. It will store the public fields, annotated private fields and bean properties into an XML format. To remove a public field from the serialization you can annotate the field with @Transient.

In our case I’m just going to annotate localVersion with @Attribute so it gets stored while we keep it private, return the component itself on getState and use XmlSerializerUtil to load the state. We also have to annotate the component using @State and specify where the xml is going to be.

As usual there are more options that you can do like defining the storage location or customizing the xml format but I’ll let you explore all of them, just head up to:

https://www.jetbrains.org/intellij/sdk/docs/basics/persisting_state_of_components.html

Step 5: Registering the component

The last step is registering the component in the plugin.xml file. To do that we just have to create a new component within the application-component section of the file and specify the component class that we have just created.

<application-components>
<component>
<implementation-class>
components.MyComponent
</implementation-class>
</component>
</application-components>

And this is it! You can now run the buildPlugin task, install the plugin from disk using the jar file generated in Android Studio and the next time you open Android Studio you will see this notification. After that, the notification will only be shown if you bump up the version of your plugin.

That was part number 2, in part 3 we will learn how to create a settings screen for our plugin and we will also have a first look at how you can create UI for your plugin. In the meantime if you have any questions please reach out on Twitter or leave a comment.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Written by Marcos Holgado

Senior Android Developer at DuckDuckGo. Speaker, Kotlin lover and I also fly planes. www.marcosholgado.com

Responses (2)

Write a response