Hi, everybody. Let me introduce you. This is a Bug

Many Android users should be familiar with the above picture…

The background,

A few days before the National Day, a large number of wechat Android users reported receiving or sending similar “15… Messages cause the wechat chat interface to freeze and the app to crash. This is a very serious matter for wechat, and the feedback will soon be overwhelming. When we learned of this problem, we immediately repaired the problem and covered most users of the whole network within two days, and finally the problem was solved. Trace back to the source, there is no doubt that the pot development younger brother to back, this time can not be wronged the product MM ha ha.

At the same time, many enthusiastic netizens also began to analyze the cause. On the day of 25th, a great god in the industry worked out the root of the ANR step by step through the ANR log and decompilation debug, and gave the cause of the stuck. Please accept a little brother worship, really admire!

Details refer to link: http://androidwing.net/index.php/243

The figure below is the analysis result of netizens:

According to the user’s analysis, the real reason for the deadlock is: “the WWK is always equal to 0, that is, it does not meet the null condition of dVar2 inside the while, which causes the while loop”. How do you do dynamic decompilation here?

This zhihu answer is very detailed, https://www.zhihu.com/question/65828771

Ii. Reasons revealed:

The real reason, as analyzed by netizens, is mainly stuck in the while loop, which is mainly used to break the current text content according to specific rules.

Because dVar2 and dvar2. getText are never empty, this condition is always satisfied, so an infinite loop is created. The condition that dVar2 is null depends on the following function

Dvar2.getlength () is actually the text length of the current line. Here, because of the bug of the sentence breaking algorithm, the variable “i4” keeps returning 0, while the current line text length dvar2.getLength() is >0. So this dVar2 will never be assigned to null. To get to the bottom of the question: why does the clause breaker keep returning 0? It actually calls the following function:

This function returns an object a that takes two arguments, the position of the break (a.wwk) and the length of the text after the break (a.width). This is mainly because the last non-punctuation character on the current line needs to be truncated to the next line when judging the newline because of the rule that punctuation should not be at the beginning of the line. Truncation is restricted by another rule, which states that truncation cannot be English or numeric, resulting in “15…” Finally, the truncated position is returned as 0, and the result is returned, so the endless loop is generated, causing this bug.

So the question comes and a lot of netizens also start to discuss, why typesetting, put a good system TextView does not need? What’s so good about it? What was the effect? Don’t worry, let my little brother explain the ins and outs of many problems one by one.

Three, why have this demand

In fact, most of the world’s demand comes from users. This demand also benefits from several users who will feedback that “wechat Android chat bubbles seem not as beautiful as iOS, more rigid”. This issue has also caught our attention. Is that the case? We compared iOS and Android, as shown below:

IOS looks better than Android, at least there’s not as much padding on the far right. Simply speaking, the extra padding is caused by the bubble width being limited by the screen size, so TextView is the bubble with the maximum width limit. The problem arises when system typography chooses to wrap lines when there is not enough space left for a single character.

Another question: Is typography perfect on iOS? In fact, it is not. As you can see from the image above, iOS also has this problem, that is, the text in the bubble is uneven from left to right. At first we wondered if it was the wechat app itself that was using the component incorrectly, rather than the system component. As a result, on mobile phones, we randomly found some popular apps and carefully compared, the same problem still exists.

Zhihu:

The nuggets:

Pay treasure:

Wait…

And in addition to mobile, there are also problems on PCS. Combined with these comparisons, it’s true that most apps on the market have this problem. Through this feedback, we began to think about whether we could make text typesetting on mobile client more humanized and have a better experience. . On this issue, we found the design students together to discuss, think it is really necessary. So the next step began.

Four, how to arrange typesetting?

For text typesetting, it is easy to think of, “my (Word) brother”, Microsoft for this application, do you have any method or scheme for text left and right alignment reference? The image below shows the left alignment of Word, which is the default TextView on Android.

The image below shows the centered ‘hard’ alignment of Word:

The image below shows the centered ‘soft’ alignment of Word:

From this point of view, “soft alignment” is more aesthetically pleasing and has the best experience.

The only way we can think of to achieve this effect is to dynamically adjust the spacing between words (which is what Word does).

So if you want to adjust the font spacing dynamically, can you just do that? The answer, of course, is not, if it’s like ‘hard alignment,’ it’s too blunt.

We will discuss this problem with the design team colleagues, through their research and attempt to come up with a reasonable solution, that is allowed to have an English character width adjusting range, will adjust the width of the average allocation to the current line each character, influence is the smallest for users, but also keep some beautiful.

Practice custom typesetting

For Android, it is not difficult to implement this rule, either to transform the system TextView, or to write a custom view to achieve text typesetting and rendering, we finally adopted the latter scheme. Here’s why: The logic of typesetting and drawing of TextView is not in itself, but given to three subclasses that inherit Layout, namely StaticLayout, DynamicLayout and BoringLayout. StaticLayout is more commonly used. It is only responsible for static word processing, about the difference between the respective Layout, here will not expand. The system TextView does not expose interfaces to proxy them. Of course, just because we don’t have an interface doesn’t mean we can’t do it, we can proxy it by means of reflection and so on, but in fact, to do so, the cost is relatively high.

There are three reasons: First, from Android 2.3 to Android 8.0, although the TextView code will not change much, but from the perspective of Layout, the implementation of logic or interface have changed, if through this way, the compatibility of proxy will be a problem.

Second, TextView is one of the most complex components of Android. Several Layout logic codes are very complex. It is a complicated and heavy work to implement all Layout interfaces by ourselves.

Third, in fact, their own implementation of a Layout, basically to achieve a display component, Layout and rendering are to deal with, so the realization of the significance is not much, even not flexible

Anyway, we are on the system, comparing the TextView rules finally we identified the following rule: 1, there is at most one letter character width to adjust the word spacing 2, for punctuation as far as possible avoid don’t appear at the beginning of 3, for English words or Numbers are not truncated typesetting so we started a simple demo. The effect is shown below:

Compared to the effect before optimization, the effect is indeed obvious. However, after careful observation, it is still found that for some special Chinese full-corner symbols (such as “” () [], etc.), because of the existence of redundant padding, placing them at the beginning and end of the line will also lead to uneven effect. 4. For some common full-corner symbols with extra padding at the beginning or end of a line, the default is to subtract the extra padding to achieve better alignment. The final optimization effect is shown as follows:

The last one is a rendering with the four rules applied, and the overall text alignment is much better than the system’s default typography.

So the question is again if it works well, are there other problems? That’s true.

1. Small language processing problem because wechat supports small languages, for some special small languages, such as Thai, Arabic, etc., the typesetting method of Thai is not simply horizontal, there is a up and down relationship between characters, but for Arabic, it is arranged from right to left. If only according to the above several rules, then typesetting after the effect is certainly unreasonable. Considering the small language diversity, typesetting rules are not unified, and the use of small language user scale is small, but also can’t let its typographical errors, so in this case, we through a simple regular expression to match whether belong to within the scope of string can handle, which is why netizens to analyze 15 “……” This event is initially suspected to be caused by the length of the re match.

The following is the user’s analysis:

In fact, this simple regular expression, as the user tested, is very fast to process, basically within 1ms, the impact on performance is negligible.

After judging by the re, if it is a string that can be processed, the above rules will be applied to typesetting. If it is a special string, it will be displayed by the system’s TextView agent.

Since the problem of small languages can be solved, but there is a problem here: how often do users on the Internet use special characters? This question is directly related to the fit rate of our composition component, that is, how much it improves the user experience? In our opinion, ordinary people do not send some strange symbols in wechat, so it should be the majority of people who can apply this layout rule. Of course, this is just a guess, and it would be premature to determine the feasibility. Therefore, we conducted a round of grayscale for this problem, and the grayscale results are as follows:

gray The results of
Target grayscale number 40W
SetText total number 400w+
Average hit rate 96% +

Through the gray scale, the users of the live network can apply the adaption of this component to achieve the expected results.

If the performance of this component differs too much from the system, or even seriously affects the frame rate, causing user lag, this is of course not desirable. To solve this problem, we carried out a local automatic frame rate test and a function comparison with TextView: experimental data:

Attributes CellTextView TextView Remarks
FPS(good) 53.93 54.11 Chat interface, various types of text, running the same case, frame rate on a good machine
FPS(bad) 41.91 41.41 The frame rate on the machine
setText(ns) 1345208 8839618 For the same 1000-char text, set ext once every 100ms, and collect 30 setText statistics
onMeasure(ns) 2152881 6111 Average time it takes for setText to trigger onMeasure 30 times
onDraw(ns) 16516024 2459097 SetText triggers onDraw, 30 times on average
sum(ns) 20014113 11304826 SetText process, 30 times on average

Conclusion:

  • From the micro point of view, through function comparison, CellTextView comparison system TextView performance is slightly worse 2 times, the main difference lies in the need to adjust the spacing of single words when drawing text.

  • Macroscopically, CellTextView has little influence on the actual frame rate, and users have no obvious perception of performance deterioration.

Through the above attempts and gray results, it is actually meaningful to do this thing, so the optimization scheme was finally finalized.

At the end

This is the context of the whole requirement. In fact, sorting out the context of this process can not only help me to reflect on some problems existing in the process, but also, because this bug has really caused a bad impact on everyone (really deeply sorry!). “, so that you can understand how this thing happened, at least you don’t get stuck in the dark. You have to be very careful when writing code. Remember the pain this time, a fall into the pit, a gain in your wit. Wish the world’s programs all without bugs. Yes, nothing!!

Finally, paste an optimized effect diagram:

Article write bad place, hope forgive, big god don’t spray don’t spray. I’m gonna take the fall for this, buddy.