Simplifying the development of Android UI

Source: Internet
Author: User
Tags event listener

>
* Original link: Android UI development Made Easy
* Translator: Chaossss
* Reviewer: Zhaokaiqiang
* Status: Proofreading completed

If you think this article is too long and you haven't read it yet, I can give you a brief introduction to what the article is about: I use pure Java to provide a way of data binding

The code for Android UI development is often fragmented, and the code that is written is usually a lot of templating code, and there is no structure to say. Here are some questions (purely personal):

    • Android UI Development rarely conforms to the MVC pattern (or m-v-anything else).

    • XML files often contain a lot of duplicated code, which is bad for code reuse

    • XMLS is very fragile, which allows you to write an XML file, even if you enter Textveiw, the compiler will not warn you during the compilation, but will throw a inflateexception exception when the APP runs

    • Lack of support for styles, lack of support for variables, macros and calculations not supported (e.g. 10DP + 2px)

    • No data binding, which makes you have to put all the Findviewbyid and setOn yourself ... Listener, write it.

    • You can implement your layout through Java, but the code you write is like a heavenly book.

Using Mithril.js to establish a user interface

In WEB development, developers quickly realized that it was difficult to develop complex applications without MVx, which made them aware of the problems in JQuery and developed the backbone,knockout,angular,ember ... And so on, to improve their development efficiency.

But in Android, we're still using that little bit of function to set the View's properties in a haphazard way, just like in JQuery:

    $(‘.myview‘).text(‘Hello‘);    $(‘.myview‘).on(‘click‘, function() {    });    myView.setText("Hello");    myView.setOnClickListener(new View.OnClickListener() { ...});

We define our Layout in one directory, use them in another directory, and then change the code in the UI development
, it's not good.

React.js has a little impact on WEB development: they create a virtual DOM concept from a tree-relational custom object to show the actual HTML layout. Virtual tree creation and switching times are very short, so when the actual DOM needs to be rendered, the two virtual trees (the previous tree and the new tree) will be compared and only the mismatched parts will be rendered.

Mithril.js is a lean, short frame that allows the react.js to be more uncluttered. In Mithril, in addition to pure JavaScript, you can almost get rid of everything, at the same time, it also allows you to write the layout of the time to feel the full power of the Turing language.

    return m(‘div‘,             m(‘p‘, someText),             m(‘ul‘,               items.map((item) => m(‘li‘, item))),             m(‘button‘, {onclick: myClickHandler}));

So you can use loops to generate many View, you can change a part of the layout with a judgment statement, and finally you can bind the data and set up the event listener.

Can this method be used in Android?

Virtual layouts

A virtual layout (using the concept of a virtual DOM similar to the Web) is a tree-like collection of custom Java objects that are used to show the actual Android layout. Although the APP's data changes how many times, the tree will be built many times, but the layout changes should be only the inconsistent parts (the current layout and the pre-change layout).

Our framework only imports a static class, so static methods in all classes do not require the class name prefix to be used (for example, we only need to use V () instead of RENDER.V ()), which is the benefit of the language feature. Here's an example of how we create layouts:

    v(LinearLayout.class,        orientation(LinearLayout.VERTICAL),        v(TextView.class,            text(someText)),        v(Button.class,            text("Click me"),            onClick(someClickHandler)));

The first V () method returns a virtual layout that, after each call, returns the actual display of the current application state (not the actual view! )

When some text variables are changed-the virtual tree obtains a changed node value for the next render, and then calls SetText () to change the corresponding TextView instance. But the rest of the layout doesn't change any more.

A virtual layout tree should ideally be just a class, let's call it a knot. But there are two main types of nodes: View nodes (Textview.class, etc.) and attribute settings nodes, such as text (Sometext).

That means that the node should arbitrarily include a view class and a method to change the view's properties.

Interface Attributesetter { Public void Set(View v); } Public Static  class Node {List<node> attrs =NewArraylist<node> (); class<? Extends view> Viewclass;//For view nodesAttributesetter setter;//For attribute setter nodes         Public Node(class<? extends view> c) { This. Viewclass = C; } Public Node(Attributesetter Setter) { This. Setter = setter; }    }

Now we need to define what the class actually does when it comes to creating the virtual layout, so let's call the Render class. A rendered class can be an Activity, a custom viewgroup, or Fragment. Each of the rendered classes should have a method for returning the virtual layout, and it would be better if the method specifies which View it is going to use in the actual layout.

    publicinterface Renderable {        Node view();        ViewGroup getRootView();    }

Because the first parameter of the V () method is generic to the View subclass, you do not have to worry about type safety issues. The rest of the parameters are node types, so we just need to add them to the list, and it would be better to ignore the empty nodes.

    publicstaticv(finalfinal Node ...nodes) {        returnnew Node(cls) ;    }

Here's an example of the text () attribute setter (the real code was a bit different, but it could has been implemented Lik E this):

Here is a method for setting the text () property (the actual code will be a bit different, but it can be implemented as follows):

    publicstatictext(final String s) {        returnnew Node(new AttributeSetter() {            publicvoidset(View v) {                ((TextView) v).setText(s);            }        });    }

Other similar tool methods can be used to change the direction of the linear layout, the size of the view, the margins, and the spacing, in short, all the view parameters can be changed.

So, how are we going to render it?

Now we need a "renderer". This is a way to create a view based on the class name, modify the corresponding parameters using Attributesetters, and add the child View recursively. (Again, the following code is simplified, and the actual code is somewhat different, the main difference being how we should avoid rendering the view when the node is not changed)

     Public StaticViewInflatenode(Context C, node node, viewgroup parent) {if(Node.viewclass = =NULL) {Throw NewRuntimeException ("Root is not a view!"); }//Exception handling skipped the code look shorterView V = (view) node.viewClass.getConstructor (Context.class). newinstance (c); Parent.addview (v); for(Node subnode:node.attrs) {if(Subnode.setter! =NULL) {Subnode.setter.set (v); }Else{View Subview = Inflatenode (c, subnode, (ViewGroup) v); }        }returnV }

Now we can really get rid of the xmls and lay it out in Java in a neat way.

Layout nodes should not be used directly, but should be used by render (Renderer R) and render (). The former is used to re-render a view, which is used to re-render all the displayed view. Renderer is stored through a weak hash table so that when the View is removed or the Activity is destroyed-their renderer will no longer be used.

When is it going to be rendered?

The core of this framework is the automatic re-rendering, which allows the UI to always show the current virtual layout state. This means that render () should be called at a particular node.

I refer to Mithril method, put each on ... Listener and the method that calls render are bundled in the interaction of each UI.

     Public StaticNodeOnClick(FinalView.onclicklistener listener) {return NewNode (NewAttributesetter () { Public void Set(View v) {V.setonclicklistener (NewView.onclicklistener () { Public void OnClick(View v) {Listener.onclick (v);//After the click is Processed-some data may have been changed                        //So we try to re-render the UIRender ();            }                });    }        }); }

I think it makes sense to do this because most Android app data is changed when user interaction occurs. If your data is changed because of other factors-it can only be rendered manually through render ().

Overall

This method is simple, but useful:

    • You can define your layout structure in an XML-like way (by calling the V () method by nesting)

    • You can bind data and listeners in a way that's clear and understandable

    • Layouts are type-safe, and your compiler will do the work automatically

    • No runtime-generated overhead, no reflection mechanism, no automatic code generation

    • You can use Java (variables, statements, macros) to generate layouts everywhere

    • You can use custom View and custom properties to set the method

    • Because all of your UI data is stored in attributes, you can easily save them

    • Using pure Java To implement these logic requires less than 250 lines of code!

To make it clear that this method is feasible. Now I'm thinking, what if someone wants to develop a fully functional library in this way?

Designing a good "differentiate" algorithm is the key. Basically, it should be able to determine whether a node has been added/removed/modified, and the file is in the attribute node. Simple data types We just have to call equals () to compare two values, but what about the listener?

    v(SomeView.java,        onClick(v => ...));

In doing so, each time a virtual tree is created, a corresponding listener object is created. So how do you compare them? Or never update the listener, just update the listener class that has changed? Or use some sort of event distribution mechanism to distribute events instead of using listeners?

Another thing to be aware of: I don't want to write all the property settings myself. Here's a better way to do that, Kotlin they did in the Koan library.

I'm now working on how to automate the generation of the setup from the Android.jar class to make this project more useful.

Anyway, I put the code on Github now, with the permission of MIT. You are welcome to comment and pr!

Simplifying the development of Android UI

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.