📜 ⬆️ ⬇️

Thread support in Mail.Ru Mail Android application: we are achieving complete sync



Threads, or chains of letters in the mail, are one of the features that geeks and mass audiences have polar views on. Geeks actively use them; ordinary users, as our polls show, are more likely to be wary of them. First, it is unusual, and secondly, people are afraid that they will not be able to orient themselves in chains. When we implemented threads in the web version of Mail.Ru Mail, we remembered this chelendzhe - and we found, as it seems to us, the most convenient and intuitively understandable grouping algorithm, which will be convenient for geeks and less advanced users. We took the system developed by the Big Mail as a basis for working on mobile threads, since we did not want to confuse users and make different logic. From the point of view of the product, our task was to ensure that both web threads and mobile threads work in the same way for the user. But many things had to be redone in the light of offline work. About how we did in the Mail.Ru Mail Android application, where letters are not lost even with network failures, I will tell in this article (we'll tell you about the same thing in an iOS application in the following posts).



In the mobile application, we placed special emphasis on stable and uninterrupted work offline. Our goal was to make the user offline to edit letters, move them, put labels, work with mail and perform actions with entire threads - and when the network appears, so that information about all these actions is correctly transmitted to the server.
')
The most common way to implement threads in email applications is to group letters on the client itself: letters are pumped out and only then they are collected in chains. This option covers most of the standard situations with the exception of difficult cases, among which, for example, the correct grouping of letters into threads when working offline. However, we needed a solution that would work well for all users. We did not want to sacrifice offline work, because the quality of the product is manifested just in difficult situations. In addition, when we conducted usability testing, people noted that using threads was convenient and cool - but many were afraid that they would stop finding letters in the drawer if the chains were grouped non-intuitively. Therefore, we paid special attention to the work of the application offline: it was necessary to make sure that all changes were saved separately, and then synchronized unnoticed when convenient. For the user, it should look like this: he makes changes, and then the application itself understands how and when to send all this to the server.

The technical side of synchronization


So, we decided on the approach, it was possible to start implementation. The logic of grouping letters into chains was developed even for the large web version of Mail. So we did not have to reinvent the wheel: in an Android application, we simply implemented the same algorithm. On Habré there is a detailed post about how it was developed and how it differs from the algorithms that other mail services use, so I will not describe it in detail in today's article.

So, it was important to make sure that all operations with letters within our logic are carried out correctly. For example, when moving or deleting messages, all the counters in the web and the application should display the correct (updated) number of letters in the thread, all the flags and marks “Read”, “Not read” should be updated and synchronized, certain threads should stop displaying in some folders and so on. In addition to the correctness of synchronization, it was important to ensure that operations on letters were performed quickly. We tested the speed on an array of 200 letters in different threads and folders. In the first version it took about 20 seconds - and all this time the user would have to wait. Naturally, we could not allow this.

We began to look for the reason for such slowness. Initially, we assumed that SQL operations took up most of the time, because they depended on the number of letters: when performing an operation, each of them had to update threads, counters, folders, the letter itself, and so on. However, in reality, the bottleneck was copying overly complex indexes, which we then used to select data from memory. It took 70-80% of these 20 seconds. We removed the copying of these indexes, as well as rebuilding the indexes for each operation, made buffering and update after the operation was completed at the end of the transaction. As a result, instead of 20 seconds, we only got about 20-50 ms for the operation of rebuilding indexes. In addition, we removed from the rebuilds of the index data that does not change according to our business logic.

We have fairly simple and fast indexes, for example, by some specific value: flagged, unflagged, read, unread, by folder value, by account. If the value of state options is finite, the indices are rebuilt quickly. And text indexes based on prefix trees are rebuilt for a long time: they are large in terms of the amount of memory occupied, and in general this structure is rather cumbersome. It allows you to speed up the search process, but it is very complex and changes for a long time. These are standard problems of different structures and data processing algorithms. Where we want to win on the search, we naturally lose on changing this data.

At first we tried to do different implementations of text indexes. Tangible difference was not noticed and chose those that were faster according to our measurements. But we still did not achieve the desired indicators in time. Then we decided to go on the other side. Such data as the subject of the letter, the sender, etc. during operations with the letter do not change. So you can simply refuse to rebuild complex indexes and limit those that are responsible for the flagged, unflagged, and so on parameters, that is, fast. We abandoned all unnecessary operations, optimized what cannot be abandoned, and immediately accelerated synchronization by 50-60%.

But we didn’t stop at that either, because operations can be grouped. If you do not try to make a universal algorithm, but parse it into final variants and group the input data by type of operation, then you can perform it without any conditions and unnecessary operations from the database. We individually optimized operations with flags, with the movement of letters, etc., and they ceased to depend on the amount of transmitted data.

As a result, the user sees a fast response no matter what kind of operation he performed and on what data. At the very beginning, we set the bar for 100 ms for ourselves, but rested on the limitations of Android itself: the transaction mechanism is rather slow, and if you do not use it, then we get an intermediate state error. I had to adjust the requirements. We planned that, from the user's point of view, the operation took no more than 200-500 milliseconds. Most likely, in the next version of Android, we still achieve that the user operations are performed almost instantly.

Interface


As I already mentioned, the logic of displaying threads is the Mail Android application inherited from the web version. However, in the implementation of the interface, of course, there are differences: the screen of the smartphone and even the tablet is much smaller than the desktop, and it was necessary to decide exactly how to display threads on them.



Initially, we chose between two options. The first is a display in two levels (the list of threads and the viewing of a thread combined with reading a letter). At first it seemed logical and preferable to us. But having tested this implementation in other applications, we were disappointed in it: the display of threads on two screens in all cases turned out to be quite inconvenient. Therefore, we have chosen the option with three levels (a list of threads, viewing letters inside this thread, opening and reading a letter). In this case, the user has the opportunity to look at the headers and choose which letters he wants to open.

Due to the fact that the threads inside the thread have the same topics, they are grouped, and there is a place on the screen for displaying more detailed snippets. In general, it turned out to be more convenient: when you need to remember what was discussed in a long correspondence, you can refresh it in your memory by snippets of letters, or quickly go to the desired letter and start reading the correspondence from the place where something is important.

Another difference between the big web and the application concerns the position of the new letters in the thread. In the web version, this is done in two screens, because the browser has where to place this information. The web always shows a thread and opens either the last unread letter or the top letter from this folder, and then you can fold and unfold any letters on one screen. In the Android application, the user at the moment is always “failing” either in a thread or reading a letter (if the conversation contains only one letter). Between letters inside the thread, you can move left or right on the svaypu.

We should also tell you about the toolbar, which relates to the whole thread. Here, Android-mail has more discrepancies with the web version. In the last toolbar - this is a large panel that allows you to perform operations with the top letter thread in the folder. In the Mail.Ru Android application, work is carried out either with a whole chain or with specific letters allocated by the user. There is only one exception: when working with a thread, there is an opportunity to respond to the last letter in this thread. This is one of quite frequent and important cases, so we removed this button from reading the letter and included it in the work tools for the thread. The "Reply" and "Forward" buttons, which can be called the main action buttons for a thread, apply to the last letter in the thread.

Interaction with Android Wear and Android Auto


We initially implemented support for Android Wear and Android Auto, so for the interaction of Android Mail with a clock and a radio tape recorder, we didn’t have to do anything extra. If the user has included in the mail settings the grouping of letters, notifications on the clock will also be grouped by threads. If the grouping of letters is disabled, then everything will work as before, and notifications will not be grouped. On the radio running Android Auto, notifications are also grouped by threads.

In our opinion, we have coped with the tasks. But, as always, we are looking forward to your feedback. Test threads on Android and tell if it’s convenient for you?

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


All Articles