[Bugly practical sharing] Android APP quick pad implementation

[Bugly practical sharing] Android APP quick pad implementation

[[164151]]

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.


Project Background

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.


1.Classic structure of MyApp page

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.
Looking at the code, we found that except for TabContent area 2, all pages from the home page to other full-screen pages are implemented using Android Activity components. According to statistics, there are about hundreds of Activities. These Activities also include other non-main process Activities such as Web process, peak process (picture selection and viewing).


1.MyApp pad design

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.


The exploration process of mobile APP pad

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.
The first thing that comes to mind is that since the mobile APP page is mainly composed of Activities, can we shrink the Activities and display multiple Activities on the same screen? Soon our solution 1 came out.

 

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:
1. Class A Activity inherits Base Activity
2. Modify the starting coordinate x and width width of the Base Activity window so that it is exactly located in area 3.
3. Change the background of Activity A to transparent
4. Repeat steps 1, 2, 3, and 4 for the activity that continues to be opened in type A activity.

 

But the problem was soon discovered.
1. Open Activity A in the current Tab, and Activity A remains displayed after switching Tabs.
2. The activities opened in each tab are in the same activity stack, added in the order of opening, and exited in order by clicking the back key. In this way, the activities opened in each tab are mixed together instead of being independent of each other, which causes problems with the back key.

 

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:
1. Override the startActivity method of the main Activity.  
2. Use LocalActivityManager to start class Aactivity and return the window object.
3. Return the layout of the opened Activity through the Window object window.getDecorView() and add it to the main Actvity.
4. Rewrite the Back logic of the main Activity and remove the mounted decorView when the back button is clicked.

 

But when testing on Demo, I found many problems.
1. Use mat to check that class A Activity cannot be released because LocalActivityManager has captured the parent of class A Activity.
2. Directly removing the decorView of Class A Activity will make Class A Activity lose all the characteristics of Activity, including life cycle, return logic, ActivityResult, and the function of starting other Activities, which will cause a lot of problems for Class A Activity that was running normally before.

 

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.


Note that the conversion of Activity to Fragment mentioned below does not mean directly changing Activity to Fragment, which will cost a lot, but using an empty Fragment as a container to host Activity.

 

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:
1. Add BasePadActivity, let all Activities inherit BasePadActivity, override the StartActivity method, manually create a new class A Activity in this method, and pass the context object Context of the main Activity to it.
2. Create MyFragment, hold a reference to the instance of Activity A, directly call the lifecycle method of Activity A in the lifecycle of MyFragment, and pass the view of Activity A to Fragment for use.
3. All methods inherited from Activity in class A are rewritten, and the specific implementation is handled by the main Activity context obtained in step 1. In this way, class A Activity has become a common instantiated object and is no longer managed by the Android system.

 

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.


After the solution was implemented, the initial test seemed to be normal, but several problems were discovered soon after:
1. There is a problem with the custom TitleBar of the original Activity.
2. Since the fragments opened in each tab belong to the same main activity, they only have one fragment stack. When returning to the previous activity, similar problems will occur as in solution 1.
3. Although most behaviors are simulated after the Activity is converted to a Fragment, some important behaviors are not processed, such as the Activity startup mode, the Back button, onActivityResult, etc. These need to be improved.
4. For an Activity declared as multi-process, it loses the multi-process feature after being converted to a Fragment, because these Fragments belong to the main Activity, which belongs to the mobile QQ process.

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?


Question 1: How to implement a custom TitleBar after Activity is replaced with Fragment?

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

?

1

2

getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,

             R.layout.custom_commen_title);

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.


Question 2: How to ensure that the operations of the Fragments in each tab do not interfere with each other?

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

?

1

2

3

4

5

Activity.java

final   FragmentManagerImpl mFragments = new   FragmentManagerImpl();

public   FragmentManager getFragmentManager() {

     return   mFragments;

}

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?


Question 3: After replacing Activity with Fragment, improve Fragment to simulate the behavior of Activity.

Improve the Activity behavior of Fragment, for example, you need to simulate the Activity startup mode, Activity result, startActivity, finish, onBackPressed, etc.


Question 4: How to handle the display of multi-process Activities?

Before answering this question, let me ask you a question: why not convert them all to Fragment?
When studying the code of mobile APP projects, I found that many Activities are designed to belong to other processes, such as Web processes. The reasons for this design are:

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.
Another important reason is that the Android platform has a memory limit for each process. Using multiple processes can increase the memory used by the app several times. Other processes can share the memory pressure of the main process, greatly reducing crashes caused by memory overflow.

 

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.


Question 5: How to handle multi-process activities after switching tabs? How to handle the Back key?

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.
How can this be achieved? I learned from reading http://developer.android.com/guide/components/tasks-and-back-stack.html
An app usually contains several Activities. We can divide these Activities into several categories, let each category belong to the same Task, and divide these Activities into several groups in a multi-tasking manner. For example, put the multi-process Activity opened in Tab1 into one Task, and put the multi-process Activity opened in Tab2 into another Task. When switching tabs, you only need to let the two tasks alternately move to the foreground to display or hide in the background, and each Task maintains an Activity stack. This idea seems to solve this problem.

 

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?
1. Implementation issues. To use the multi-task implementation, you need to declare the TaskAffinity of the Activity in Android. However, TaskAffinity cannot be declared dynamically in the code, but can only be written in the configuration file. As a result, the same Activity opened by different tabs may need to be declared twice in the configuration file, because their TaskAffinity must be different, and the same Activity cannot be declared twice. Therefore, you can only write an empty Activity to inherit it, resulting in a large number of empty Activities. In addition, you need to redirect to the inherited Activity before starting the Activity in the code, which is quite troublesome. After all, multi-process Activities are still rare, so this is possible. But it is obviously not advisable to implement all in this way.

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.


APP rapid pad implementation architecture solution

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.  
2. Let the converted Fragment simulate the behavior of Activity and keep the behavior of Fragment consistent with that of the original Activity.
3. Use LocalActivityManager to achieve the independence of each Tab Fragments operation.
4. Multi-process Activities (including plug-in Activities) are not converted into Fragments to achieve multi-tasking split-screen display.

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.
The following is the implementation of some pseudocodes. Please note that the following codes are all pseudocodes. Many of them only have methods but no implementation. The main focus here is on ideas .

[Java] Plain text view   Copy code

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

twenty one

twenty two

twenty three

twenty four

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

BasePadActivity.java

 

public   class   BasePadActivity extends   Activity{

     /**

      * Convert Fragment to Activity by overriding startActivityForResult

      */

     @Override

     public   void   startActivityForResult(Intent intent) {

         if   (isfragment && !isNewProcessActivty()){ //Multi-process Activity is not converted to Fragment

                 //Initialize activity. Note that this Activity is instantiated by ourselves.

                 BasePadActivity activity =(BasePadActivity)newInstance(intent);

                 activity.attachBaseContext(getBaseContext())

                 activity.onCreate(intent.getExtras()); //Simulate Activity's onCreate

                 activity.addMyFragment();

             }

         }

     }

 

     public   class   MyFragment extends   Fragment {

         @Override

         public   View onCreateView() {

             View contentView = getWindow().getDecorView(); //Fragment’s View is Activity’s decorView

             return   contentView;

         }

 

         @Override

         public   void   onResume() {

             super .onResume();

             BasePadActivity. this .onResume(); //Simulate Activity

         }

 

         @Override

         public   void   onPause() {

             super .onPause();

             BasePadActivity. this .onPause(); //Simulate Activity onPause

         }

         ........

         ........

     }

}

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.


2. Fragment simulates the behavior of Activity

Simulate the finish method of Activity

[Java] Plain text view   Copy code

?

1

2

3

4

5

6

7

BasePadActivity.java

 

  public   void   finish() {

     if   (bActivityToFragment) {

         removeTopFragment(); //Remove the topmost Fragment in the Fragment stack

     }

}

 

Simulate the onActivityResult of Activity and trigger it when the current Fragment is finished

[Java] Plain text view   Copy code

?

01

02

03

04

05

06

07

08

09

10

private   void   removeTopFragment() {

     if (popBackStackImmediate()){ //Successfully remove the top-level Fragment from the Fragment stack.

         handleSetResult(requestCode, false );

     }

}

 

private   void   handleSetResult( int   requestCode){

      //Trigger onActivityResult of the upper Fragment

     topFragment.onActivityResult(requestCode, resultCode, data);

}

 

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

?

1

2

3

4

5

6

7

8

9

BasePadActivity.java

 

public   void   onBackPressed() {

     if (isActivityForFragment()){ //, the Activity to which the Fragment belongs

         if (!handleFragmentBackEvent()){ //Handle the return event of Fragment itself first, for example, if you want to close the current Fragment menu first.

             finishTopFragment(); //***finish the Fragment

         }

     }

}

 

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

?

1

2

3

4

5

6

7

public   boolean   hasFlagClearTop( int   flags){

      return    (flags & Intent.FLAG_ACTIVITY_CLEAR_TOP )!= 0    ;

}

 

public   boolean   hasFlagNewTask( int   flags){

     return    (flags & Intent.FLAG_ACTIVITY_NEW_TASK )!= 0    ;

}

 

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.


3. Fragment implements custom TitleBar

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

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

twenty one

twenty two

twenty three

twenty four

25

26

27

28

29

30

BasePadActivity.java

public   Window getWindow() {

     if (customWindow== null ){ //Custom window, mainly to solve the problem that many Activities inherit IphoneTitleBar

             customWindow = new   Window4FragmentTitle(mContext);

         }

         return   customWindow;

}

 

Window4FragmentTitle.java

 

public   class   Window4FragmentTitle extends   Window{

     @Override

     public   void   setContentView(View view, LayoutParams params) {

         if   (mContentParent == null ) {

             installDecor();

         }

         mContentParent.addView(view, params);

     }

 

     @Override

     public   void   setFeatureInt( int   featureId, int   value) {

          if (featureId != FEATURE_CUSTOM_TITLE){

              return ;

          }

          FrameLayout titleContainer = (FrameLayout) findViewById(android.R.id.title);

          if   (titleContainer != null ) {

              mLayoutInflater.inflate(value, titleContainer);

          }

     }

}

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.


4. Use LocalActivityManager to achieve independent management of Fragments in each Tab.

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.
Main Activity

[Java] Plain text view   Copy code

?

1

2

3

4

5

6

7

8

9

addFrame(Tab1Content. class , mTabs[ 1 ]); //Tab1

addFrame(Tab2Content. class , mTabs[ 2 ]); //Tab2

.....

public   void   addFrame(){

     mTabHost.setup(getLocalActivityManager());

     TabSpec tabSpec = mTabHost.newTabSpec( "" ).setIndicator(tab).setContent( new   Intent( this , clz));

     mTabHost.addTab(tabSpec);

 

}

 

Use setContent(new Intent(this, clz) to add each tab bar content as a child Activity.


5. Multi-task split-screen display.

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.  
2. Define the size and position of the Activity.

Implemented in the onCreate method of Activity

[Java] Plain text view   Copy code

?

1

2

3

WindowManager.LayoutParams layoutParams = window.getAttributes();

layoutParams.gravity = Gravity.RIGHT | Gravity.TOP; //Position on the right

layoutParams.width = mActivity.getRightPanelWidth(); //The width is the width of the right area

 

** 3. Let the main Activity on the left receive events**
By setting the flag of the window's WindowManager.LayoutParams to FLAG NOT TOUCH_MODAL, the main Activity displayed below the left side of the transparent Activity can receive events.
The newly opened activity is located in the right area, and the left area is the main activity display area. The left and right areas can receive user click events at the same time, and it looks like the same activity.

 

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?


Provide a different TaskAffinity for the first Activity opened by each Tab
First, let's understand what is TaskAffinity ?
In some cases, Android needs to know which Task an Activity belongs to. This is done through TaskAffinity. TaskAffinity provides a unique name for a task that runs one or more Activities. When an Activity is marked with the Intent.FLAG_ACTIVITY NEW TASK flag and a unique TaskAffinity is declared for the Activity, the Activity no longer runs in the Task that started it, but restarts a new Task. The new task manages a new Activity stack, and the opened Activity is at the bottom of the stack.
Understanding TaskAffinity, we set the TaskAffinity value of the related tab for the opened multi-process Activity in the configuration file


The following shows the processing of web process Activity

[Java] Plain text view   Copy code

?

01

02

03

04

05

06

07

08

09

10

11

12

13

<activity

   android:name= "BrowserActivity1"

   android:process= ":web"

   android:taskAffinity= "com.tab1.BrowserActivity1"

   android:theme= "@style/Default.Transparent"   />

 

<activity

   android:name= "BrowserActivity2"

   android:process= ":web"

   android:taskAffinity= "com.tab2.BrowserActivity2"

   android:theme= "@style/Default.Transparent" />

 

........

 

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

?

1

2

3

4

5

6

7

8

9

public   void   startActivityForResult(Intent intent) {

   if (isBrowserActivity(intent)){ //Purely open QQBrowserActivity

     int   curTab = getTabIndex(); //Get the current Tab index

     Class<?> c = getBrowserMap().get(curTab); //Get the corresponding opened Activity

     redirectAndOpenInNewTask() // redirect

   }

   ......

   ......

}

 

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

?

1

2

3

4

5

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);

}

 

At this point, the problem caused by displaying multi-process Activities and the main Activity on the same screen has basically been solved.


Summarize

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.


Extensions

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

Recommend

Teasing Microsoft Cortana, it will answer you like this

Microsoft's personal voice assistant Cortana i...

The strategy to increase the volume of live broadcasts from 0-1!

When it comes to private domain, everyone’s first...

How to write a complete event operation plan?

This year I also tried event operation for the fi...

How long will these IP marketing be popular?

No one can tell how long they will remain popular...

Advertising and marketing creative poster collection

For every designer Posters are the most common an...

Today I will teach you how to blow the biggest bubbles in the world

I believe most people have played the game of blo...

From ad images to landing pages, 14 tips to improve conversions

This article is a summary of the book "The B...

Why did eBay return to China together with JD.com?

[[132426]] After a year of preparation, JD.com...

Summary of Common Methods for Custom Controls

[[183466]] In addition to the measurement, layout...

Short video operation topic selection guide

When operating short videos, topic selection, dir...