Deprecated. A word that usually makes us developers a little anxious whenever we see it in our project. What does it even mean that something is deprecated? It means that you should no longer use the solution annotated as deprecated and you should start using a new approach that is usually simpler, easier, and sometimes even less expensive resources wise. But how can we know what needs to be done to replace our deprecated code? One way is to search for a solution on the internet. But if you are lucky and the person that has deprecated the code is accustomed to documenting their changes, then you don’t need to leave your Android Studio to find what is the correct way to replace your deprecated code.
Let’s take a real case scenario that has probably already happened to you. You might have some project that targets API 29 or below and is using a custom view for Toast messages in your project. And if you run your implementation on a device with API 30 you can see your Toasts not showing anymore. But how could this happened to us, since the code we are using doesn’t alert us that something is deprecated? If we check the official Android documentation, we can see they have deprecated getting or setting a view from the Toast component with API 30. The code is marked as deprecated only once you set your project target SDK to API 30. I believe the Android team could have handled this way better than they did, but we will leave this for some other time.
Since API 30 is more and more widely used, we need to handle this issue as a high priority and fix it as soon as possible. Luckily for us, we have the implementation of a custom view for a Toast in one file and the whole project depends on this file to show a Toast message. Our implementation for this is written in ToastUtils and it looks like this:
To go quickly through the code, we have 4 public methods for 4 different types of Toast messages. The only thing changing according to the type is the color of the Toast message. And all public methods are calling the same private method that is responsible for showing the Toast in the correct color and position. Check the video below for how it works.
Before we deprecate our Toast usage in our project, we need to find a good replacement for it. As we can see in the video, our Toast looks a lot like Snackbar, so we found a good solution for our example. Before we do any deprecation in our project, we need to implement a replacement that will behave in the same way as our Toast did before. For this purpose we implemented the next code in our SnackbarUtils object:
The above implementation doesn’t exactly match the previous Toast design, but for a sake of a short example, we show a regular Snackbar at the top of the screen. You can find a matching Snackbar solution here if you are interested. If we go through the code, we can see that we have the same 4 public methods with the same properties as in ToastUtils object and 1 private method that is responsible for a look of Snackbar. Whenever you are writing a replacement for your code try to match the deprecated method's signature if is possible.
And now we can deprecate our old implementation of ToastUtils. But how should we do that? We can use @Deprecated annotation on our methods inside ToastUtils class. Let’s check the constructor of Deprecated annotation, what can be done.
That constructor has provided us with 3 properties. Let’s go through them one by one and see how did we use them in our case.
message - Custom text that will be shown whenever the developer sees deprecated code in the project. In our example, we can use the same message for all methods since all the methods do the same thing, and the reason for deprecation is the same for all of them.
replaceWith - here we provide an alternative that can be used instead of deprecated code. As we can see in the constructor, this property is optional and doesn’t need to be provided. But is recommended to provide it if you can, because it will make our colleague's lives a lot easier. ReplaceWith object can receive 2 properties. The first is an expression where we put an actual replacement for deprecated code. And the second one imports, where you can list all imports need it for provided expression. This is something that will be different for all of ours methods, but let’s check what we have used for our regular type of Toast message.
level - with this property we set how sensitive will our deprecated code be in our project. We can choose among 3 different levels.
HIDDEN. As we can see in the constructor, the level is set as
WARNING there. It’s recommended to start your deprecation at this level. That way will your code only warns developers with crossed-out code, but in our example, we will use different levels, so we can see their impact. Note that if you choose
ERROR for your level, then your usage of this deprecated method will be shown as an error and you will not be able to build your project. If you decide to use level
HIDDEN then your method will be shown as an unaccessible method and IDE navigation to it won’t work anymore. Consequently, your project won’t successfully build under this level as well.
After deprecation our ToastUtils class looks like this:
Now we can take a look at how deprecation affected our code. For this example, we have usage of ToastUtils class only in one class and we can see that our depreciation has taken an effect on written code. Since we have 4 different methods with 4 different behaviors attached to them, we can see that Android Studio is presenting each one of them in a different way. To make a clear difference between different levels in our project we decided to:
- leave regular Toast message as it was
- warn the developer about the usage of success Toast type
- show an error whenever a developer wants to use error Toast type
- hide method that could be used for showing warning Toast type.
Let’s check the next image of how did we impact our code with our deprecation.
If you leave your mouse cursor over a method that is deprecated with the
ERROR level, you can see the next message that helps the developer a lot.
At the top part of that dialog, we see everything that we need to know regarding our next steps to make our project deprecation free. We see our message why is method deprecated and we can also see the alternative that needs to be used instead. And there is one more benefit for developers with this popup. If the developer press on Replace with SnackbarUtils.showSuccess(activity, textMessage), your code gets automatically fixed with all the imports added. Isn’t that awesome? You can also use the Quick actions shortcut to fix deprecation in the same way.
The whole process of deprecation in Android with kotlin is very easy to introduce in your project. So I encourage you to use it whenever you can, especially on big projects. If you have any questions, just leave a comment down below.
1. Base project
2. Target change to API 30
3. SnackbarUtils implementations
4. Matching Snackbar design to previous Toast design
5. Deprecation with different deprecation levels
6. Deprecation with only WARNING level