📜 ⬆️ ⬇️

Early bury java

image

Much has been said about the "beauty" of Java code, but in my opinion, the main thing is not a tool, but the ability to use it. Under the cut an attempt to write a declarative DSL for layout for Android without even inventing a new programming language !

Java layout has always been associated with pain.

float dp = getResources().getDisplayMetrics().density; FrameLayout root = new FrameLayout(this); root.setBackgroundColor(RED); root.setLayoutParams( new ViewGroup.LayoutParams( MATCH_PARENT, (int)(100f*dp))); FrameLayout child = new FrameLayout(this); child.setBackgroundColor(GREEN); FrameLayout.LayoutParams childParams = new FrameLayout.LayoutParams( (int)(50f*dp), (int)(50f*dp)); childParams.gravity = CENTER; child.setLayoutParams(childParams); root.addView(child); 

Result:
')


And the point is not that the code looks scary (and it is scary as hell). The main problem is that it is impossible not to be mistaken. I passed this code 3 times here, for the first and second times naively believing that I could write everything correctly at once, and carefully rechecking everything only for the third. You will say that the matter of my carelessness will be right, but if even in such a simple layout you can mess up, then what can we say about something more complicated?

But why is everything so sad with the Java layout? In my opinion, the main reason is the ability to typeset in xml and the lack of a tool for Java layout.

Cons xml


For me there are 3 of them.

The first is an overhead projector.
Why waste the resources of already not very powerful Android devices for operations such as inflate and findViewById? A lot of time and effort was spent on optimization of these operations, but they did not become free from this.

The second is cumbersome.

 <FrameLayout android:background="#f00" android:layout_width="match_parent" android:layout_height="100dp"> <FrameLayout android:background="#0f0" android:layout_gravity="center" android:layout_width="50dp" android:layout_height="50dp"/> </FrameLayout> 


It depresses the need to duplicate tags, write before each attribute "android:", and then work out partial blindness to read this code.

The third is the limitations of the language.
Suppose I want to make a signature to the avtar 10dp more than the avatar itself.

 <ImageView android:layout_width="@dimen/avatarSide" android:layout_height="@dimen/avatarSide"/> <TextView android:layout_width="@dimen/avatarSide + 10dp" android:layout_height="wrap_content"/> 


But this can not be done because xml does not support expressions.

Why not Anko?


Anko is a DSL with which you can declaratively describe markup on Kotlin.

 frameLayout { backgroundColor = RED frameLayout { backgroundColor = GREEN }.lparams(dip(50), dip(50)) { gravity = CENTER } }.lparams(matchParent, dip(100)) 

We get all the features of a full-fledged programming language, better performance and do not even suffer from the layout of the interface in Java!

Everything is fine, but, in my opinion, it is indecent to pull a whole runtime of the language behind while developing libraries. 500 kb is not so much for the final application, but for the library it’s obviously overkill.

Janko


As it turned out, there is enough Java capability to declare it.

 new frameLayout(this) {{ new lparams(this) {{ width = MATCH_PARENT; height = dip(100); }}._(); backgroundColor = RED; new frameLayout(this) {{ new lparams(this) {{ width = dip(50); height = dip(50); gravity = CENTER; }}._(); backgroundColor = GREEN; }}._(); }}._(); 

The language supports unnamed code blocks. They are executed before the class constructor immediately after the parent class constructor.

 class A { // block { // some code } } 

I used this Java opportunity not to write the name of the variable in which the widget lies to change each of its properties.

Example with avatar and signature.

 new imageView(this) {{ new lparams(this) {{ width = dimen(R.dimen.avatarSide); height = dimen(R.dimen.avatarSide); }}._(); }}._(); new textView(this) {{ new lparams(this) {{ width = dimen(R.dimen.avatarSide) + dip(10); height = WRAP_CONTENT; }}._(); }}._(); 

Looks a little weird.



It looks like a man in a monocle and an operator on scala. But for the proof of concept - enough.

Results


0). On Kotlin, the code looks like this:

 object : frameLayout(this) { init { object : lparams(this) { init { width = MATCH_PARENT height = dip(100f) } }.`_`() backgroundColor = RED object : frameLayout(this) { init { object : lparams(this) { init { width = dip(50f) height = dip(50f) gravity = CENTER } }.`_`() backgroundColor = GREEN } }.`_`() } }.`_`() 

1) aar weight is 12kb
2) Idea does not knock formatting
3) Java code can sometimes be made unexpected for Java

Repository with library and examples
Benchmark

Usually a little faster than Anko, which is funny.

I expected my mini-library to become the last refuge of this monster, but even from there I sawed it in favor of Litho , which performs measurment and layout in another thread. Thank you eirnym for the link.

Source: https://habr.com/ru/post/331790/


All Articles