This project contains a set of useful Android Kotlin Extensions separated according to their use and dependencies.
This library contains some useful common Android extensions without additional dependencies.
Use the library by adding implementation "com.twocoders.extensions:common:1.1.1"
into your build.gradle file.
Android versions:
if (isAtLeastOreo) { /*true logic here*/ } else { /*false logic here*/ }
General information:
// This prints: My device is Google Pixel running on Android 10.
Log.i("Example", "My device is $deviceName running on Android $androidVersion.")
Kotlin Singleton with arguments:
// Declaration
class Repository private constructor(app: Application) {
companion object : SingletonHolder<Repository, Application>(::Repository)
}
// Access
val repository = Repository.getInstance(app)
Context (ApplicationContext) and Application extensions:
// Access system managers
val inputMethodManager: InputMethodManager? = context.inputMethodManager // or application.inputMethodManager
val batteryManager: BatteryManager? = context.batteryManager // or application.batteryManager
...
// Check device features
val hasGps: Boolean = context.hasGps // or application.hasGps
val hasGyroscope: Boolean = context.hasGyroscope // or application.hasGyroscope
...
// Check system features
val isRtl: Boolean = context.isRtl // or application.isRtl
val isNightModeEnabled: Boolean = context.isNightModeEnabled // or application.isNightModeEnabled
val isNetworkAvailable: Boolean = context.isNetworkAvailable // or application.isNetworkAvailable
...
// Start most common activities
context.startApplicationSystemSettingsActivity()
context.startYouTubeActivity("Rqfufnlq_KU")
context.startWebBrowserActivity("https://github.com/")
context.startGooglePlayActivity("com.google.android.keep")
...
// Soft Keyboard
context.showKeyboard(view)
context.toggleKeyboard()
context.hideKeyboard(view)
// Toasts
context.showShortToast(R.string.test)
context.showLongToast(R.string.test)
and much more! Please visit this link for all available common extensions:
https://github.com/Two-Coders/android-kotlin-extensions/tree/master/extensions/common/src/main/java/com/twocoders/extensions/common
This library contains some useful Android Activity extensions.
Use the library by adding implementation "com.twocoders.extensions:activity:1.0.0"
into your build.gradle file.
Only Activity specific extensions:
// Data-binding layout binding
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindLayout(R.layout.my_activity)
}
}
// Immersive Mode
class MyActivity : AppCompatActivity() {
private val viewModel by viewModels<MyActivityViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
with(viewModel) {
enterImmersiveModeEvent.observe(this@MyActivity) { enterImmersiveMode() }
exitImmersiveModeEvent.observe(this@MyActivity) { exitImmersiveMode() }
}
}
}
and of course all Context extensions as well ;) Please visit this link for all available activity extensions:
https://github.com/Two-Coders/android-kotlin-extensions/tree/master/extensions/activity/src/main/java/com/twocoders/extensions/activity
This library contains some useful Android Fragment extensions.
Use the library by adding implementation "com.twocoders.extensions:fragment:1.0.0"
into your build.gradle file.
Fragment extensions are mostly only wrapped an Activity and Context extensions:
class MyFragment : Fragment() {
private val viewModel by viewModels<MyFragmentViewModel>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(viewModel) {
startGooglePlayActivityObservable.observe(viewLifecycleOwner) {
startGooglePlayActivity()
}
startAppSysSettingsActivityObservable.observe(viewLifecycleOwner) {
startApplicationSystemSettingsActivity()
}
}
}
}
Permissions (Multiple Permissions) Launcher:
class MyFragment : Fragment() {
private val viewModel by viewModels<MyFragmentViewModel>()
private lateinit var requestPermissionLauncher: ActivityResultLauncher<Array<String>>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestPermissionLauncher = registerMultiplePermissionsLauncher {
viewModel.onPermissionResult(it, requireActivity())
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(viewModel) {
requestPermissionsObservable.observe(viewLifecycleOwner) { requestPermissionLauncher.launch(it) }
}
}
}
and of course all Activity and Context extensions as well ;) Please visit this link for all available fragment extensions:
https://github.com/Two-Coders/android-kotlin-extensions/tree/master/extensions/fragment/src/main/java/com/twocoders/extensions/fragment
This library contains some useful Android Navigation extensions.
Use the library by adding implementation "com.twocoders.extensions:navigation:1.0.2"
into your build.gradle file.
Obtaining NavController:
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = bindLayout(R.layout.layout_activity_main)
val navController = navControllerFrom(R.id.navHostFragment)
binding.bottomNavigationView.setupWithNavController(navController)
}
}
This library contains some useful Android Lifecycle Runtime extensions.
Use the library by adding implementation "com.twocoders.extensions:lifecycle-runtime:1.0.1"
into your build.gradle file.
LifecycleOwner:
// Obtaining Activity from LifecycleOwner
val activity = lifecycleOwner.activity()
// Check if an Fragment or Activity is in finishing state
val isFinishing: Boolean = lifecycleOwner.isFinishing()
This library contains some useful Android Lifecycle LiveData extensions.
Use the library by adding implementation "com.twocoders.extensions:lifecycle-livedata:1.1.1"
into your build.gradle file.
This library adds some useful extensions to LiveData and Hadilq LiveEvent:
@HiltViewModel
class MyFragmentViewModel @Inject constructor(
application: Application
) : AndroidViewModel(application) {
val goToSettingsObservable: LiveData<Any> = LiveEvent()
val requestPermissionsObservable: LiveData<Array<String>> = LiveEvent()
private fun requestStoragePermission() {
if (!isStoragePermissionGranted) {
val permissions = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
requestPermissionsObservable.asLiveEvent().value = permissions
}
}
fun onSettingsButtonClick() {
goToSettingsObservable.asLiveEvent().call()
}
}
MutableLiveData access restriction:
@HiltViewModel
class MyFragmentViewModel @Inject constructor(
application: Application
) : AndroidViewModel(application) {
val viewAnimatorIndex: LiveData<MainFragmentContentIndex> = MutableLiveData(MainFragmentContentIndex.CONTENT)
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
if (!isStoragePermissionGranted) {
viewAnimatorIndex.asMutable().value = MainFragmentContentIndex.NO_PERMISSION
} else {
switchToContent()
}
}
}
Transformations:
@HiltViewModel
class MyFragmentViewModel @Inject constructor(
application: Application
) : AndroidViewModel(application) {
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
val firstLiveData: LiveData<Int> = MutableLiveData(0)
val secondLiveData: LiveData<String> = MutableLiveData(EMPTY_STRING)
firstLiveData
.withLatestFrom(secondLiveData) // Rx withLatestFrom transformation
.observe(owner) {
// it is Pair<Int, String>
}
firstLiveData
.zip(secondLiveData) // Rx zip transformation
.observe(owner) {
// it is Pair<Int, String>
}
firstLiveData
.combineLatest(secondLiveData) // Rx combineLatest transformation
.filter { it.first >= 5 } // filter example
.observe(owner) {
// it is Pair<Int, String>
}
...
}
}
and much more! Please visit this link for all available LiveData extensions:
https://github.com/Two-Coders/android-kotlin-extensions/tree/master/extensions/lifecycle-livedata/src/main/java/com/twocoders/extensions/lifecycle/livedata
This library contains some useful Android Lifecycle LiveData Preference extensions.
Use the library by adding implementation "com.twocoders.extensions:lifecycle-livedata-preference:1.0.1"
into your build.gradle file.
@HiltViewModel
class MyViewModel @Inject constructor(
application: Application,
preferences: SharedPreferences
) : AndroidViewModel(application) {
private val preferences = PreferenceManager.getDefaultSharedPreferences(app)
private val booleanPreferenceLiveData = preferences.liveData("pref-key-boolean", false)
private val stringPreferenceLiveData = preferences.liveData("pref-key-string", EMPTY_STRING)
private val enumPreferenceLiveData = preferences.liveData("pref-key-enum", Fruit.APPLE)
init {
logd("Boolean preference value is: ${booleanPreferenceLiveData.value}")
logd("String preference value is: ${stringPreferenceLiveData.value}")
logd("Enum preference value is: ${enumPreferenceLiveData.value}")
}
fun onSomethingHappened() {
booleanPreferenceLiveData.value = true
stringPreferenceLiveData.value = "test"
enumPreferenceLiveData.value = Fruit.BANANA
}
}
This library contains some useful Android Lifecycle ViewModel extensions.
Use the library by adding implementation "com.twocoders.extensions:lifecycle-viewmodel:1.0.1"
into your build.gradle file.
This library mostly wrap the common Application extensions:
@HiltViewModel
class MyViewModel @Inject constructor(
application: Application
) : AndroidViewModel(application) {
init {
...
if (hasWifi) { /*true logic here*/ } else { /*false logic here*/ }
if (isNightModeEnabled) { /*true logic here*/ } else { /*false logic here*/ }
if (batteryManager.isCharging) { /*true logic here*/ } else { /*false logic here*/ }
if (checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) { /*true logic here*/ } else { /*false logic here*/ }
val internalPrivateDirPath = internalPrivateDir.absolutePath
...
}
}
and much more! Please visit this link for all available ViewModel extensions:
https://github.com/Two-Coders/android-kotlin-extensions/tree/master/extensions/lifecycle-viewmodel/src/main/java/com/twocoders/extensions/lifecycle/viewmodel
This library contains some useful Android Lifecycle ViewModel SavedState extensions.
Use the library by adding implementation "com.twocoders.extensions:lifecycle-viewmodel-savedstate:1.0.0"
into your build.gradle file.
@HiltViewModel
class MyViewModel @Inject constructor(
application: Application,
savedStateHandle: SavedStateHandle
) : AndroidViewModel(application) {
private val mySafeArg: MySafeArg = savedStateHandle.request("mySafeArg")
...
}
This library contains some useful Android Material extensions.
Use the library by adding implementation "com.twocoders.extensions:material:1.0.1"
into your build.gradle file.
MaterialAlertDialog:
class MyFragment : Fragment() {
private val viewModel by viewModels<MyFragmentViewModel>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(viewModel) {
showMaterialAlertDialogObservable.observe(viewLifecycleOwner) {
showMaterialAlertDialog(it.dialogComponent, buttonClickListener = alertDialogButtonListener)
}
}
}
}
BottomSheetDialogFragment Behavior:
class MyBottomSheetDialogFragment : BottomSheetDialogFragment() {
private val viewModel by viewModels<MyBottomSheetDialogFragmentViewModel>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(viewModel) {
setBottomSheetBehaviorObservable.observe(viewLifecycleOwner) { behavior?.state = it }
}
}
}
This library contains some useful Android RecyclerView extensions.
Use the library by adding implementation "com.twocoders.extensions:recyclerview:1.0.0"
into your build.gradle file.
ExtendedRecyclerView automatically removes the assigned Adapter in the onDetachedFromWindow:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="myFragmentViewModel"
type="com.sample.app.vm.MyFragmentViewModel" />
</data>
<com.twocoders.extensions.recyclerview.ExtendedRecyclerView
android:id="@+id/myRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
...
app:adapter="@{myFragmentViewModel.adapter}"
... />
</layout>
SpanCount extension and BindingAdapter:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="myFragmentViewModel"
type="com.sample.app.vm.MyFragmentViewModel" />
</data>
<com.twocoders.extensions.recyclerview.ExtendedRecyclerView
android:id="@+id/myRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
...
app:spanCount="@{myFragmentViewModel.spanCount}"
tools:spanCount="3"
... />
</layout>