Kotlin Extension functions to split big classes - android

Recently at my company a debate started after reviewing a different approach for writing heavy duty classes.
A big Java class holding component specific logic (no standard OOP principles made sense) had to be rewritten in Kotlin. The solution provided was splitting the logic in categories and the categories into separate files with internal extension functions to the main class.
Example:
Main.kt
class BigClass {
// internal fields exposed to the extension functions in different files
// Some main logic here
}
BusinessLogic.kt
internal fun BigClass.handleBussinessCase() {
// Complex business logic handled here accessing the exposed internal fields from BigClass
}
What are your thoughts on this? I haven't seen it used anywhere maybe for a good reason, but the alternative of thousand lines classes seems worse.

You have to consider that an extension function is nothing more than a function with an implicit first parameter which is referenced with this.
So in your case you'd have something like:
internal fun handleBussinessCase(ref: BigClass)
which would translate to Java as:
static void handleBussinessCase(BigClass ref)
But this could be assumed to be a delegate pattern, which could be encapsulated much cleaner in Kotlin as well.
Since the properties have to be internal anyhow, you could just inject these as a data class into smaller use-cases. If you define an interface around these (which would make the properties public though), you could create a delegate pattern with it and still reference each property with this in your implementation.

Here are some thoughts on making extension functions for the class:
It will be a utility function that will operate with the object you're extending, it will not be an object function, meaning that it will have access to only public methods and properties;
If you're planning to use class that being extended in unit tests, these methods (extensions) will be harder to mock;
Most likely they wont behave as you expect when used with inherited objects.
Maybe I missed something, so please read more about extensions here.

Related

MVVM Architecture Android

I have one Activity and i have created one View-model for it. I have created different classes like
UiUtil( show, hide view, hide key board ), Network layer , Data Base layer, AppUtil( for common functionality like Collection check, String validation, Date Conversion etc)
My question is, In MVVM design pattern is Activity can use these utility classes directly or it needs to use these classes via View-model, if it via view model then in the view-model i have to write a method that just call utility classes method . like below TimeDateManager is utility class used in view-model
class HomeViewModel: BaseViewModel()
{
fun prepareTimeAmPmToDisplay(context: Context, alarm: Alarm): String
{
return TimeDateManager.prepareTimeAmPmToDisplay(context, alarm)
}
}
Architectures are not obligatory, they are recommendational, thus you can change their usage in quite wide range. The only stopper should be a common sense(if it is present of course).
In this particular case the usage of utility class inside an Activity maybe ok, based on your ViewModel construction and its way of communication with View(read Activity).
For example if you have some LiveData that sends some kind of event(for ex. data loaded from backend or alarm trigger) inside your ViewModel and your View listens to it, I think it is ok to use util classes inside an Observer in Activity. Especially if this utils method doesn't depend on any ViewModel or Repository data. The direct utils usage in Activity is not limited by this usecase, though - there are plenty of others.
I understand that this may be an unpopular opinion in modern time of "clean approach" but I believe that this "clean approach" sometimes complicates stuff where it shouldn't, thus if mixing things a bit does not brake overall architecture but rather makes some thing more readable and easy to maintain - I would go for it.
Hope it helps.
My approach toward MVVM is simple, ViewModel is responsible for business logic, dealing with repositories (Network, Database, etc.) and all of the non-UI codes preparing the required data for UI, just like the documentation:
A ViewModel object provides the data for a specific UI component, such as a fragment or activity, and contains data-handling business logic to communicate with the model. For example, the ViewModel can call other components to load the data, and it can forward user requests to modify the data. The ViewModel doesn't know about UI components, so it isn't affected by configuration changes, such as recreating an activity when rotating the device.
On the other hand, ViewModels should not store a context (ApplicationContext is exceptional) and it's preferred that they do not use android APIs at all, so they become more testable (especially in the case on pure unit tests).
Also we are recommended to make use of LiveData in ViewModels and the UI has to observe the LiveData. For example, in onCreate of your Activity, you will call loadMainContent() method from VM, it calls getMainContent(page=1) from repository, and the repository will decide to load data from DB or network, and the result will be set on a LiveData were the View is listening for changes.
TL;DR
Sometimes it's even better to call these utilities from View rather than the VM. I'm pretty sure about your UiUtil also I think TimeDateManager is more view related rather than logic related. In addition, Network and DB layers are more efficient if called through a repository (which is responsible for caching, etc.) and VM can use that repo.

Do we really need to avoid constructors with default values for Fragments and Activites in Kotlin?

I am great fan of Kotlin and how it allows us to write better code. One of the best features is interface implementation delegation which looks like this:
class A(val someObject:SomeInterface) : SomeInterface by someObject
someObject has to be singleton (object), has to be created using constructor after keyword by (but then you cannot reference to it, or maybe someone has idea how to do it?) or has to be provided in constructor.
In Android messy and bad world we are discouraged to use constructors in fragments and activites due to configuration changes. But how about this:
class MyFragment(val someObject:SomeInterface = SomeObjectImpl()):Fragment,SomeInterface by someObject
I tried to change configuration and event I allowed system to kill my appliction and still, everything is looking ok, my object is creating again and again with my fragment. Is this valid, or am I missing something?
Happy Kotlin everyone!
This is valid. The reason you're discouraged from overloading fragment constructors is that Android can recreate them, and it will use the default one: MyFragment()
But the way Kotlin implements default parameter values behind the scenes is by creating additional constructors. You can decompile your class and see it contains two constructors now, one receiving someObject, and another empty.
From the JVM perspective the empty constructor would look like this:
public A() {
this(new SomeObjectImpl());
}
Calling it will populate your fragment with new instances of implemented classes.

Kotlin - can i use an extension for method overloading?

I have created a custom view in android. one of the methods has a signature like this:
fun show(CategoryFilterModel model) {/*...*/}
and it works fine. and now i'd like to create a overloaded function which would look like this if i did it by adding it to the custom view class:
fun show(ShopFilterModel model) {/*...*/}
Notice the type is different so this is a method overload.
a thought came to me that i could instead use an extension in kotlin to add another method to the class.
so it would like something like this:
fun MyCustomView.show(ShopFilterModel: model){
}
is this advised or should i only add utility methods with extensions ? Are there any overheads ?
It’s not only for utilities, as you can read in this great answer, which lists pretty much all use cases.
Imho, if you have control over that class you want to extend with a method, there’s no problem to add the method directly to it as opposed to doing it with an extension method. Yet, technically you can consider doing this. Please be aware that calling such an extension function from Java isn’t very idiomatic because it will be compiled to a static function. If it’s ever going to be invoked from Java, I’d rather use ordinary methods when possible.

strings.xml on MVPand clean architecture

I'm developing an android app implementing MVP and clean architecture. I have the following scenario:
One core module with presenters and view interfaces,...
One domain module with repositories, data sources,..
App module with the core implementation (so the Fragment/Activities).
Currently the strings.xml file is in the app module, but I'm thinking whether it should be in a commons module or not. The problem is that, sometimes, the presenter must set the text to the view, so the presenter should need to access to the strings.xml. I've thought in two possible solutions:
1) Create a TextHelper interface on core module that will be implemented on the app module and injected to the presenter, so the presenter will use this helper to get the strings it requires. (This is the solution I have implemented).
2) Move the strings.xml file to a common module so the file can be accessed from core module. But this solution would have a problem: the presenter doesn't have a context.
What do you think? What is the best approach?
Thanks in advance
If your view has nested if/elses related to strings, then they should probably be unit-tested. Therefore, that logic should stay in presenters or use-cases, where can be tested more quickly.
Your question is about how to retrieve the actual strings, given that they reside in the "outer layers" of the Clean Architecture scheme, i.e. in the Context object. IMHO your TextHelper is the right approach, as it allows to inject a mock when writing unit tests: you're interested in how the strings are processed, rather than how the strings actually look. I'm trying a very similar approach and calling it StringsRepository.
A point of uncertainty is how the the repository API should look like:
A single method like getString(#StringRes int stringResId, Object... formatArgs) that simply wraps Context.getString(): very simple to implement, but will make the presenters depend on your R.string class, which in turns requires strings.xml to be in the same module as your code under test;
One method per string with optional arguments, each one containing the reference to the appropriate string ID. This solution allows for best abstraction, but may become big (both the interface and the implementation...) and many domain classes may depend upon it. Handle with care.
Like (2), but with several classes, one per each part of your app. Each class may have a base class similar to (1) but with that method with protected visibility.
The best options for your case would be (2) or (3), but your mileage may vary.
You can use Application class to get the context any where from the app.
public class MVPApplication extends Application {
private static Context context;
public static Context getContext() {
return context;
}
#Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
}

What does the annotations do exactly in Android at compile time?

#SuppressWarnings("unsued")
#Override
#SuppressLint({ "InflateParams", "SimpleDateFormat" })
I don't get why we need to declare annotations.
We want to facilitate the writing and the maintenance of Android applications.
We believe that simple code with clear intents is the best way to achieve those goals.
Robert C. Martin wrote:
The ratio of time spent reading [code] versus writing is well over 10 to 1 [therefore] making it easy to read makes it easier to write.
While we all enjoy developing Android applications, we often wonder: Why do we always need to write the same code over and over? Why are our apps harder and harder to maintain? Context and Activity god objects, complexity of juggling with threads, hard to discover API, loads of anonymous listener classes, tons of unneeded casts... can't we improve that?
How?
Using Java annotations, developers can show their intent and let AndroidAnnotations generate the plumbing code at compile time.
Features
Dependency injection: inject views, extras, system services, resources, ...
Simplified threading model: annotate your methods so that they execute on the UI thread or on a background thread.
Event binding: annotate methods to handle events on views, no more ugly anonymous listener classes!
REST client: create a client interface, AndroidAnnotations generates the implementation.
No magic: As AndroidAnnotations generate subclasses at compile time, you can check the code to see how it works.
AndroidAnnotations provide those good things and even more for less than 50kb, without any runtime perf impact!
Is your Android code easy to write, read, and maintain?
Look at that:
#EActivity(R.layout.translate) // Sets content view to R.layout.translate
public class TranslateActivity extends Activity {
#ViewById // Injects R.id.textInput
EditText textInput;
#ViewById(R.id.myTextView) // Injects R.id.myTextView
TextView result;
#AnimationRes // Injects android.R.anim.fade_in
Animation fadeIn;
#Click // When R.id.doTranslate button is clicked
void doTranslate() {
translateInBackground(textInput.getText().toString());
}
#Background // Executed in a background thread
void translateInBackground(String textToTranslate) {
String translatedText = callGoogleTranslate(textToTranslate);
showResult(translatedText);
}
#UiThread // Executed in the ui thread
void showResult(String translatedText) {
result.setText(translatedText);
result.startAnimation(fadeIn);
}
// [...]
}
Java annotations bind specific conditions to be satisfied with code. Consider a scenario where we think we are overriding a method from anther class and we implemented code that (we think) is overriding the method. But if we somehow missed to exactly override one (e.g. we misspelled name. In superclass it was "mMethodOverridden" and we typed "mMethodoverridden"). The method will still compile and execute but it will not be doing what it should do.
So #Override is our way of telling Java to let us know if we are doing right thing. If we annotate a method with #override and it is not overriding anything, compiler will give us an error.
Other annotations work in a very similar way.
For more information, read docs Lesson: annotations
Annotations are basically syntactic metadata that can be added to Java source code.Classes, methods, variables, parameters and packages may be annotated .
Metadata is data about data
Why Were Annotations Introduced?
Prior to annotation (and even after) XML were extensively used for metadata and somehow a particular set of Application Developers and Architects thought XML maintenance was getting troublesome. They wanted something which could be coupled closely with code instead of XML which is very loosely coupled (in some cases almost separate) from code. If you google “XML vs. annotations”, you will find a lot of interesting debates. Interesting point is XML configurations were introduced to separate configuration from code. Last two statements might create a doubt in your mind that these two are creating a cycle, but both have their pros and cons.
For eg:
#Override
It instructs the compiler to check parent classes for matching methods.

Categories

Resources