In-depth analysis of Android custom layout and android custom Layout
In-depth analysis of Android custom Layout
As long as you have written the Android program, you must have used several built-in layout s on the Android platform, including RelativeLayout, LinearLayout, and FrameLayout. They can help us build a good Android UI.
These built-in la s provide many convenient components, but in many cases you still need to customize your own la S.
To sum up, the custom layout has two advantages:
By reducing the use of views and faster traversal of layout elements, you can make your UI display more efficient;
You can build UIs that cannot be implemented by existing views.
In this blog post, I will implement four different custom la S and compare their advantages and disadvantages. They are composite view, custom composite view, flat custom view, and async custom views.
These code implementations can be found in the android-layout-samples project on my github. This app uses the four custom la s mentioned above to achieve the same UI effect. They use Picasso to load images. The UI of this app is only a simplified version of twitter timeline-no interaction, only layout.
Well, let's start with the most common custom Layout: composite view.
Composite View
Composite views (also known as compound views) are the easiest way to combine multiple views into a reusable UI component. The implementation process of this method is as follows:
Inherit related built-in la S.
Fill in a merge layout in the constructor.
Initialize the member variable and use findViewById () to point to the internal view.
Add a custom API to query and update the view status.
TweetCompositeViewcode is a composite view. It inherits from RelativeLayout, fills in the tweet_composite_layout.xmlcode layout file, and finally exposes the update () method to update its status in adaptercode.
Custom Composite View
The preceding Implementation of TweetCompositeView can meet most of the requirements. However, in some cases, it will not work. Suppose you want to reduce the number of child views to make the convenience of layout elements more effective.
In this case, we can look back and see that although the implementation of composite views is relatively simple, there is still a lot of overhead to use these built-in Layout-especially the complicated containers such as LinearLayout and RelativeLayout. Because of the built-in layout Implementation of the Android platform, in a layout element traversal, the system needs to deal with the combination of many layout_weight layouts and multiple measurements of sub-views. The layout_weight attribute of LinearLayout is a common example.
Therefore, you can customize a set of sub-view computing and positioning logic for your app, so that you can greatly optimize your UI. This is the custom composite view I will introduce next.
As the name suggests, a custom composite view is a composite view that overrides the onMeasure () and onLayout () methods. Therefore, compared with the previous composite view, RelativeLayout is inherited. Now we need to go further-inherit more abstract ViewGroup.
TweetLayoutViewcode is implemented using this technology. Note that this implementation does not inherit LinearLayout from TweetComposiveView, which avoids the use of the layout_weightcode attribute.
In this large cost-effective process, the measureChildWithMargins () method of ViewGroup's and the getChildMeasureSpec () method behind it calculate the MeasureSpec for each subview.
TweetLayoutView cannot correctly process all possible layout combinations, but it does not have. We certainly need to optimize our custom layout based on specific needs. This method allows us to write simple and efficient layout code.
Flat Custom View
As you can see, custom composite views can be implemented simply by using the ViewGroup API. Most of the time, this implementation can meet our needs.
However, if we want to go further, we can optimize the UI of key parts in our application, such as ListViews and ViewPager. What if we merge all the TweetLayoutView sub-views into a single custom view and manage it in a unified manner? This is the flat custom view we will discuss next -- see the image below.
Custom composite view on the left and flat custom view on the right
Flat custom view is a fully customized view. It is fully responsible for the calculation, location arrangement, and drawing of internal subviews. Therefore, it inherits the View instead of the ViewGroup directly.
If you want to find out whether an app exists in real life, it is very simple-enable the "display layout boundary" option in "Developer mode" on your mobile phone, and then open Twitter, Gmail, or Pocket apps use flat custom view in the list UI.
The main advantage of using flat custom view is that it can greatly compress the view level of the app, so that it can perform faster layout element traversal and ultimately reduce memory usage.
Flat custom view gives you the greatest freedom, as if you were painting on a blank sheet of paper. However, such freedom has a price: you cannot use the existing view elements, such as TextView and ImageView. That's right. It's really easy to describe the text on the Canvas, but what if you want to implement ellipsizing (that is, truncation of long texts? Similarly, it is really easy to draw an image on the Canvas, but how to scale it? These restrictions also apply to touch events, accessibility, keyboard navigation, and so on.
Therefore, the bottom line for using flat custom view is to apply flat custom view only to the core UI part of your app. Others directly depend on the view provided by the Android platform.
TweetElementViewcode is flat custom view. To implement it more easily, I created a small custom view framework called UIElement. You can find it in the canvascode package.
UIElement provides the measure/layout API similar to the Android platform. It contains TextView and ImageView without an image interface, and these two elements contain several required features-see TextElementcode and ImageElementcode respectively. It also has its own inflatercode to help instantiate the UIElement from the layout resource file code.
Note: UIElement is still in very early stages of development, so there are still many defects, but it may become very useful with the continuous improvement of UIElement in the future.
You may think that the code of TweetElementView looks very simple, because the actual code is in the TweetElementcode-in fact, TweetElementView plays the hosted role code.
The layout code in the TweetElement is very similar to that in the TweetLayoutView, but it does not have the same code when requesting an image using Picasso, because the ImageView is not used in the TweetElement.
Async Custom View
In general, the Android UI framework is single-threaded. Such a single thread will impose some restrictions. For example, you cannot traverse layout elements outside the main thread-however, this is very beneficial to the complex and dynamic UI.
If your app has complicated entries in a ListView (like most social apps), you may jump frames when sliding the ListView, because ListView needs to calculate their view size code and layout code for the new content to be displayed in the list. The same problem also occurs in GridViews, ViewPagers, and so on.
Can we solve the above problem if we can traverse the layout of those child views on the threads other than the main thread? That is to say, calling the measure () and layout () Methods on the subview does not occupy the Time of the main thread.
Therefore, async custom view is an experiment that allows the sub-view layout traversal process to happen outside the main thread. This idea is inspired by Facebook's Paperteam async node framework video.
Since we will never be able to access the UI components of the Android platform outside the main thread, we need an API to measure and layout the content of this view without being able to directly access this view. This is exactly what the UIElement framework provides to me.
AsyncTweetViewcode is an async custom view. It uses a thread-safe AsyncTweetElementcode factory class code to define its content. The specific process is that the code of an Smoothie subitem loader creates, pre-measures, and caches temporarily invisible AsyncTweetElement on a background thread (in the memory for later use ).
Of course, I have compromised some implementation of this asynchronous UI, because you do not know how to display layout placeholders of any height. For example, when the layout is passed asynchronously, you can only change the size of the layout in the background thread once. Therefore, when an AsyncTweetView is to be displayed, the appropriate AsyncTweetElement cannot be found in the memory. At this time, the framework will force the creation of an AsyncTweetElement code on the main thread.
In addition, the pre-loaded logic and memory cache expiration time settings must be well implemented to ensure that the cache layout in the memory is used as much as possible in the main thread. For example, using LRU to cache code in this solution is not a wise choice.
Despite these limitations, the preliminary results of Using async M view are promising. Of course, I will continue to explore this field by restructuring this UIElement framework and using other types of UIS. Let's stay tuned.
Summary
The deeper we define the layout, the less dependencies we can obtain from the Android platform. Therefore, we also need to avoid premature optimization. We can customize the layout only in areas that can actually improve the app quality and performance.
This is not a non-black-white decision. There are also many solutions between using the platform's UI elements and completely customized two extremes-from simple composite views to complex async views. In actual projects, you may write excellent apps in combination with several solutions in the article.