Each year there’s a new version of the Android SDK released. Along with the myriad of new features come deprecations. When something is deprecated, although it’s still available, it’s best to migrate to the recommended new API. With that being said here are some common deprecations I encountered in my company’s Android codebase and how to fix them.
Deprecated Menu APIs on Fragments
The Fragment APIs for providing a menu to your activity’s ActionBar
have been deprecated as they tightly couple your fragment to your activity and are not testable in isolation. The new MenuHost
and MenuProvider
APIs provide a testable, lifecycle-aware equivalent API surface that fragments should use instead.
Previous
Previously, in the onViewCreated
method, you’d make a call to setHasOptionsMenu
().
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
setHasOptionsMenu(true)
}
Current
Now, you let your fragment implement the MenuProvider
interface. Then inside of the onViewCreated
method, you can set the fragment as the menu provider for your menu host.
class MyFragment : Fragment(), MenuProvider {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
val menuHost: MenuHost = requireActivity() as MenuHost
menuHost.addMenuProvider(
this, viewLifecycleOwner, State.RESUMED
)
}
}
Finally, implement the following methods of the MenuProvider
interface. The naming is similar to the previous functions that you would use for the action bar.
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.menu_event_comment_post, menu)
}
override fun onPrepareMenu(menu: Menu) {
...
}
override fun onMenuItemSelected(item: MenuItem): Boolean =
when {
...
}
Deprecated Handler constructor
This is a simple one. A Handler allows you to send and process Message
and Runnable
objects on Android. In our application, handlers are mostly used in legacy portions of the codebase to perform a delayed action.
Previous
You could implicitly choose a Looper during Handler construction by not providing any value to the constructor. This could easily lead to bugs, crashes, or race conditions.
private val handler = Handler()
Current
To help protect us from ourselves, the default constructor is now deprecated. Instead, you should use an Executor
or specify the Looper
explicitly. Here’s an example where we specify the main looper.
private val handler = Handler(Looper.getMainLooper())
Deprecated startActivityForResult APIs
The startActivityForResult
method allows you to start another activity either from your own app or another and get some type of result back. This is common for things like taking a picture, opening a document, or asking for a permission.
Previous
Previously, you would call a method on the activity startActivityForResult
and then override the onActivityResult
method to listen for the result. And this worked fine. Here’s an example of starting an activity to edit a user’s profile. And then listening for a successful result and refreshing the screen.
startActivityForResult(
Intents.editProfile(activity, false, null, memberId),
EDIT_PROFILE
)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == EDIT_PROFILE && resultCode == RESULT_OK) {
onRefresh()
}
}
Current
However, it’s now recommended to use the Activity Result APIs. The Activity Result APIs provide components for registering for a result, launching the result, and handling the result once it is dispatched by the system.
Now, to do the same thing as we did previously, you create a property in the class, often denoted as a launcher
. This launcher does the same behavior as the onActivityResult
callback. Finally, you call launch
on the launcher property when you’re ready to start the other activity.
private val editProfileLauncher = registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == RESULT_OK) {
onRefresh()
}
}
editProfileLauncher.launch(Intents.editProfile(activity, false, null, memberId))
Keeping up-to-date with the ever-changing Android APIs doesn’t have to be a daunting task. In fact, you can often make these types of changes quickly with IntelliJ’s Structural Search and Replace feature.
Hope you found this helpful!