Bugly The technical content series mainly involves mobile development. Bugly invited technical experts from Tencent to write it based on their daily work experience and insights. The content is original. Please indicate the source when reprinting. How can we implement the latest version of an Android app on a pad in the fastest time? From the development of a large mobile app code to the release of its first new pad version, we gave a satisfactory answer in less than 3 months. The latest version of the mobile APP (hereinafter referred to as MyApp) code is used to implement its padding to provide a better experience for tablet and large-screen mobile phone users. To implement the padding of MyApp, we first need to understand the composition of the classic page of the MyApp project and the changes in the page structure after padding. The main page of mainstream mobile APPs nowadays is usually displayed in the form of a tab bar plus label content. The secondary pages entered through the home page are all displayed in full screen. For example, mobile QQ, WeChat, Alipay, etc. are mainly displayed in the form of a tab bar. After entering a specific function, they are opened in full screen. This is also the case with our project. Let's take a look at the page composition diagram of the mobile terminal of the MyApp project. On the left is a page consisting of a Tab bar (area 1) and Tab Content (area 2), and on the right is a function details page (full screen area 3) that is entered after clicking a specific function in TabContent. After understanding the structure of the MyApp page on the mobile phone, we need to look at the changes in the UI structure after the Pad version, and explore the implementation scheme of the Pad version through comparison. The following is the page structure diagram of our PAD version. Since the space of a Pad tablet is much larger than that of a mobile phone, the content displayed on the homepage of the Pad is more than that of a mobile phone. By observing the design diagram, it is found that the entire page is divided into 3 areas, which correspond to areas 1, 2, and 3 of the mobile phone page. The Tab bar is moved to area 1 on the left, and the Tab Content is moved to area 2 in the middle. The Details page opened in area 2 is required to be displayed in area 3, instead of full screen like a mobile phone APP. By understanding the changes in the classic page composition of the MyApp project and the pad version page structure, as well as the principles of rapid padification, we began a long exploration of the pad implementation solution for mobile APPs.
Solution 1: If the entire page of the design is called the main activity, the main activity is displayed in full screen, and the new activity (called A) opened in the main activity is displayed in the design area 3 in a reduced size, we can achieve the requirements of the pad design. Then our specific implementation steps are:
But the problem was soon discovered.
Since there is a problem with directly displaying Actvity, we think that since we are displaying the UI layout anyway, can we pull out the root layout of Class A Activity and mount it on the right side of the main Activity? Thus, we derived Solution 2. Solution 2: When the main activity starts the A type activity, get the root layout of A and add it to an empty layout reserved in the right area 3 of the main activity. The specific implementation steps are:
But when testing on Demo, I found many problems.
Since it is useless to get the root view directly, what should we do? How can we mount the page of class A Activity on the right side of the main Activity while ensuring the life cycle and activity behavior of A? After some thinking and discussion, can we use the idea of plug-in to take out the life cycle methods in class A Activity and the methods inherited from the Activity class and call them at the appropriate time? This ensures that there will be no problems with the original code in A, and there is no need to modify any code in A. But what is the best container (agent)? Later we thought of using Fragment, because Fragment can exist anywhere as a block of the Activity to which it belongs, and Fragment has its own life cycle and is affected by the life cycle of the Activity to which it belongs, just like a child Activity. It is simply a *** container. Moreover, Fragment is relatively lightweight and is managed by Activity itself (unlike Activity is managed by Android system service). Reusing Fragment in different layout structures can optimize screen space and user experience.
Finally, Plan 3 was successfully implemented. Solution 3: Convert Activity to Fragment and use Fragment to simulate Activity methods. Then add Fragment directly to the right layout of the main Activity. The specific steps to achieve this are:
This solution has many advantages. Since it inherits base, it can not only quickly convert a large number of activities into fragments, but also keep the functional logic of the original A-type activity normal after the conversion. And because the context of the A-type activity actually uses the context object of the main activity, the resources, windows, and assets objects that need to be obtained in the A-type activity can be obtained through the context of the main activity. Although this solution also has many problems, after research and testing, it is found that most of them can be solved. Due to the advantages of this solution and the difficulty of solving the problems it has, it is finally decided to optimize and improve it. So how to solve the above problems? Setting a custom TitleBar is an interface provided by Activity. Looking at the mobile APP code, most Activities inherit TitleBarActivity. [Java] Plain text view Copy code ?
To define the style of TitleBar. So after changing to Fragment, many Activity titlebars cannot be displayed, or even crash. So can we implement a custom window object that inherits android.view.Window, and get our custom Window object through getWindow(), which can handle the use of custom Titlebar. The homepage of the Pad version is also divided into multiple Tab tabs. The operations on Fragments in each tab should be independent of each other. Fragments in Android are managed by FragmentManager. The operations of adding, replacing, and removing Fragments are recorded and executed by the FragmentTransaction object in FragmentManager. There is only one FragmentManager instance in each Activity. [Java] Plain text view Copy code ?
Get. If the entire page in the design is called the main activity, using a FragmentManager in the main activity to manage the fragments of all tab bars will obviously cause confusion. So can we implement an instance of FragmentManager in each tab page to manage the fragments of all activity transitions in the current tab? Improve the Activity behavior of Fragment, for example, you need to simulate the Activity startup mode, Activity result, startActivity, finish, onBackPressed, etc. Before answering this question, let me ask you a question: why not convert them all to Fragment? One is that these types of Activity functions all belong to the same module, and even if a crash occurs, it will not cause the entire QQ to crash.
Therefore, we cannot easily convert these Activities into Fragments, because if they are converted into Fragments, the multi-process characteristics of Activities will be lost, which violates the original design intention and greatly increases the memory pressure of the APP. In this case, can multiple Activities be displayed on the same screen ? Can the new Activity opened from the main Activity be made transparent, and its size and position just cover area 3 of the design diagram, while allowing areas 1 and 2 belonging to the main Activity to receive events. This will not only give Acitvity the characteristics of multiple processes, but also make them look like they are operating in the same Activity. Hey, isn't this our solution 1? Yes, due to the above reasons, for multi-process Activities, we still have to deal with it according to solution 1. So how to solve the problem in solution 1. The multi-process activities opened in each tab should only be associated with this tab. After switching to another tab, these activities should be hidden. When switching back to the tab again, the activities previously opened in the tab should be redisplayed. And each tab's activities should be managed by an activity stack.
Now you may have another question: since the problem in solution 1 can be solved, why not just use solution 1? Why do we need to convert Activity to Fragment? 2. User experience issue: When switching tabs and moving a task to the foreground, there will be a delay, and this delay is uncertain. As a result, when switching back to the tab, the bottom page will be displayed first, and then the Activity in the task will cover it. 3. The problem with the model. For a very small number of models, there may be a problem when multiple activities are displayed on the same screen due to manufacturer customization. When receiving the event of the main activity on the left, the A-type activity will disappear. After searching for the cause, it was found that the task of the A-type activity automatically returned to the background. It should be that the system source code has been modified. In this case, it is basically unusable. After several analyses and discussions, we have basically figured out the approximate solution to the problem encountered in Solution 3. After balanced consideration, the following solution is the current solution for Padization. After clarifying the entire process of MyApp padification and the problems that would be encountered, we determined the architecture plan for our mobile APP padification after thinking and discussing with everyone: 1. Convert the Activity of the APP main process to Fragment, and try not to modify any code of the original Activity during the conversion process. 1. Cleverly convert Activity to Fragment Implement BasePadActivity as the base class for all Activities, and implement the operation of converting Activities to Fragments in BasePadActivity. Using the idea of plug-ins, using Fragments as shells, move the real specific implementation from Activities to Fragments without modifying any code of the original Activity. By rewriting the StartActivity method, the original action of starting an Activity is changed to adding a new Fragment, and calling the addToBackStatck() method to add it to the Fragment stack. [Java] Plain text view Copy code ?
The code cleverly implements the process of converting all Activities that inherit BasePadActivity into Fragments. Of course, only a small part of the conversion is shown here, and other details are not listed in the code. When the process of opening an Activity is converted to the process of opening a Fragment, we need to let the Fragment simulate the behavior of the Activity. Simulate the finish method of Activity [Java] Plain text view Copy code ?
Simulate the onActivityResult of Activity and trigger it when the current Fragment is finished [Java] Plain text view Copy code ?
Simulate the return event of Activity. When converting Activity to Fragment, its return event has been received by the Activity to which the Fragment belongs, so it is necessary to process the return event of the real Activity to which it belongs. All Fragments in the Activity can be managed through FragmentManager. [Java] Plain text view Copy code ?
Simulate the way the Activity is started, and determine the start mode of the Activity by obtaining the value of intent.getFlags(). [Java] Plain text view Copy code ?
To determine whether the Flag contains the corresponding startup mode value, to handle the opening of the Fragment accordingly. This will be a little troublesome, so I won't explain it in code. Without changing the original Activity code, you can control the Fragment layout by changing the Window object. Implement a custom Titlebar. [Java] Plain text view Copy code ?
By calling the setFeatureInt(int) method through Window4FragmentTitle, the custom Title layout will be embedded into the layout mDecor we created, and then mDecor will be placed in the Fragment to realize the display of the custom Titlebar in the Fragment. Use LocalActivityManager to implement tab layout, so that each Tab has an Acitvity object, and each Activity has a FragmentManager to manage the Frament stack of the Tab, so that the Fragments of each Tab are independent of each other and do not affect each other. [Java] Plain text view Copy code ?
Use setContent(new Intent(this, clz) to add each tab bar content as a child Activity. As mentioned above, for multi-process Activities, in order to maintain their modularity and share the memory pressure of the main process , after discussion, we decided not to convert them into Fragments, so we need to solve the problem of displaying multiple Activities together. After research, we found that the effective implementation method is to make the Activities opened in each tab bar transparent, and make their size and position just in area 3 of the design diagram, and at the same time allow the main Activity in the left area below the Activity to receive click events . 1. To make Activity transparent, declare the Activity theme as transparent in the configuration file. Implemented in the onCreate method of Activity [Java] Plain text view Copy code ?
** 3. Let the main Activity on the left receive events**
However, since the Activity opened in the current Tab and located in the right area follows the current Tab, it should disappear after switching Tabs. For example, the Activity opened in Tab1 should be hidden when switching to Tab2, and redisplayed when switching back to Tab1 to preserve the scene. How to implement this function? After understanding and thinking about the characteristics of Android, it is found that the display and hiding of multi-process Activities in different Tabs can be achieved by using multi-task split-screen display . Let the Activities opened in different Tabs belong to different Tasks, and each task has an Activity stack to manage the Activities in it. Switching tabs requires switching between different Tasks. This logic is very clear and also conforms to the principle of fast Padization. So how to implement it specifically? [Java] Plain text view Copy code ?
The BrowserActivity opened in different Tabs has different TaskAffinity set for them. In the code, when it is found that the opened page is a web page, the page is redirected to the Activity with the corresponding TaskAffinity set in the Tab in which it is opened. [Java] Plain text view Copy code ?
This creates different tasks for activities opened in different tabs. Then, when switching tabs, tasks are dynamically displayed and hidden by sending broadcasts. public void onTabSelected(int curTabIndex) { Intent i = new Intent("action"); i.putExtra("cur_Tab_Id",curTabIndex); //Switch to the index of the current Tab sendBroadcast(i);} Receive broadcasts in the root Activity of the Task and handle Task display and hiding logic [Java] Plain text view Copy code ?
At this point, the problem caused by displaying multi-process Activities and the main Activity on the same screen has basically been solved. Through the above solution and the clever solution of some problems, the rapid development of MyApp Pad was finally realized. Moreover, MyApp for Pad has been running stably since the first version was released and has been iterating 6 to 7 versions. The advantage of this solution is that as long as the architecture is well maintained, other developers do not need to care whether it is a real Activity or a Fragment when modifying a single page. As long as they know that these pages all show the behavior of Activity, it is the same as developing on a mobile phone APP. Through the implementation of the MyApp Pad development solution, we wondered if our solution could be written into a universal mobile app pad component to provide technical support for the company's other Android products. Even if your app layout is not in tab mode, we open a Base Activity, and other app activities can be automatically converted to Fragments by inheriting Base, and can provide processing solutions for multi-process activities. But this certainly requires considering more situations and solving more problems. The road is long and arduous, and I will continue to explore. I look forward to the perfect Android App PAD component to meet you.
If you feel that the content is not enough, if you want to know more relevant information, please scan the QR code below and follow our public account to get more technical information and share exciting activities with you~
Tencent Bugly is a quality monitoring tool designed for mobile developers, helping developers quickly and conveniently locate online application crashes and solutions. The intelligent merging function helps developers to merge and classify the thousands of crashes reported every day according to the root cause. The daily report will list the crashes that affect the most users. The precise positioning function helps developers locate the problematic code line. Real-time reporting can quickly understand the quality of the application after release. It is compatible with the official operating systems of iOS and Android. Tencent engineers are using it. Come and join us!
|
<<: iOS Development - Basic Framework
>>: Big Data and Behavior Prediction Model—Liu Zhijun
In the post-epidemic era, technology's domina...
Microsoft's personal voice assistant Cortana i...
When it comes to private domain, everyone’s first...
Natural and artificial radiation Natural radiatio...
This year I also tried event operation for the fi...
No one can tell how long they will remain popular...
For every designer Posters are the most common an...
I believe most people have played the game of blo...
This article is a summary of the book "The B...
From the 1 billion yuan red envelope subsidy camp...
[[132426]] After a year of preparation, JD.com...
[[183466]] In addition to the measurement, layout...
Author: Shi Xiangqi and Li Chuanfu On September 2...
The Beginning of Autumn is the thirteenth solar t...
When operating short videos, topic selection, dir...