www.rajendhiraneasu.in Open in urlscan Pro
2607:f8b0:4006:816::2013  Public Scan

Submitted URL: http://rajendhiraneasu.in/
Effective URL: https://www.rajendhiraneasu.in/
Submission: On November 15 via api from US — Scanned from US

Form analysis 1 forms found in the DOM

Name: contact-form

<form name="contact-form">
  <p></p> Name <br>
  <input class="contact-form-name" id="ContactForm1_contact-form-name" name="name" size="30" type="text" value="">
  <p></p> Email <span style="font-weight: bolder;">*</span>
  <br>
  <input class="contact-form-email" id="ContactForm1_contact-form-email" name="email" size="30" type="text" value="">
  <p></p> Message <span style="font-weight: bolder;">*</span>
  <br>
  <textarea class="contact-form-email-message" cols="25" id="ContactForm1_contact-form-email-message" name="email-message" rows="5"></textarea>
  <p></p>
  <input class="contact-form-button contact-form-button-submit" id="ContactForm1_contact-form-submit" type="button" value="Send">
  <p></p>
  <div style="text-align: center; max-width: 222px; width: 100%">
    <p class="contact-form-error-message" id="ContactForm1_contact-form-error-message"></p>
    <p class="contact-form-success-message" id="ContactForm1_contact-form-success-message"></p>
  </div>
</form>

Text Content

RAJENDHIRAN EASU - #TECHFREAK







SUNDAY, 21 AUGUST 2022


JETPACK COMPOSE UI – STATEFUL, STATELESS AND STATE HOISTING




















Jetpack Compose is a declarative approach of design and code, where as the
typical imperative programming era moving to parallel universe of declarative
programming.  Here on this process, it gives more impact on the UX and it
rendering process, so it closely works on the single changes that would have to
be repaint i.e. re-construct the UI as fully or partially whichever the use case
demands.  So, the changes would be caught and works with UI States and these are
works on the parameters of events and observers.  Here we going to see where and
how the state works in our android app. 




Before we go into these details of Stateful and Stateless, we have to understand
fewer things which connects the State and Composables. 




State on Composition & Re-Composition:  Compose is declarative one and through
it will also calling the same composable with the new arguments on demand of
changes, the arguments are the real representatives of this UI state. It would
be anything the updates made on the state, the recomposition of UI will take
place. 




For Example, things like TextField, Checkbox, and Option etc... As like as
imperative programming (XML layout views) these widgets won’t automatically
update while on selecting/toggling in compose. Here in a composable we have to
explicitly tell the new state as value changed in order update. 




How the State Drive On: Composable functions can use the remember APIs to store
an object in memory. A value computed by remember is stored in the Composition
during initial composition, and the stored value is returned during
recomposition. remember can be used to store both mutable and immutable objects,
these objects are defined with mutableStateOf which is an observable type
integrated with the compose runtime.




Now coming to our discussion point, how and what would be the Stateful and
Stateless Compose?




Here is the screenshot of the use case and code snippet for both Stateful and
Stateless compose will be as follows, 









Simple logic is in the initial screen click me is an action button it will keep
increase by 1 on each click, on the regular interval of every 5 count and the
ahead a step of 2, that text “I’m Visible between x to y” will be displayed and
this keeps on continuing. (Refer this branch for the full Source code)




Stateful: Stateful is when composable uses remember to store an object i.e.
create, holds and modifies its own State internally.  Stateful is useful when we
don’t need to control the State of a composable.  However, the weakness of
Stateful is that it tends to be less reusable and difficult to test.  




Here in the below code the state, ui and logic is completely packed into one
single compose function. 








Stateless:  Stateless composable is a composable that doesn't hold any state,
rather it only receive & hoist the state and this pattern is called State
hoisting.  State hoisting in Compose is a pattern of moving state to a
composable's caller to make a composable stateless.  Another thing by using this
State Hoisting approach, we can easily mock the parent method by using Mockito
and test our parent and child methods


Benefits of State Hoisting:
 * By Moving state instead of duplicating it, we’re ensuring there’s only one
   source of truth. This helps avoid bugs.
 * Only stateful composable will be able to modify their state. It’s completely
   internally encapsulated.
 * Hoisted states can be shared with multiple composable.
 * Only the callers to the stateless composable can decide to ignore or modify
   events before changing the state, easy to intercept

Here in the below code snippet, we have 3 compose functions (1 stateful and 2
stateless), maybe we can keep it as 2 compose, but I just wanted to make it
intentionally 3 because want to separate the UI into two different stateless and
passing state param and action as lambda param to the functions.





Statement from the official docs


“As we develop reusable Composables, we often want to expose both a Stateful and
a Stateless version of the same composable. The Stateful version is convenient
for callers that don’t care about the state, and the Stateless version is
necessary for callers that need to control or hoist the State.”


Above Code Ref Gist: Sateful, StateHoisting

Posted by Rajendhiran Easu at 02:02 No comments:
Email ThisBlogThis!Share to XShare to FacebookShare to Pinterest
Labels: Jetpack Compose UI – Stateful, Stateless and State Hoisting



SUNDAY, 3 JULY 2022


LIVEDATA & FLOW



As part of developing apps on android, it is quite important things is how
effectively and efficiently the UI can be updated on demand to the changes in
data at lower layers, decoupling those layers, handling callbacks. Separation of
these layers really helps on the testing part. (i.e. constructing the domain and
data layer independently).   Since the legacy android code i.e. code which is
written on imperative styles we would have writing lot of boilerplate code to
handle the data changes using AsyncTask, callbacks, handlers etc.  But now the
development has notably evolved and I would say much easier if one understands
the basics.  There are always multiple ways to perform a given task within
android and one can only decide the best alternative if the basic difference,
pros, and cons of all options are mastered.






Just Glimpses:




LiveData: LiveData is a lifecycle aware observable data holder (means it knows
the lifecycle of the activity or a fragment) use it when you play with UI
elements (views).




Flow: Flow (cold stream) – In general think of it like a stream of data flowing
in a pipe with both ends having a producer and consumer running on a coroutines.




StateFlow: (hot stream) does similar things like LiveData but it is made using
flow by kotlin guys and only difference compare to LiveData is it’s not
lifecycle aware but this is also been solved using repeatOnLifecycle api’s, so
whatever LiveData can do StateFlow can do much better with power of flow’s api.
StateFlow won’t emit same value.




SharedFlow: (hot stream) – name itself says it is shared, this flow can be
shared by multiple consumers, I mean if multiple collect calls happening on the
sharedflow there will be a single flow which will get shared across all the
consumers, unlike normal flow.




What are the above highlighted terms, let’s try to address here what are those
in details and that helps us to choose among LiveData, Flow, SharedFlow, and
StateFlow




LiveData:  Live data is part of Android Architecture Components.  




It is an Observable data class:  it can hold data and that data can be observed
from android components. Meaning it can be observed by other components — most
profoundly UI controllers (Activities/Fragments).  




It is Lifecycle aware—it sends updates to our components i.e. UI
(Activities/Fragments) only when our view is in the active state.

 

Pros

Cons

 * Would always get the latest data
 * Always check if the subscriber is active before publishing data.
 * No memory leaks
 * No crashes or unnecessary ANR
 * Configuration changes update

 * Lack of control over the execution context
 * Threading issue especially when used in Repositories
 * Not built on top of Coroutines and Kotlin
 * Lack of seamless data integration across between database and UI especially
   using Room.
 * Lots of Boiler Plate Codes especially while using Transformations

 








Flow:  Built on top of a coroutines, a flow emits multiple values sequentially. 
It’s a stream of data that can be computed sequentially.  Flow can handle
streams of values, and transform data in complex multi-threaded ways using
an intermediate operators to modify the stream without consuming values. (So
basically it’s an alternate to RxJava.)

 

Flows by nature are not lifecycle aware unlike LiveData. Which makes sense as
it’s not a part of android component but a type from Kotlin language. However,
this can be resolved by responsibly collecting flow values within
lifeCycleScopes via coroutines.

 

Flow is declarative/cold: It can only be executed on collection and there are
hot flows as well (SharedFlow and StateFlow).

 

COLD: Stops emission when any collector is not active. HOT: It remains in memory
as long as the flow is collected or as long as any other references to it exist
from a garbage collection root.

 

StateFlow:

 

 * State Flow is similar to normal flow but it holds the state. When you
   initialize the state flow you always need to tell the initial value of state
   flow. Hence state flow will have always a value.
 * State flow is Hot Flow because it starts emitting values even though there is
   no consumer and those data will be remains in the memory
 * State flow always has an initial value, replays one most recent value to new
   subscribers, does not buffer any more values, but keeps the last emitted one.
 * All methods of state flow are thread-safe and can be safely invoked from
   concurrent coroutines without external synchronization.
 * When you collect state flow through collect{} and if the consumer gets
   recreated due to configuration change it will re-call collect{}
 * You can convert Cold flow to state flow using stateIn () operator.

SharedFlow:

 * A SharedFlow is a highly-configurable generalization of StateFlow, that emits
   all value to all consumers in a broadcast fashion.
 * A shared flow keeps a specific number of the most recent values in its replay
   cache. Every new subscriber first gets the values from the replay cache and
   then gets new emitted values. The maximum size of the replay cache is
   specified when the shared flow is created by the replay parameter.
 * A default implementation of a shared flow that is created
   with MutableSharedFlow() constructor function without parameters has no
   replay cache nor additional buffer.
 * All methods of shared flow are thread-safe and can be safely invoked from
   concurrent coroutines without external synchronization.
 * When you collect shared flow through collect{} and if the consumer gets
   recreated due to configuration change it will not re-call collect{}
 * You can convert Cold flow to shared flow using shareIn () operator.

Extras….








StateFlow and LiveData have similarities: Both are observable data holder
classes, and both follow a similar pattern when used in your app architecture.

The StateFlow and LiveData do behave differently: StateFlow requires an initial
state to be passed into the constructor, while LiveData does not.




LiveData.observe() automatically unregisters the consumer when the view goes to
the STOPPED state, whereas collecting from a StateFlow or any other flow does
not stop collecting automatically. To achieve the same behavior,you need to
collect the flow from a Lifecycle.repeatOnLifecycle block.




StateFlow Vs. SharedFlow: The main difference between a SharedFlow and a
StateFlow is that a StateFlow takes a default value through the constructor and
emits it immediately when someone starts collecting, while a SharedFlow takes no
value and emits nothing by default.




Here we see the code snippet in the blog using LiveData, SharedFlow and
StateFlow used in ViewModel and that how it handles with the retrofit response
and updates the same to the Fragment.




Full Source Code Reference in Branch







updateView(..) in the Fragment (Code Snippet to update the UI View handle)






private fun updateView(res: Resource<Summary>) {
        when (res.status) {
            Status.LOADING -> {
                binding.progressBar.visibility = View.VISIBLE
            }
            Status.SUCCESS -> {
                binding.progressBar.visibility = View.GONE
                res.data?.let {
                    updateCards(it.global)
                    it.countries?.let {
                        statusAdapter.setData(it)
                    } ?: kotlin.run {
                        Toast.makeText(activity, "No Data Available " + res.msg, Toast.LENGTH_LONG)
                            .show()
                    }
                }
            }
            Status.ERROR -> {
                binding.progressBar.visibility = View.GONE
                Toast.makeText(
                    activity,
                    "Something went wrong... Please contact admin " + res.msg,
                    Toast.LENGTH_LONG
                ).show()
            }
        }
    }



LiveData: In ViewModel class:



private val _summaryLiveData = MutableLiveData(Resource.loading(Summary()))
val summaryLiveData = _summaryLiveData as LiveData<Resource<Summary>>

// LiveData Object gets updated

fun getCovidStatusLiveData() {
        viewModelScope.launch(Dispatchers.IO) {
            try {
                _summaryLiveData.postValue(Resource.loading(null))
                val summaryResponse =
                    APIClient.createService(tClass = CovidStatusAPI::class.java)
                        .getCountriesSummary()
                summaryResponse.takeIf { it.isSuccessful }?.let {
                    _summaryLiveData.postValue(Resource.success(it.body() as Summary))
                } ?: kotlin.run {
                    _summaryLiveData.postValue(Resource.error("Error", null))
                }
            } catch (e: Exception) {
                _summaryLiveData.postValue(Resource.error(e.message ?: "Err", null))
            }
        }
    }

// Using LiveData Scope (It uses emits)
fun getCovidStatusLiveDataScope() = liveData {
        try {
            emit(Resource.loading(null))
            val summaryResponse =
                APIClient.createService(tClass = CovidStatusAPI::class.java).getCountriesSummary()
            summaryResponse.takeIf { it.isSuccessful }?.let {
                emit(Resource.success(it.body() as Summary))
            } ?: kotlin.run {
                emit(Resource.error("Error", null))
            }
        } catch (e: Exception) {
            emit(Resource.error(e.message ?: "Err"))
        }
    }



In Fragment (LiveData observer):



// Observing the LiveData object of viewmodel 
viewModel.summaryLiveData.observe(viewLifecycleOwner) {
            updateView(it)
        }

// Observing the direct livedata scope function of viewmodel 
viewModel.getCovidStatusLiveDataScope().observe(viewLifecycleOwner){
            updateView(it)
        }



StateFlow & SharedFlow: In ViewModel class:



private val _summaryStateFlow = MutableStateFlow(Resource.loading(Summary()))
val summaryStateFlow = _summaryStateFlow as StateFlow<Resource<Summary>>

private val _summarySharedFlow = MutableSharedFlow<Resource<Summary>>()
val summarySharedFlow = _summarySharedFlow as SharedFlow<Resource<Summary>>

// Using SharedFlow
fun getCovidStatusSharedFlow() {
        viewModelScope.launch(Dispatchers.IO) {
            try {
                _summarySharedFlow.emit(Resource.loading(null))
                val summaryResponse =
                        APIClient.createService(tClass = CovidStatusAPI::class.java)
                                .getCountriesSummary()
                summaryResponse.takeIf { it.isSuccessful }?.let {
                    _summarySharedFlow.emit(Resource.success(it.body() as Summary))
                } ?: kotlin.run {
                    _summarySharedFlow.emit(Resource.error("Error", null))
                }
            } catch (e: Exception) {
                _summarySharedFlow.emit(Resource.error(e.message ?: "Err", null))
            }
        }
    }

// Using StateFlow
fun getCovidStatusStateFlow() {
        viewModelScope.launch(Dispatchers.IO) {
            try {
                _summaryStateFlow.emit(Resource.loading(null))
                val summaryResponse =
                        APIClient.createService(tClass = CovidStatusAPI::class.java)
                                .getCountriesSummary()
                summaryResponse.takeIf { it.isSuccessful }?.let {
                    _summaryStateFlow.emit(Resource.success(it.body() as Summary))
                } ?: kotlin.run {
                    _summaryStateFlow.emit(Resource.error("Error", null))
                }
            } catch (e: Exception) {
                _summaryStateFlow.value = Resource.error(e.message ?: "Err", null)
            }
        }
    }



In Fragment (Handling state and shared flow emitted values): Since we know Flows
by nature are not lifecycle aware, so it need to be handled like below.



// StateFlow to make it as lifecycle aware.
viewLifecycleOwner.lifecycleScope.launch {
             viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                 launch {
                     viewModel.summaryStateFlow
                         .collectLatest {
                             updateView(it)
                         }
                 }
             }
         }

// SharedFlow to make it as lifecycle aware.
viewLifecycleOwner.lifecycleScope.launch {
             viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                 launch {
                     viewModel.summarySharedFlow.collectLatest {
                         updateView(it)
                     }
                 }
             }
         }



But doing above for all stateflow or sharedflow object is tedious so we can
write one common inline function in Utils to make it as easy for the lifetime.



// This Take care of LifeCycle Aware
inline fun <T> Flow<T>.launchAndCollectIn(
    owner: LifecycleOwner,
    minState: Lifecycle.State = Lifecycle.State.STARTED,
    crossinline block: suspend CoroutineScope.(T) -> Unit
) {
    owner.lifecycleScope.launch {
        owner.repeatOnLifecycle(minState) {
            collect {
                block(it)
            }
        }
    }
}

viewModel.summarySharedFlow.launchAndCollectIn(viewLifecycleOwner) {
            updateView(it)
        }

viewModel.summaryStateFlow.launchAndCollectIn(viewLifecycleOwner) {
            updateView(it)
        }



Posted by Rajendhiran Easu at 01:10 No comments:
Email ThisBlogThis!Share to XShare to FacebookShare to Pinterest
Labels: LiveData || StateFlow || SharedFlow



SUNDAY, 12 JUNE 2022


KOTLIN DELEGATION



In object-oriented programming, delegation refers to evaluating a member
(property or method) of one object (the receiver) in the context of another
original object (the sender). 




Delegation is a design pattern in which an object handles a request by
delegating to a helper object, called the delegate. The delegate is responsible
for handling the request on behalf of the original object and making the results
available to the original object.  




Kotlin supports “delegation” design pattern by introducing a new keyword “by”.
Using this keyword or delegation methodology, Kotlin allows the derived class to
access all the implemented public methods of an interface through a specific
object




Delegation should be used when:



 * Any components that behave identically, but we realize were it will have some
   upgradation on top of it in future point of time where we do our own logical
   implementation and expose the results.  For E.g. We can take an example of
   Analytics class, where instead of directly using the analytics method we can
   have our delegation and use the param to handle the screen views and event
   logging.
 * Place where we feel delegate would be the better than inheritance because, it
   doesn’t force you to define all the methods of the super class, you can use
   or override only the methods that really needed.  For e.g. here you can refer
   the code below that PaymentProcess doesn’t enforced to override the method
   (Kotlin), but if really needed we can override and do our implementations.
 * If we want to extend the behavior of classes that we cannot or don’t want to
   subclass for the below reasons For E.g. here you can see in the below code
   snippet Payment classes (CashPayment, UPIPayment, CardPayment) are can’t be
   inherited.
    * Restricted to share or disallowed to create a hierarchy (Class marked as
      final)
    * Planning to expose the limited or different API methods by consuming the
      existing code functionality and also we may add our feature update. 
    * Planned to hide the serious implementation from the calling code.







Example: This will be very simple and self-explanatory code snippet, here we are
having an interface IPayment for the payment and it would track the mode of
payment happens, and there would be an implementation classes CashPayment,
UPIPayment, CardPayment of different mode of payment (Cash, Card and UPI). 
 There in PaymentProcess class the delegation will be happen through the
interface.  Also the method paymentProcess in java and processPayment in Kotlin
does the payment process.   


Comparatively with Java and Kotlin, In Kotlin we avoid lot of boilerplate code
because of delegation using “by”, else in java we are mandatory to do the
implementation of all interface method (see in this example I have used only one
interface method, so if it is more than, it would be more override method in
PaymentProcess.java class). 





Java Style of Delegate


This file contains bidirectional Unicode text that may be interpreted or
compiled differently than what appears below. To review, open the file in an
editor that reveals hidden Unicode characters. Learn more about bidirectional
Unicode characters
Show hidden characters

package java_comp; class PaymentProcessDelegation { public static void
main(String[] args) { new PaymentProcess(new CashPayment()).paymentMode();
System.out.println(new PaymentProcess(new CashPayment()).paymentProcess());
PaymentProcess.isUPIDown = true; System.out.println(new PaymentProcess(new
UPIPayment("Tez")).paymentProcess()); PaymentProcess.isUPIDown = false;
System.out.println(new PaymentProcess(new
UPIPayment("Paytm")).paymentProcess()); PaymentProcess.isCardDown = true;
System.out.println(new PaymentProcess(new CardPayment("HDFC",
"CC")).paymentProcess()); PaymentProcess.isCardDown = false;
System.out.println(new PaymentProcess(new CardPayment("Citi",
"DC")).paymentProcess()); } } interface IPayment { String paymentMode(); } final
class CashPayment implements IPayment { @Override public String paymentMode() {
return "Cash"; } } final class UPIPayment implements IPayment { String upiName;
public UPIPayment(String upiName) { this.upiName = upiName; } @Override public
String paymentMode() { return "UPI - " + upiName; } } final class CardPayment
implements IPayment { String providerName, cardType; CardPayment(String
providerName, String cardType) { this.providerName = providerName; this.cardType
= cardType; } @Override public String paymentMode() { return "Card - " +
providerName + "-" + cardType; } } class PaymentProcess implements IPayment {
public static final String PROCESSING_ERROR_MSG = "Sorry we can't process it for
now with "; public static final String ERROR_MSG = "Payment Option is
Unavailable"; public static final String PROCESSING_MSG = "Process Initiated for
"; public static Boolean isCardDown = false; public static Boolean isUPIDown =
false; private final IPayment payment; PaymentProcess(IPayment iPayment) {
payment = iPayment; } String paymentProcess() { if (payment != null) { String
paymentMode = paymentMode(); if (!(payment instanceof CashPayment) && (isUPIDown
|| isCardDown)) { return PROCESSING_ERROR_MSG + paymentMode; } else { return
PROCESSING_MSG + paymentMode; } } return ERROR_MSG; } @Override public String
paymentMode() { return payment.paymentMode(); } }

view raw PaymentProcessDelegation.java hosted with ❤ by GitHub



Kotlin Style of Delegate:


This file contains bidirectional Unicode text that may be interpreted or
compiled differently than what appears below. To review, open the file in an
editor that reveals hidden Unicode characters. Learn more about bidirectional
Unicode characters
Show hidden characters

package delegation fun main() {
println(PaymentProcess(CashPayment()).processPayment()) PaymentProcess.isUPIDown
= true println(PaymentProcess(UPIPayment("Tez")).processPayment())
PaymentProcess.isUPIDown = false
println(PaymentProcess(UPIPayment("Paytm")).processPayment())
PaymentProcess.isCardDown = true println(PaymentProcess(CardPayment("HDFC",
"CC")).processPayment()) PaymentProcess.isCardDown = false
println(PaymentProcess(CardPayment("Citi")).processPayment())
PaymentProcess(CashPayment()).paymentMode() } interface IPayment { fun
paymentMode(): String } class CashPayment : IPayment { override fun
paymentMode(): String { return "Cash" } } class UPIPayment(val upiName: String)
: IPayment { override fun paymentMode(): String { return "UPI - $upiName" } }
class CardPayment(val providerName: String, val cardType: String = "DC") :
IPayment { override fun paymentMode(): String { return
"Card-$providerName-$cardType" } } const val PROCESSING_ERROR_MSG = "Sorry we
can't process it for now with " const val PROCESSING_MSG = "Process Initiated
for " class PaymentProcess(private val iPayment: IPayment) : IPayment by
iPayment { companion object { var isCardDown: Boolean = false var isUPIDown:
Boolean = false } fun processPayment(): String { val paymentMode =
iPayment.paymentMode() return if (iPayment !is CashPayment && (isUPIDown ||
isCardDown)) { "$PROCESSING_ERROR_MSG $paymentMode" } else { "$PROCESSING_MSG
$paymentMode" } } }

view raw PaymentProcessDelegation.kt hosted with ❤ by GitHub

Happy Coding :-)

Posted by Rajendhiran Easu at 01:24 No comments:
Email ThisBlogThis!Share to XShare to FacebookShare to Pinterest
Labels: delegation, Kotlin Delegation



SUNDAY, 5 JUNE 2022


SAM - FUNCTIONAL INTERFACE









Almost we all of us have seen code like view.setOnClickListener { } or
view.setOnLongClickListener { } in Kotlin, and when you click on it to see the
source code it will show you the Java OnClickListener interface. Is it a kotlin
extension? How can we call our custom listener like this? Let’s see the answer
to all of these now.


This syntax is not an extension, it is SAM conversion, SAM stands for Single
Abstract Method interface and it’s called also Functional interface which is an
interface with only one non-default method (abstract method) and any number of
default methods (non-abstract methods), for examples In the JDK we have Runnable
class which has only one method called run and in Android SDK we have
OnClickListener, OnLongClickListener etc..


How can we create a custom functional interface?


In Kotlin starting from Version 1.4, we can declare a functional interface in
Kotlin, we need to use the fun modifier before to the interface keyword.

fun interface MyInterface {
    fun aMethod()
}

Creating a function with the functional interface as param



fun runMyInterface(fi : MyInterface) { ... }




We can pass MyInterface as an anonymous object 



runMyInterface(object : MyInterface {

    override fun aMethod() {

        println("Welcome to www.rajendhiraneasu.in")

    }

})

For functional interfaces, SAM conversion can be achieved through lambda
expressions, which makes the code more concise and more readable.  Using lambda
expressions can replace manually creating classes that implement functional
interfaces. Through SAM conversion, Kotlin can convert any lambda expression
whose signature matches the signature of a single abstract method of an
interface into an instance of a class that implements the interface.  Please see
the above anonymous reference with lambda expressions as below



runMyInterface ({ println("Welcome to www.rajendhiraneasu.in") })




Also, in Kotlin if your last parameter is functional interface you can move your
lambda out the brackets ()



runMyInterface {

    println("Welcome to www.rajendhiraneasu.in")

}




Now you can realize that setOnClickListener { } is just because this method
takes functional interface which is OnClickListener as a parameter.


Eg: Let’s see with the use case to get the Students Grade of different class
levels.
 

// Class Levels
const val PRIMARY_SCHOOL = 1
const val HIGH_SCHOOL = 2

// Data Class holds the student details
data class StudentMarks(val sName: String, val classLevel: Int, val sAvg: Double) {
    fun getStudentGrade(predicate: GradePredicate) = predicate.getGrade((sAvg))
}

// Functional interface (SAM)
fun interface GradePredicate {
    fun getGrade(avg: Double): String
} 

// Grade Predicate definition as lambda 
val primarySchoolGrade = GradePredicate {
    when {
        it > 90 -> "A+"
        it > 80 -> "A"
        it > 65 -> "B"
        it > 45 -> "C"
        it > 34 -> "D"
        else -> "F"
    }
}

val highSchoolGrade = GradePredicate {
    when {
        it > 80 -> "Very Good"
        it > 60 -> "Good"
        it > 34 -> "Fair"
        else -> "Fail"
    }
}

// Lambda expression to select the grade predicate based on the class level 
val gradeSel by lazy { { classLevel: Int -> if (classLevel == PRIMARY_SCHOOL) primarySchoolGrade else highSchoolGrade } }

fun main() {
 val studentList = listOf(
        StudentMarks("Ragavan", PRIMARY_SCHOOL, 92.79),
        StudentMarks("Rajeevan", PRIMARY_SCHOOL, 65.15),
        StudentMarks("Rajeevan", PRIMARY_SCHOOL, 52.23),
        StudentMarks("Arun", HIGH_SCHOOL, 83.21),
        StudentMarks("Harish", HIGH_SCHOOL, 63.56)
    )

    println("Name || Grade")
    studentList.forEach {
        println(
            "${it.sName} ||  ${
                it.getStudentGrade(gradeSel(it.classLevel))
            }"
        )
    }
}


 
Output:






Posted by Rajendhiran Easu at 02:18 No comments:
Email ThisBlogThis!Share to XShare to FacebookShare to Pinterest
Labels: SAM - Functional Interface



SUNDAY, 15 MAY 2022


KOTLIN ENUM CLASS VERSUS SEALED CLASS



 Enum Class: 



 * It helps to represent a constant set of possible options and values i.e.
   group of constants, 
 * This can be used when a variable can only accept value out of a small set of
   known values 
 * It will increases the compile-time checking and avoid errors from passing in
   invalid constants. 
 * Easy to document which values are valid to use and what it implies.

For example, enumeration defines as like as below 
Flags accounting ledger (DEBIT, CREDIT),
Factory outlet process, (CRUSHING, WINDING, DRYING)
A concrete set of payment mode (UPI, NEFT, IMPS, AEPS) 
Handling API request status (LOADING, SUCCESS, RETRY, FAILURE), etc.


It holds the value which are always specific to the item, this value is mutable
and static to the each items, this functionality is often used to attach some
constant values on each item through the constructor.


Kotlin enums have methods and their implementations are also specific to the
items, when we define them, enum class must have the abstract method, and each
item mandatory to override it.

enum class Flavours(val preparationTime: Long) {
    VANILLA(3000L) {
	  // Even I don’t have the discount, I need to be overrided
        override fun discount(amt: Double): String {
            return ""
        }
    },
    CHOCOLATE(5000L) {
        override fun discount(amt: Double): String {
            return "Discount is $amt"
        }
    },
    COOKIES_CREAM(1000L) {
        override fun discount(amt: Double): String {
            return "Discount is $amt"
        }
    };

    var brand: String = "Amul"
    abstract fun discount(amt: Double): String
}

val flav1 = Flavours.COOKIES_CREAM
flav1.brand = "Arun"
val flav2 = Flavours.COOKIES_CREAM

// changing the brand of flav2 but it affects flav1 too, because It is item specific
flav2.brand = "Ponlait"   

val flav3 = Flavours.CHOCOLATE
flav3.brand = "Vadilal"
    
println("${flav1.name} | ${flav1.brand} | ${flav1.discount(7.5)}")
println("${flav2.name} | ${flav2.brand} | ${flav2.discount(2.5)}")
println("${flav3.name} | ${flav3.brand} | ${flav3.discount(3.5)}")



Output:
COOKIES_CREAM | Ponlait | Discount is 7.5
COOKIES_CREAM | Ponlait | Discount is 2.5
CHOCOLATE | Vadilal | Discount is 3.5




Here in the above code snippet we are able to see the brand will be the value
which is specific to item (refer the comment and output value highlighted) and
discount function is mandatory to override on all the enum values.  


Therefore iterating over enum values is easy, and their
serialization/deserialization is simple and efficient (as they are generally
represented just by name) and automatically supported by most libraries for
serialization (like Gson, Jackson, Kotlin Serialization, etc.). They also have
ordinal, and automatically implemented toString, hashCode and equals. 


Sealed Class: 
 * It helps to represent constrained hierarchies in which an Object can only be
   of one of the given types.
 * This class can have a specific number of subclasses i.e. restricted subclass
   hierarchy and each can be handled through multiple instances, 
 * It is an abstract classes (no possibility to create an instance)

In case, if we are sharing our code as a compiled jar/aar file to our client
with the sealed class in it.  Our client can’t inherit or subclass our sealed
classes.


Code Snippet for Reference:



sealed class Flavours(val preparationTime: Long)

class Vanilla(preparationTime: Long) : Flavours(preparationTime) {
    fun getCreamType() {
        println("Inside Vanilla")
    }
}

class Chocolate(preparationTime: Long, val isDiscount: Double) : Flavours(preparationTime) {
    fun knowChocolateType() {
        println("Inside Chocolate")
    }
}

class CookieCream(preparationTime: Long, val isDiscount: Double, val isSmokey: Boolean) : Flavours(preparationTime) {
    fun getCookieType() {
        println("Inside Cookie")
    }
}

fun getMyFlavor(flavorType: Flavours) = when (flavorType) {
    is Chocolate -> {
        flavorType.knowChocolateType()
    }

    is CookieCream -> {
        flavorType.getCookieType()
    }

    is Vanilla -> {
        flavorType.getCreamType()
    }
} 

//While calling this function
getMyFlavor(Chocolate(3000L, 10.50))
getMyFlavor(CookieCream(3000L, 10.50, true))
getMyFlavor(Vanilla(3000L))



Output:
Inside Chocolate
Inside Cookie
Inside Vanilla



Other Uses Case – Code Snippet:



// Handling Ledger balance & API Response along with generics (Covariance)
sealed class LedgerExpenses<out D, out C>
class Expense<D>: LedgerExpenses <D, Nothing>()
class Incomes<C>: LedgerExpenses <Nothing, C>()

// Handling multiple Eye lense
sealed class EyeLense
object IndianLense(val manuf:String, val degree:Double): EyeLense ()
object CollaborationLense: EyeLense (val degree:Double): EyeLense ()
class CustomizedLense(val src: String, val owner:Owner): EyeLense ()

// Handling API Response along with generics (Covariance)
sealed class Response<out R>
class Success<R>(val value: R): Response<R>()
class Failure(val error: Throwable): Response<Nothing>()



Conclusion:







Similarities:
 * The set of values for an enum type is also restricted like the sealed class
   restricting the subclasses.
 * Enum and sealed class increase the compile-time checking by restricting the
   constants or types to be matched at compile-time instead of runtime check.



Differences:
 * Each enum constant exists only as a single instance, whereas a subclass of a
   sealed class can have multiple instances, each with its own state. The state
   of an object is stored in fields (Variables).



Final Touch…
 * Enum handles with concrete set of values, whereas sealed classes uses
   concrete set of classes. 
 * Enum have the methods values() and valueOf, so we can serialize and
   de-serialize the values. 
 * Enums have ordinal and we can hold constant data. 
 * Sealed classes can hold instance-specific hierarchy. 
 * Sealed class helps to define on our own custom set of objects and we can use
   them with the multiple instance.
 * Sealed class is packed and secured way of creating a hierarchy of defined
   instance and those definitions are restricted to inherit.  (It violates the
   Open Close Principle, but this required for such an use cases)


Posted by Rajendhiran Easu at 01:41 No comments:
Email ThisBlogThis!Share to XShare to FacebookShare to Pinterest
Labels: Kotlin Enum Class versus Sealed Class



SUNDAY, 24 APRIL 2022


ANDROID REGISTERFORACTIVITYRESULT





As a very fundamentals that we Android developer has learned, and it shows the
way for communicating between two components. The provided
startActivityForResult(..), onActivityForResut(..) was simple enough to
implement for many years, but now we are hard to accept the change, it would be
the evolution of language and its features which really helps to do the code in
concise way.  So, as per this we see some pitfalls on the earlier approach like





 * Difficult to search the caller function in our project, 
 * Tedious in getting and handles the results on the fragment, 
 * Chance of missing out the results when the component is recreated, 
 * Conflicts with the same request code, 
 * Handling self-permissions request etc.

Earlier Approach:







Now, with updates to androidx.activity:activity-ktx to 1.2.0. It has deprecated
startActivityForResult in favor of registerForActivityResult, notable thing is
this implementation avoids and taken care of the above mentioned issues. 
Notable thing is here we no need of permission request code, it will be taken
care automatically. 


Let’s see the new implementation on implicit and explicit calls with
registerForActivityResult, ActivityResultLauncher, ActivityResultContracts,
ActivityResultCallback.


The class registerForActivityResult helps to register with
ActivityResultContracts (which handles explicit or implicit calls) and other
param as the callback action as lambda blocks with (ActivityResultCallback) and
returns the launcher (ActivityResultLauncher) object, where we use the launch
(...) method with params.


New Approach:


Explicit Calls: We all know calling another activity or component and getting
result from there on finish on explicit intent calls.




In the above approach we are creating our explicit launcher which gets data on
the resultant callbacks, so this way it would be easy to define our multiple
launcher and those are handled independently.  Here the same approach can be
used on the Fragment as well.


Implicit Calls: The implicit calls which invoke the system contracts such as
take a Picture from camera gallery, accessing contacts, etc.  Please refer the
below link for all available ActivityResultContracts




Conclusion:  The approach towards registerForActivityResult is really clean &
concise, IMO below are the pros 
 * Improved code readability, here we no need to jump between onActivityResult()
   & startActivityForResult.
 * ActivityResultLauncher is returned by registerForActivityResult and this used
   to launch the components, the input parameter is clearly defined to get the
   desired results is the callback.
 * There is no Boilerplate code for requesting permission from the user.

Code Reference: Gist







Posted by Rajendhiran Easu at 02:27 No comments:
Email ThisBlogThis!Share to XShare to FacebookShare to Pinterest
Labels: ActivityResultCallback., ActivityResultContracts,
ActivityResultLauncher, Android registerForActivityResult,
registerForActivityResult



SATURDAY, 2 APRIL 2022


GET CONTEXT IN JETPACK COMPOSE



In Android Compose, you can get the context by using the LocalContext, but it
should be call'd from the composable function / scope.

val context = LocalContext.current



In the below code snippet we are retrieving the context and show a toast message
inside the composable.



@Composable
fun MyToastDisplay(name: String) {
    val ctx = LocalContext.current
    Column(
        Modifier
            .fillMaxHeight()
            .fillMaxWidth(), verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Hello $name", color = Color.Red,
            modifier = Modifier
                .background(Color.Green)
                .clickable {
                    Toast
                        .makeText(ctx, "Welcome to the Compose World", Toast.LENGTH_SHORT)
                        .show()
                })
    }
}



If you use the LocalContext.current directly inside the clickable function
results in the compilation error “@composable invocations can only happen from
the context of an @composable function”.





Since the LocalContext.current is composable, you can’t invoke it within the
non-composable function.  i.e. clickable function is not a composable function
and so can’t accept other composable functions. 


Alternatively, you can get the context outside the clickable function scope and
use, as shown in the above code snippet.





Happy Coding :-)




Posted by Rajendhiran Easu at 13:10 No comments:
Email ThisBlogThis!Share to XShare to FacebookShare to Pinterest
Labels: local context compose

Older Posts Home

Subscribe to: Posts (Atom)



BLOG ARCHIVE

 * ▼  2022 (11)
   * ▼  August (1)
     * Jetpack Compose UI – Stateful, Stateless and State...
   * ►  July (1)
   * ►  June (2)
   * ►  May (1)
   * ►  April (2)
   * ►  March (2)
   * ►  February (1)
   * ►  January (1)

 * ►  2021 (12)
   * ►  December (1)
   * ►  November (1)
   * ►  October (1)
   * ►  September (2)
   * ►  August (1)
   * ►  July (1)
   * ►  June (2)
   * ►  May (1)
   * ►  April (1)
   * ►  March (1)

 * ►  2020 (5)
   * ►  December (1)
   * ►  May (1)
   * ►  April (2)
   * ►  January (1)

 * ►  2019 (5)
   * ►  September (1)
   * ►  August (1)
   * ►  July (1)
   * ►  May (1)
   * ►  January (1)

 * ►  2018 (6)
   * ►  December (1)
   * ►  September (1)
   * ►  July (1)
   * ►  March (1)
   * ►  January (2)

 * ►  2017 (20)
   * ►  December (1)
   * ►  November (1)
   * ►  October (1)
   * ►  September (1)
   * ►  August (2)
   * ►  July (1)
   * ►  June (3)
   * ►  May (3)
   * ►  April (2)
   * ►  March (2)
   * ►  February (2)
   * ►  January (1)

 * ►  2016 (24)
   * ►  December (2)
   * ►  November (2)
   * ►  October (1)
   * ►  September (2)
   * ►  August (4)
   * ►  July (1)
   * ►  June (2)
   * ►  May (2)
   * ►  April (2)
   * ►  March (2)
   * ►  February (2)
   * ►  January (2)

 * ►  2015 (10)
   * ►  October (1)
   * ►  September (1)
   * ►  August (1)
   * ►  June (1)
   * ►  May (2)
   * ►  February (2)
   * ►  January (2)




TOTAL PAGEVIEWS

022124232320431522638734873916109511511255134814221536162617581822192820432134223423724302528264027272834296



121475



FOLLOWERS




CONTACT FORM



Name




Email *




Message *












rajendhiraneasu.in. Awesome Inc. theme. Theme images by mammamaart. Powered by
Blogger.