1 introduction

The previous article was a bit sloppy for a relatively small and complex framework, so I’ve rewritten this one. Now I will take you hand in hand to learn Gbox, decryption of large factory level home high-performance dynamic framework.

Note: All the XML in this article can be pasted directly to the mock test, and screenshots of running the preview are included with the article. Reading this article may take you billions of times.

What problem should we solve?

2.1 Do not talk about the application scenario is playing rogue!

Online, RN and WebView are not flexible enough or perform well enough for some scenarios that require strong presentation, light interaction and high scalability.

RN takes up the entire Activity, and the communication loss between Native and Js is unavoidable. WebView is even worse, and you have to lock the main thread to load webKit. This is in the second, third page is ok, in the home page is absolutely not using this performance out of the scheme.

In addition, for the active blocks of feed stream cards and first-level pages, the logic of these pages itself is not strong, and often only needs local dynamic. Therefore, in a comprehensive view, RN and WebView are not optimal, so we need a third way.

2.2 Plan of Meituan APP team

For these application scenarios, meituan APP team has its own set of closed source dynamic container MTFlexbox to deal with this, which can quickly develop the layout online and is not restricted by the distribution. I had the honor to learn MTFlexbox during my internship in Meituan, so I would like to thank the students in the APP terminal business RESEARCH and development group of Meituan as well as my former Leader.

This scheme not only bears the dynamic home page of Meituan, but also solves the problem of FPS fluctuations in the continuous sliding process of the home page of Meituan. For details, please refer to their article 👉Litho’s practice in the dynamic scheme MTFlexbox.

2.3 My solution

After returning to school after the internship, I always wanted to make a summary of my internship in Meituan, but I did not know what topic was appropriate. After thinking about it, I felt that I had a good understanding of MTFlexbox and its applicable business characteristics, so I finally chose to design and implement an open source framework Gbox with similar functions to MTFlexbox, so that Gbox could become an open source substitute of MTFlexbox.

Note: Gbox was developed using Kotlin and released under the Apache Open Source license. Although I say Gbox is an open source alternative to MTFlexbox, but Gbox ≠ MTFlexbox🙅, it does not contain any source code for MTFlexbox, nor is it a compatible version of MTFlexbox. It is a completely new open source software implementation based on open source software.

3 Gbox profile

3.1 Development History

Gbox development, from requirements analysis -> design -> technology selection -> coding ->bug fixes, took me about three weeks. Portability (or cross-platform) and performance indexes were mainly evaluated during the technology selection, and finally the technology selection of Litho+Tomcat EL+ Kotlin was confirmed.

  • Litho is sufficiently efficient and the package size is small. In addition to draw operation measure and layout are completed in asynchronous thread, which can meet the performance requirements. In addition, there is equivalent ComponentKit implementation on iOS platform.
  • Tomcat EL is powerful and proven. There is almost no external dependence on the implementation, and it can be directly ported to iOS using Google’s open source project J2Objc.
  • Kotlin dramatically reduces code redundancy, and uses Kotlin’s inlining to achieve higher performance with less code.

In fact, the rendering layer of the framework was originally intended to use Flutter, but I realized that it was too heavy in the middle of the code. Then I went back to the Litho line for development. During this time, I stepped on a lot of Litho, Drawable and Canvas holes. I also gained a deeper understanding of the entire Android rendering system.

So far, Gbox is pretty much stable, but there will be more small features coming in, which you can find at github 👉.

3.2 Features supported by Gbox

Gbox is business-friendly and performance-friendly:

  • Time-consuming operations are asynchronized. One of the reasons why Gbox is efficient is to move measure and layout from the original View system to the asynchronous thread, freeing up the main thread
  • Kill the layout hierarchy. Rendering directly using lightweight Drawable provides a performance advantage over WebView
  • Asynchronous image loading. Using a lightweight Glide as an image loading engine, all images can be loaded from the web without triggering additional layout updates
  • Agile development, ready to go online, front and back end separation. The backend delivers the layout and data JSON, which can be integrated into the data interface and can be delivered locally to parse and render the layout
  • Single container View access, basically no intrusion. Can be used to replace any existing static display View, and support exposure buried point, click buried point, click time processing and other events
  • Provides a complete development tool chain. Layout development provides real-time preview APP (Overview) and mock tools, which can be connected to a computer by scanning codes for real-time preview debugging
  • Based on the widely used Flexbox layout model, it contains a wealth of configurable styles, such as border colors, rounded corners, pictures, text, etc
  • Powerful intra-layout binding expressions. Includes math operations, for statements, ternary expressions, simple Java method calls, used when using expressionsThe ${}Surrounded by
  • Screen adaptation: The layout unit is device-independent PT. The screen is divided into 360 parts based on the screen width of the device. 1PT = device screen width /360
  • Using Kotlin implementation, code implementation is very simple, very easy to read and learn
  • Old logic friendly, support native View embedded in Gbox

3.3 Contrast with MTFlexbox

Compare MTFlexbox (Meituan APP) with Gbox (Gbox’s real-time preview APP) on the left.

This layout file

4 Start building the Gbox development environment

4.1 Installing the Overview APP

Git Clone

git clone https://github.com/sanyuankexie/Gbox
Copy the code

Since APT technology is used in the project, it is necessary to rebuild the source code after cloning.

First we need to install the Overview APP. Open the Overview module and install the Overview APP on your test machine.

The next most important step is to make sure your phone is on the same network as your computer.

4.2 Executing Test Cases

Locate the MockTestCase file in the mock module.

Notice The theme color of Android Studio must be white; otherwise, the GENERATED QR code cannot be recognized by the mobile phone.

4.3 Starting a Real-time preview

The APP scans the QR code generated by the console to preview the layout file on the computer.

So how does Gbox implement live preview?

The principle is simple, as you might have guessed. The Mock module opens an HTTP server, and the overview scans for the IP address and port number of the computer. The Overview then requests the server to deliver the layout and data every second, providing a real-time preview of the layout. Attach the source 👉 mocksession.kt.

5 Start to write the layout file

5.1 Binding Expressions

Before we start writing the layout, we need to understand the binding expressions for Gbox.

Gbox binding expressions are based on embedded Tomcat (right! So it supports all the features of EL expressions, including Java Bean access, method calls, ternary expressions, mathematical operations, and so on.

Suppose you have a JSON file like this:

{
    "number":1000."control": {"display":true
    },
    "text":"This text will not be displayed."
}
Copy the code

Write the binding expression below

<?xml version="1.0" encoding="utf-8"? >
<Flex
    width="360"
    background="yellow"
    flexDirection="row">
    <Text
        textSize="30"
        text="${control.display? 'Other text ':text}"
        height="100">
    </Text>
</Flex>
Copy the code

This Text will not display the Text ‘this Text will not be displayed’, but ‘other Text’. Note that string constants are wrapped in single quotes in binding expressions.

Mathematical operations:

<?xml version="1.0" encoding="utf-8"? >
<Flex
    width="360"
    background="yellow"
    flexDirection="row">
    <Text
        textSize="30"
        text="${number+1000}"
        height="100">
    </Text>
</Flex>
Copy the code

You can use binding expressions in any property, not just the text property, to suit your data presentation needs.

5.2 the Flex

Since Gbox is based on Litho’s UI framework, and Litho uses Yoga’s layout engine based on flexbox’s layout model, the first thing to support is Flex, which, as its name implies, is an elastic container.

Flex’s implementation is very simple, and you can think of it as an enhanced LinenerLayout, which supports the following properties:

FlexDirection is used to specify the main axis direction and supports row, column, rowReverse, and columnReverse. The following is a screenshot of row and column. If flexDirection is not specified, the default is Row.

<?xml version="1.0" encoding="utf-8"? >
<Flex flexDirection="row">
    <Flex
        background="red"
        width="100"
        height="100">
    </Flex>
    <Flex
        background="blue"
        width="100"
        height="100">
    </Flex>
</Flex>
Copy the code

<?xml version="1.0" encoding="utf-8"? >
<Flex flexDirection="column">
    <Flex
        background="red"
        width="100"
        height="100">
    </Flex>
    <Flex
        background="blue"
        width="100"
        height="100">
    </Flex>
</Flex>
Copy the code

Next came the justifyContent property, which identifies the alignment of all its child layouts on the spindle, including flexStart, flexEnd, center, spaceBetween, and spaceAround. I demonstrated this effect by writing an XML document.

FlexStart, flexEnd, and Center need no explanation, while spaceBetween and spaceAround need some explanation.

  • SpaceBetween means that both ends are aligned, with equal intervals between items.
  • SpaceAround means equal spacing on both sides of each item.
<?xml version="1.0" encoding="utf-8"? >
<Flex
    width="360"
    background="yellow"
    flexDirection="column">
    <Flex
        justifyContent="flexStart"
        margin="5">
        <Flex
            background="red"
            width="100"
            height="100">
        </Flex>
        <Flex
            background="blue"
            width="100"
            height="100">
        </Flex>
    </Flex>
    <Flex
        justifyContent="flexEnd"
        margin="5">
        <Flex
            background="red"
            width="100"
            height="100">
        </Flex>
        <Flex
            background="blue"
            width="100"
            height="100">
        </Flex>
    </Flex>
    <Flex
        justifyContent="center"
        margin="5">
        <Flex
            background="red"
            width="100"
            height="100">
        </Flex>
        <Flex
            background="blue"
            width="100"
            height="100">
        </Flex>
    </Flex>
    <Flex
        justifyContent="spaceBetween"
        margin="5">
        <Flex
            background="red"
            width="100"
            height="100">
        </Flex>
        <Flex
            background="blue"
            width="100"
            height="100">
        </Flex>
    </Flex>
    <Flex
        justifyContent="spaceAround"
        margin="5">
        <Flex
            background="red"
            width="100"
            height="100">
        </Flex>
        <Flex
            background="blue"
            width="100"
            height="100">
        </Flex>
    </Flex>
</Flex>
Copy the code

Then there is alignItems, which describes the alignment of the sub-layout on the secondary axis. It supports flexStart, flexEnd, Center, baseline, and Stretch.

The baseline is aligned with the first line of the project. When “stretch” is specified, the child Layout will fill up the parent Layout if the height is not specified.

Write the following XML:

<?xml version="1.0" encoding="utf-8"? >
<Flex
    width="360"
    height="360"
    background="yellow"
    flexDirection="row">
    <Flex
        height="360"
        alignItems="flexStart"
        margin="5">
        <Flex
            background="red"
            width="100"
            height="100">
        </Flex>
        <Flex
            background="blue"
            width="100"
            height="100">
        </Flex>
    </Flex>
    <Flex
        height="360"
        alignItems="flexEnd"
        margin="5">
        <Flex
            background="red"
            width="100"
            height="100">
        </Flex>
        <Flex
            background="blue"
            width="100"
            height="100">
        </Flex>
    </Flex>
    <Flex
        height="360"
        alignItems="center"
        margin="5">
        <Flex
            background="red"
            width="100"
            height="100">
        </Flex>
        <Flex
            background="blue"
            width="100"
            height="100">
        </Flex>
    </Flex>
    <Flex
        height="360"
        alignItems="baseline"
        margin="5">
        <Flex
            background="red"
            width="100"
            height="100">
        </Flex>
        <Flex
            background="blue"
            width="100"
            height="100">
        </Flex>
    </Flex>
    <Flex
        height="360"
        alignItems="stretch"
        margin="5">
        <Flex
            background="red"
            width="100">
        </Flex>
        <Flex
            background="blue"
            width="100">
        </Flex>
    </Flex>
</Flex>
Copy the code

In the layout above, you’ll find the value 360 appears a lot, and yes, it’s a special value in Gbox. For screen adaptation, Gbox’s size unit is device independent. It divides the screen width into 360 parts based on the screen width. The pixel value of one unit is equal to the screen width pixel value /360, which is exactly the size of the 2X design drawing.

All Layout properties and levels of Gbox will eventually be applied to Facebook’s Yoga Layout engine. No matter how complex the Layout is, you don’t need to worry because all calculations are done in a designable Layout thread without affecting the main thread. And the View that is eventually generated on the screen does not have these redundant layout levels. For more information about Litho, I suggest you consult the Litho documentation.

5.3 Frame

Frame implements a layout effect similar to FrameLayout on Android, which is used for multi-layer stacking that is difficult to achieve with Flex.

With Frame, Gbox takes a more aggressive layout measurement strategy than Flex. As we all know, in Android FrameLayout, onMeasure measures all sub-layouts to determine the width and height. Gbox parallelizes this operation by taking advantage of the immobility of Litho Component (thread safety).

Frame has a separate thread pool and can measure all sublayouts concurrently, with the result aggregated in one thread, as shown in the following figure.

PS: People speaking is to invoke the Java. Util. Concurrent. Executors# newCachedThreadPool, then wait for a thread for other Java. Util. Concurrent. The Future is completed, The source link is 👉 framefactory.kt

Write the following layout for the overlay effect:

<?xml version="1.0" encoding="utf-8"? >
<Frame
    width="360"
    height="360"
    background="yellow"
    flexDirection="row">
    <Flex
        background="red"
        width="100"
        height="100">
    </Flex>
    <Flex
        marginTop="50"
        marginLeft="50"
        background="blue"
        width="100"
        height="100">
    </Flex>
</Frame>
Copy the code

5.4 the Image

Image is more than just a simple ImageView. It is a Glide Image loading engine that supports asynchronous loading, rounded cropping, and Gaussian blur.

Load web images using urls:

Instead of using Litho’s State for asynchronous image loading, Gbox does not trigger Litho’s layout update, instead replacing the underlying Drawble and then calling invalidateDrawable to refresh the dirty rectangle.

PS: Using drawableWrapper.kt.

Json data used by the mock:

{
    	"image2": "http://5b0988e595225.cdn.sohucs.com/images/20180606/0a49d21848324503a1e04c4b942a1631.png"
}
Copy the code

Writing XML:

<?xml version="1.0" encoding="utf-8"? >
<Flex
    width="360"
    background="yellow"
    flexDirection="row">
    <Image
        width="360"
        height="360"
        url="${image2}">
    </Image>
</Flex>
Copy the code

<?xml version="1.0" encoding="utf-8"? >
<Flex
    width="360"
    background="yellow"
    flexDirection="row">
    <Image
        scaleType="fitXY"
        borderRadius="100"
        width="360"
        height="360"
        url="${image2}">
    </Image>
</Flex>
Copy the code

BlurRadius is radian, and the value is between 1-25; blurSampling is sampling rate, and the value is larger than 1.

Gbox uses RenderScript technology to maximize the efficiency of Gaussian blur and reduce the delay time of image appearance when gaussian blur is used.

PS: To speak human language, Glide added a Transformation to the image, the source link is 👉BlurTransformation

<?xml version="1.0" encoding="utf-8"? >
<Flex
    width="360"
    background="yellow"
    flexDirection="row">
    <Image
        blurRadius="25"
        blurSampling="2"
        scaleType="fitXY"
        borderRadius="100"
        width="360"
        height="360"
        url="${image2}">
    </Image>
</Flex>
Copy the code

If you are careful, you will notice that fitXY is already being used. Lol

<?xml version="1.0" encoding="utf-8"? >
<Flex
    width="360"
    background="yellow"
    flexDirection="row">
    <Image
        scaleType="fitEnd"
        width="360"
        height="360"
        url="${image2}">
    </Image>
</Flex>
Copy the code

5.5 the Text

Text is used to display Text, and currently supports the following attributes:

  • Text specifies the text to display
  • HorizontalGravity Specifies the text alignment method, which can be center, left, or right
  • TextSize specifies the textSize
  • TextStyle is used to specify text styles such as normal (default), bold (bold)
  • MaxLines specifies the maximum number of lines
  • MinLines specifies the minimum number of lines
  • TextColor specifies the font color
<?xml version="1.0" encoding="utf-8"? >
<Flex
    width="360"
    background="yellow"
    flexDirection="column">
    <Text
        textColor="#59a9ff"
        textSize="30"
        text="1111 text">
    </Text>
    <Text
        textColor="red"
        textSize="30"
        text="1111 text">
    </Text>
    <Text
        textColor="blue"
        textSize="30"
        text="1111 text">
    </Text>
</Flex>
Copy the code

5.6 Native

Gbox is also friendly to traditional business components.

If you have to write custom views from scratch after you plug in Gbox, then Gbox loses the point of rapid development. So Gbox also supports native View access.

PS: people speaking is encapsulates the com. Facebook. Litho. ViewCompatComponent, source 👉 NativeFactory. Kt.

Using the Type attribute, write the following code to implement the style shown in the figure below.

<?xml version="1.0" encoding="utf-8"? >
<Flex
    width="360"
    background="yellow"
    flexDirection="row">
    <Flex
        flexDirection="row">
        <Text
            marginLeft="10"
            textSize="28"
            text="Switch">
        </Text>
        <Native
            marginLeft="10"
            type="ch.ielse.view.SwitchView">
        </Native>
    </Flex>
</Flex>
Copy the code

5.7 Scroller

A Scroller is a ScrollView. Like a ScrollView, it can have only one child View, which is styled by two properties:

  • ScrollBarEnable is a Boolean value (true or false) that controls whether the scroll bar is displayed.
  • Orientation controls whether horizontal or horizontal.
<?xml version="1.0" encoding="utf-8"? >
<Scroller>
    <Flex>
        <Image
            width="360"
            height="600"
            scaleType="fitXY"
            url="${image2}">
        </Image>
    </Flex>
</Scroller>
Copy the code

I’m not going to show it. I just don’t see the point of screenshots.

5.8 the for

The for tag is used when there is list data in the Model data to expand.

The for tag has three attributes that must be specified when used. Var, FROM, to, and index are used to specify the name of the iterator in the loop. From and to specify the scope of the iteration of var. Let’s say you have the following data:

{
    "height":1000."itemTexts": ["Gbox"."Facebook"."Litho"."Google"]}Copy the code

Write the following layout:

<?xml version="1.0" encoding="utf-8"? >
<Flex
    width="360"
    background="yellow"
    flexDirection="column">
    <for var="index" from="1" to="3">
        <Text
            textSize="30"
            text="${itemTexts[index]}">
        </Text>
    </for>
</Flex>
Copy the code

Can be equivalently expanded as:

<Flex
    width="360"
    background="yellow"
    flexDirection="column">
        <Text
            textSize="30"
            text="${itemTexts[1]}">
        </Text>
        <Text
            textSize="30"
            text="${itemTexts[2]}">
        </Text>
        <Text
            textSize="30"
            text="${itemTexts[3]}">
        </Text>
</Flex>
Copy the code

The iterator specified by the for tag var only applies to the layout tag included in the for loop

PS: for tag is called Tomcat EL ELContext#enterLambdaScope and ELContext#exitLambdaScope implementation, code I will not post here, you can 👉 directly jump to github to see the source code

5.9 Built-in Functions

Gbox also currently supports built-in functions that must be called within a binding expression:

utils:check(o:Any)

It is possible to check if a variable is valid, and false is returned for empty or zero-sized sets or empty strings

The check method is implemented by Kotlin:

        fun check(o: Any?).: Boolean {
            return when (o) {
                is String -> o.isNotEmpty()
                isCollection<*> -> ! o.isEmpty()isNumber -> o.toInt() ! =0
                else-> o ! =null}}Copy the code

In the layout logic below, nothing is displayed on the screen because there is no ‘no_found’ variable in json.

<?xml version="1.0" encoding="utf-8"? >
<Flex>
    <Image
        width="360"
        height="360"
        url="${utils:check(no_found)? image2:''}">
    </Image>
</Flex>
Copy the code

draw:gradient(o:Orientation,vararg colors: String)

Used to achieve gradient color, the first parameter is gradient color direction, there are t2b(top to bottom), TR2BL (top right to bottom left), L2R (right to left), BR2TL (bottom right to top left), B2T (bottom to top), R2L (right to left), TL2BR (top left to bottom right) eight directions can be selected, the second parameter is variable, A string of several colors can be passed

Kotlin source code implementation:

        fun gradient(orientation: GradientDrawable.Orientation.vararg colors: String): GradientDrawable {
            return GradientDrawable(orientation, colors.map {
                parseColor(it)
            }.toIntArray())
        }
Copy the code

Write XML to implement gradient:

<?xml version="1.0" encoding="utf-8"? >
<Flex>
    <Flex
        width="360"
        height="360"
        background="${draw:gradient(tl2br,'red','blue','yellow')}">
    </Flex>
</Flex>
Copy the code

5.10 Other General Attributes

In addition to the above attributes, there are many other attributes that are common, so I will briefly introduce some of the more important attributes due to space limitations.

The background property is common to all widgets and is used to specify a background for an image. It supports one of three display sources:

  • The url of the picture
  • Hex color value starting with #
  • Gradient (demonstrated above)

Image URL as the background

<?xml version="1.0" encoding="utf-8"? >
<Flex>
    <Flex
        width="360"
        height="360"
        background="${image2}">
    </Flex>
</Flex>
Copy the code

BorderRadius is used to implement the rounded corners of clipping background boundaries.

<?xml version="1.0" encoding="utf-8"? >
<Flex>
    <Flex
        borderRadius="100"
        width="360"
        height="360"
        background="${image2}">
    </Flex>
</Flex>
Copy the code

You can also specify the width and color of the border using borderColor and borderWidth.

<?xml version="1.0" encoding="utf-8"? >
<Flex>
    <Flex
        borderColor="red"
        borderWidth="10"
        borderRadius="100"
        width="360"
        height="360"
        background="${image2}">
    </Flex>
</Flex>
Copy the code

Use the clickUrl and open the Overview APP’s console, click on the image, and receive the message from the click event in an EventListener, which can be a URL for external jumps.

<?xml version="1.0" encoding="utf-8"? >
<Flex>
    <Flex
        clickUrl="Lafite is the cutest in the world."
        borderColor="red"
        borderWidth="10"
        borderRadius="100"
        width="360"
        height="360"
        background="${image2}">
    </Flex>
</Flex>
Copy the code

There are also some general attributes, which I have briefly listed here:

Wide high

  • height
  • width

visibility

  • Visibility is similar to Android, with support for Visible, Invisible, and Gone

From the outside

  • margin
  • marginBottom
  • marginTop
  • marginLeft
  • marginRight

padding

  • padding
  • paddingTop
  • paddingBottom
  • paddingLeft
  • paddingRight

Other attributes supported by Flexbox

  • alignSelf
  • alignContent
  • flexGrow
  • flexShrink
  • .

For the Flexbox section, I sincerely recommend you to read Ruan Yifeng’s article on Flex layout.

The corresponding properties in Gbox are basically using the Java naming style for these properties, dropping the median line and starting the second word in uppercase. Align-content in CSS is alignContent in Gbox.

6 Back-end integration precautions

6.1 Integration Suggestions

On the back end, potential integrators need to establish a unified layout management system that includes:

  • The layout of the CDN.
  • Git linkage version control function and so on.

Of course these are also in the future development plan, welcome your PR.

6.2 Json is Delivered, not XML

It’s worth noting that even though the layout is written in XML, you can see that the mock server ultimately delivers only JSON to the client. This is because the mock server has converted the XML to JSON at the time the layout is delivered, so that the layout is integrated into the data interface for delivery and parsed using uniform tools. So Gbox does not have a parsing module to couple XML, but instead maximizes existing infrastructure. Therefore, XML needs to be converted to JSON for storage during back-end integration.

7. Integrate Gbox into new projects

7.1 Remote Dependence on Gbox

Gbox is built using the JitPack, added in your root project’s build.gradle

	allprojects {
		repositories {
			...
			maven { url 'https://jitpack.io'}}}Copy the code

It is then dependent in modules

	dependencies {
	        implementation 'com.github.LukeXeon.flexbox:core:latest.release'
	}
Copy the code

Sync project, SDK can be integrated into the project, the package size of Gbox is not too large, about 1M, which is mainly the size of Facebook Litho.

7.2 Container Litho integrated with Gbox

Gbox is based on a Litho, so you have to find a place to initialize a Litho, either in your Application, or in your first Activity, but you just initialize it before LithoView.

SoLoader.init(this, false);
Copy the code

LithoView is a container for Gbox, used in XML:

<com.facebook.litho.LithoView
    android:id="@+id/host"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</com.facebook.litho.LithoView>
Copy the code

Then grab the instance in the Java layer, call setComponentAsync, and pass in a newly constructed DynamicBox.

mLithoView.setComponentAsync(
                    DynamicBox.create(c)
                        .bind(data)
                        .layout(layout)
                        .eventListener(this)
                        .build()
                );
Copy the code

The layout is a com. Guet. Flexbox. NodeInfo class instances, it is used to describe a layout of the tree, the entire layout tree roots.

Data, on the other hand, is data bound to the layout, which supports automatic matching of multiple data formats, in the following two cases:

  • In projects that rely on Gson, data can be String, byte[], Reader, and InputStream data sources.
  • If there is no Gson in the project, Gbox also supports nested multilevel maps

    and standard Java beans (with getters, setters) as data sources.
    ,object>

In the Overview APP, I use Retrofit to simplify this process.

Add Retrofit dependencies:

    implementation 'com. Squareup. Retrofit2: retrofit: 2.6.2'
    implementation 'com. Squareup. Retrofit2: converter - gson: 2.6.2'
Copy the code

Instantiate the interface with Retrofit:

package com.guet.flexbox.overview;

import com.guet.flexbox.NodeInfo;

import java.util.Map;

import retrofit2.Call;
import retrofit2.http.GET;

public interface MockService {
    @GET("/data")
    Call<Map<String, Object>> data();

    @GET("/layout")
    Call<NodeInfo> layout(a);
}

mMockService = new Retrofit.Builder()
        .baseUrl(url)
        .client(new OkHttpClient())
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(MockService.class);
Copy the code

EventListener is used to handle event callbacks, and there are currently three types of event click, reported click, and reported exposure.

package com.guet.flexbox

enum class EventType {
    CLICK,
    REPORT_CLICK,
    REPORT_VIEW
}

package com.guet.flexbox

interface EventListener {
    fun onEvent(type: EventType, action: String?)
}
Copy the code

The action passed in is the result of parsing the string you wrote in XML.

8 epilogue

8.1 make fun

As a joke, it’s hard to document, but you can’t do it without quality documentation. People can’t understand what you’re doing, so it really proves the old adage that “programmers want detailed documentation, but never write it themselves and hate colleagues who don’t.”

8.2 If you can’t run

I’m sorry that some students pulled my code and didn’t run. The Develop branch is for me to develop and test new features by myself. The Master branch is the stable master branch for jitpack packaging. I will add the master branch to the github repository after the Develop code is stable. That shouldn’t have caused the problem we had before.

There will be some minor problems in the new framework, and I will supplement the notes in the Gbox code in the future. Please send me an email. If you find any problems, you can directly send me an issue, and I will follow up on Github, or directly send me an email at [email protected], thank you for your support.

8.3 About New Features

Here are some directions that will be tried in the future:

  • IDEA plug-in integrated with Android Studio
  • Put the drawing operation in the asynchronous thread as well
  • IOS side based on ComponentKit and EL (J2Objc)

8.3 small tail

Last but not least, star! O star! O star! Important thing say three times, ask everybody big guy to help, click once play a year, open source does not spend a cent!