Google announced official support for the Kotlin language at Google I/O 2017. Many developers started migrating the code base away from Java and learning Kotlin on the way. We are going to discuss how you can go from Java to Kotlin and also talk about some tips about this process.
Getting started
The very easy/initial thing you could do: use the Android Studio IDE to starting the convertion:
In the IDE, go to Android Studio -> Code -> Convert Java File to Kotlin File:
The converter is really nice, it is smart and does the most of job gracefully. However during the automated process the converter would choose not the most appropriate choice, so you must look into the code and figure out if the converter was right in all the scenarios. Probably the most interesting issue you may face is the nullability, because by default, all the converted object will be non-nullable and you will have to explicitly specified them to be nullable or change your logic. Another issue is about usage of android-annontations will most likely break. There is a shortcut to access the converter: CMD+SHFT+ALT+K or CTRL+SHIFT+ALT+K depending of your operational system.
Another option of converting the code is using the online tool try.kotlinlang. Access the URL https://try.kotlinlang.org and click on “Convert from Java”. In this way you can convert your project graduallly and observe all the changes clearly.
Things to keep in mind
Interoperability – Java and Kotlin work perfectly together. So don’t be afraid to add Kotlin code step by step, it’s not necessary to migrate all code to another language.
Pitfalls – Automatic conversions can also be dangerous to your project, there are some scenarios that you may face new bugs in your code, for example an unexpected nullability. Some code converted can be asserted as not null which in turn can lead to a NullPointerException.
Usage of val and lateinit – the misusage of these can cause problems to your actual project. val is like Java final variable and it’s known as immutable in kotlin and can be initialized only single time. A misusage of this field is setting a variable would be changed somehow, for example, a variable inside your model which will be used in a parcelable or as response of networki request. Make the property nullable if it makes better sense and improves null safety. lateinit might be good if used properly but it has its cons as well. Don’t make it a replacement for NullPointerException.
Google Codelab “Refactoring to Kotlin”
Google offers a Codelab specifically for refactoring Java code to Kotlin. Besides this course provides a very interesting channel to learn more about Koltin, its features and concepts, this is the list of what you will learn in the codelab:
Dependency Injection (DI) is a design pattern that removes the dependency from the programming code so that it can be easy to manage and test the application. Dependency Injection makes our programming code loosely coupled. DI allows classes to define their dependencies without constructing them. At runtime, another class is responsible for providing these dependencies.
Problems of Dependency
There are mainly two problems of dependency lookup:
The dependency lookup approach makes the code tightly coupled. If resource is changed, we need to perform a lot of modification in the code.
Not easy for testing This approach creates a lot of problems while testing the application especially in black box testing.
Dagger 2
Dagger 2 automatically constructs objects by walking the dependency tree, and it provides compile-time guarantees on dependencies.
Dagger 2 is also recommended by Android team.
Dagger 2 uses the following annotations:
@Module and @Provides: define classes and methods which provide dependencies. @Module are responsible for providing objects which can be injected. Such classes can define methods annotated with @Provides. The returned objects from these methods are available for dependency injection.
@Inject: requests the dependencies. In other words, this annotation will let Dagger knows what the dependencies it is needed to be used by the dependant.
Can be used on a constructor, a field, or a method.
@Component: enables selected modules and used for performing dependency injection.
ERC20 is a standard which defines a common list of rules that an Ethereum token has to implement, giving developers the ability to program how new tokens will function within the Ethereum ecosystem. ERC20 defines how the tokens are transferred between addresses and how data within each token is accessed.
The ERC777 token standard specifies an improvement of ERC20 while remaining backward compatible. It defines advanced features to interact with tokens. Namely, operators to send tokens on behalf of another address—contract or regular account—and send/receive hooks to offer token holders more control over their tokens.
ERC777 in a nutshell
Transactions – Let’s talk about of the most interesting features that this new standard is bringing to the world. ERC777 has a function called send() consists in having a transaction with an amount field and a data bit field. Thus the parameters can be freely selected again by the token user and the token operator in order to forward data to the recipient.
function send(address to, uint256 amount, bytes calldata data) external;
function operatorSend(
address from,
address to,
uint256 amount,
bytes calldata data,
bytes calldata operatorData
) external;
Burning Tokens – ERC777 provides a feature called “Burning tokens”. It is the act of destroying existing tokens that explicitly defines two functions to burn tokens (burn and operatorBurn). These functions facilitate the integration of the burning process in wallets and dapps. However, the token contract may prevent some or all holders from burning tokens for any reason. The token contract may also define other functions to burn tokens.
Backward Compatibility – The standard does not use transfer and transferFrom and uses send and operatorSend to avoid confusion and mistakes when deciphering which token standard is being used. Besides, ERC777 allows the implementation of ERC20 functions transfer, transferFrom, approve and allowance alongside to make a token fully compatible with ERC20.
This repository contains all reference implementation and all tests. The reference implementation is also available via npm. In order to use it, you can download and setup the npm in your machine, access the npm website to see the instructions.
After the npm configuration, install the erc777 with:
npm install erc777
OpenZeppelin
OpenZeppelin is an open framework of reusable and secure smart contracts in the Solidity. It provides implementations of standards like ERC20, ERC721 and now ERC777 too. The project started providing ERC777 after implementing the issue-1159.
In this contract ERC777.sol, we can see how the ERC777 implementation are being organized. The contract implements the interface IERC777 and IERC20, it is possible to safely interact with ERC22 and ERC777 while all the events are emitted during the interactions.
In order to use the OpenZeppelin implementation in your project, you can download and setup the npm in your machine, access the npm website to see the instructions.
After the npm configuration, install the openzeppelin with:
Every Android app has a main thread which is in charge of handling UI (including measuring and drawing views), coordinating user interactions, and receiving lifecycle events. If there is too much work happening on this thread, the app appears to hang or slow down, leading to an undesirable user experience. Any long-running computations and operations such as decoding a bitmap, accessing the disk, or performing network requests should be done on a separate background thread.
Applications may also require some tasks to run even when the user is not actively using the app such as syncing periodically with a backend server or fetching new content within an app on a periodic basis. Applications may also require services to run immediately to completion even after the user has completed interacting with the app. Google created a guide called Guide to background processing which determines which solution best meets your needs for these use cases.
TitleWorkManager is part of Android Jetpack and an Architecture Component for background work that needs a combination of opportunistic and guaranteed execution. Opportunistic execution means that WorkManager will do your background work as soon as it can. Guaranteed execution means that WorkManager will take care of the logic to start your work under a variety of situations, even if you navigate away from your app.
WorkManager is a simple, but incredibly flexible library that has many additional benefits. These include:
Support for both asynchronous one-off and periodic tasks
Support for constraints such as network conditions, storage space, and charging status
Chaining of complex work requests, including running work in parallel
Output from one work request used as input for the next
Handles API level compatibility back to API level 14(see note)
Works with or without Google Play services
Follows system health best practices
LiveData support to easily display work request state in UI
Get started
Add the WorkManager dependency in Java or Kotlin to your Android project by openning the build.gradle file for your project and add the google() repository as shown below:
Add the dependencies for the artifacts you need in the build.gradle file for your app or module. Currently you are able to add AndroidX dependencies or legacy Pre-AndroidX dependencies, so please choose the dependence what fit your project. Remember you can also add the $work_version into your gradle.build (project scope).
By default, WorkManager is initialized using a ContentProvider with a default Configuration. ContentProviders are created and run before the Application object, so this allows the WorkManager singleton to be setup before your code can run in most cases. This is suitable for most developers. However, you can provide a custom Configuration by using Configuration.Provider or initialize(android.content.Context, androidx.work.Configuration).
WorkManager BroadcastReceivers to monitor Constraints on devices before API 23. The BroadcastReceivers are disabled on API 23 and up. In particular, WorkManager listens to the following Intents:
In addition, WorkManager listens to system time changes and reboots to properly reschedule work in certain situations. For this, it listens to the following Intents:
android.permission.WAKE_LOCK to make //it can keep the device awake to complete work before API 23
android.permission.ACCESS_NETWORK_STATE //to listen to network changes before API 23 and monitor network Constraints
android.permission.RECEIVE_BOOT_COMPLETED //to listen to reboots and reschedule work properly.
Note that WorkManager may enable or disable some of its BroadcastReceivers at runtime as needed. This has the side-effect of the system sending ACTION_PACKAGE_CHANGED broadcasts to your app. Please be aware of this use case and architect your app appropriately.
Lifecycle-aware components perform actions in response to a change in the lifecycle status of another component, such as activities and fragments. These components help you produce better-organized, and often lighter-weight code, that is easier to maintain.
A common pattern is to implement the actions of the dependent components in the lifecycle methods of activities and fragments. However, this pattern leads to a poor organization of the code and to the proliferation of errors. By using lifecycle-aware components, you can move the code of dependent components out of the lifecycle methods and into the components themselves.
Components
ViewModel - provides a way to create and retrieve objects that are bound to a specific lifecycle. A ViewModel typically stores the state of a view’s data and communicates with other components, such as data repositories or the domain layer which handles business logic. To read an introductory guide to this topic, see ViewModel.
LifecycleOwner/LifecycleRegistryOwner - both LifecycleOwner and LifecycleRegistryOwner are interfaces that are implemented in the AppCompatActivity and Support Fragment classes. You can subscribe other components to owner objects which implement these interfaces, to observe changes to the lifecycle of the owner. To read an introductory guide to this topic, see Handling Lifecycles.
LiveData - allows you to observe changes to data across multiple components of your app without creating explicit, rigid dependency paths between them. LiveData respects the complex lifecycles of your app components, including activities, fragments, services, or any LifecycleOwner defined in your app. LiveData manages observer subscriptions by pausing subscriptions to stopped LifecycleOwner objects, and cancelling subscriptions to LifecycleOwner objects that are finished. To read an introductory guide to this topic, see LiveData.
Lifecycle
Lifecycle is a class that holds the information about the lifecycle state of a component (like an activity or a fragment) and allows other objects to observe this state. Lifecycle uses two main enumerations to track the lifecycle status for its associated component:
Event – The lifecycle events that are dispatched from the framework and the Lifecycle class. These events map to the callback events in activities and fragments.
State – The current state of the component tracked by the Lifecycle object.
LifecycleOwner
LifecycleOwner is a single method interface that denotes that the class has a Lifecycle. It has one method, getLifecycle(), which must be implemented by the class. If you’re trying to manage the lifecycle of a whole application process instead, see ProcessLifecycleOwner.
This interface abstracts the ownership of a Lifecycle from individual classes, such as Fragment and AppCompatActivity, and allows writing components that work with them. Any custom application class can implement the LifecycleOwner interface.
Components that implement LifecycleObserver work seamlessly with components that implement LifecycleOwner because an owner can provide a lifecycle, which an observer can register to watch.