preface
If you have more than 2-3 years of development experience and don’t know how to optimize your project, it’s a bit of a stretch. Here’s my own set of generic Android performance optimizations. If the image is not clear, you can download the original Xmind image at the end of the text.
If you’re looking for a job, you need an Android Advanced Development interview guide
1. Have you done any research on APP launch? Have you done startup optimizations?
Programmer:
I have studied the startup principle of the Application when I did the hot fix. Some startup optimizations were also made in the project.
Interviewer:
Oh, you were working on overheating repairs? (At this point, it is possible to ask in depth about the principle of hotfix, but we will not discuss the principle of hotfix here.) What optimizations have been made to boot?
Programmer:
-
I found that when the program was cold started, there would be a white screen flash for about 1s, while the earlier version was a black screen phenomenon. During this period, I found that the system AppTheme set a windowBackground by browsing the source code of the system theme, which inferred that this attribute was the ghost. In the beginning, I set the windowIsTranslucent transparent property and found that although there was no white screen, there was still a small section of invisibility in the middle. This user experience was not good. Finally, I observed that most Android software on the market will have a Splash AD page when it is cold started, and at the same time, a countdown timer is added before entering the login page or home page. I did this in the end, because it has the advantage of giving the user a basic understanding of the APP based on the ads, and also allows us to do some preparation for the plug-in and some necessary or time-consuming initialization during the countdown.
Ps: This will show the interviewer that you are a user experience oriented person
-
When we click on the desktop icon to enter our software Application, AMS sends a fork child process message to Zygote via Socket. When the Zygote fork is complete, the Zygote fork starts the ActivityThread##main function by reflection, which is then started by AMS telling ActivityThread##H to create the Application instance by reflection. The attachBaseContext and onCreate lifecycles are executed in turn, so we can’t take time on the main thread during these two lifecycles.
Ps: This will let the interviewer feel that you on the App startup process research is more deep, have a real browse the underlying source code, but not recite the answer.
-
Knowing that attachBaseContext and onCreate start first in the application, we can use performance tools like TreceView to detect the time spent on specific functions and then optimize them.
- Projects do not need the code to be loaded asynchronously in time.
- Will do lazy loading for some underused initializations.
- Some time-consuming tasks are handled by starting an IntentService.
- Redex is used to rearrange class files, and the files needed in the startup phase are arranged together in the APK file. As much as possible, the Pagecache mechanism of the Linux file system is used to read as many files as possible in the startup phase with the least disk IO times. This reduces THE I/O overhead and improves the startup performance.
- It can be done in lower version 5.0 through the douyin post
MultiDex
Optimization: At the first startup, directly load the original DEX that has not been optimized by OPT, so that the APP can be started normally first. Then start a separate process in the background, slowly finish the OPT of DEX, as far as possible to avoid affecting the normal use of the foreground APP.
Ps: 1. The interviewer here will feel that you do know a good start optimization, there is a certain start optimization experience.
- At number five, the interviewer will think that you are paying attention to what’s going on in the community and finding good solutions that you can apply to your own project. That’s a plus!
-
After the Application is started, AMS finds the Activity at the top of the foreground stack to be started, and finally instantiates the Activity by notifying ActivityThread#H with AIDL and executing the onCreate, onStart, and onRemuse lifecycle functions in turn. So this is going to be time-consuming because in the onCreate lifecycle if you call setContentView, the underlying XML2View is going to be passed. So simplify the XML layout code and optimize the layout with ViewStub, include, and merge tags whenever possible. After 16ms, if you receive a refresh message, then onMeasure->onLayout->onDraw is applied to the DecorView. Finally, the Activity’s root layout DecorView is added to the Window and displayed in the SurfaceFlinger.
So in addition to streamlining the XML layout, this step also requires that the measurement, layout, drawing and other functions of the custom View should not be time consuming and cause GC operations. Finally, the TreaceView tool can be used to check the three declaration cycles to further optimize to the limit.
This step gives the interviewer the impression that you have thoroughly researched the whole Activity startup, View drawing and refresh mechanism. This will give the interviewer a good impression that you have extensively studied these source code levels.
Conclusion:
I ended up with a 50% reduction in startup time based on the above optimization.
Interviewer:
Well, research quite deep, usually many source code to see.
Programmer:
At this point, I know that this level is passed!
2. Is there any memory optimization?
Programmer:
Have done, the current project memory optimization is still quite a lot, how about I first say what benefits optimize memory? We can’t blindly optimize!
Sometimes it’s important to take the initiative and lead the interview in areas you’re familiar with.
Interviewer:
You can.
Ps: Most interviewers here will agree to your request, unless there is a fake B.
Programmer:
Benefits:
- Reduce OOM to improve the stability of the program.
- Reduced lag and improved application fluency.
- Reduce the memory usage and improve the activity of application background storage.
- Reduce program exceptions, reduce application Crash rate, and improve stability.
Based on these four points, my program has been optimized as follows:
-
1. Reduce the OOM
LeakCanary is a performance detection tool THAT I like to use during the app development phase. The benefit is that it tells me in real time which class found the memory leak (if you know how LeakCanary works, tell me how it does it).
And why are apps sent to OOM, and how can we avoid them?
If you want to store 2 MB of data into the 1 MB memory space, this will happen.
In the application we should avoid not only scenes that lead directly to OOM but also scenes that lead indirectly to OOM. Indirect words are to avoid memory leak scenarios.
The memory leak scenario is when the object is no longer in use, the application executes its full last life cycle, but for some reason, the object is no longer in use, but it still exists in memory and GC will not reclaim it, which means that a memory leak has occurred. (Here can introduce the GC recycling mechanism, recycling algorithm, knowledge as far as possible to expand beyond the topic)
Finally, here are some scenarios to avoid memory leaks in real development:
-
Resource objects are not closed: Cursor,File
-
Registered object not destroyed: broadcast, callback listening
-
Class static variables hold big data objects
-
Static instance of a non-static inner class
-
Handler Temporary memory leak: use static + weak references, destroy upon exit
-
A memory leak caused by uncleaned objects in the container
-
WebView: Use a separate process
In fact, these are the basics, just write it down. Remember more in the actual development of the impression.
-
-
2. Cut down on lag
How to reduce lag? So we can discuss the root cause of Caton from two principles, the first principle is the drawing principle, and the other is the refresh principle.
-
Drawing principle:
-
Refreshing principle:
View’s requestLayout and ViewRootImpl##setView will eventually call the requestLayout method of ViewRootImpl, Then a drawing task is submitted to Choreographer via scheduleTraversals and a vsync vsync signal is requested via DisplayEventReceiver. When the vsync signal arrives, It will call back through JNI, post an asynchronous task to the message queue through Handler, finally ViewRootImpl to perform the drawing task, and finally call performTraversals to complete the drawing.
Please refer to the following flowchart for detailed process:
Caton’s root cause:
The fundamental principle behind a lag in terms of the refresh principle is that there are two places where frames are dropped:
One is that there are other time-consuming operations on the main thread, so doFrame does not have a chance to call the vsync signal for 16 milliseconds after it is emitted.
Another is that the current doFrame method takes too long to draw, and when the next vsync signal comes, the frame is not finished, resulting in frame loss.
Now that we know the root cause of the lag, we can monitor the lag and optimize the lag to the best of our ability. We can monitor application stalling in four ways:
-
The lag is judged based on the time difference value of Looper’s Printer distributing message.
//1. Enable listening
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
//2. As long as the message is distributed, the message will be printed before and after
public static void loop(a) {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
.
for (;;) {
Message msg = queue.next(); // might block
.
// Print before distribution
final Printer logging = me.mLogging;
if(logging ! =null) {
logging.println(">>>>> Dispatching to " + msg.target + "" +
msg.callback + ":" + msg.what);
}
.
try {
// Distribute messages
msg.target.dispatchMessage(msg);
.
// Print after distribution
if(logging ! =null) {
logging.println("<<<<< Finished to " + msg.target + "" + msg.callback);
}
}
}
Copy the code -
Monitoring is based on the Choreographer callback function postFrameCallback
-
Monitoring is based on the open source framework BlockCanary
-
Monitoring is based on the open source framework Rabbit-Client
How to avoid getting stuck:
It’s important to avoid doing time-consuming tasks in the main thread. Here’s a summary of the main thread scenario in Android:
-
UI lifecycle control
-
Handling system events
-
Message processing
-
Interface layout
-
Interface to draw
-
Interface to refresh
-
.
The most important thing is to avoid memory jitter. Do not allocate and release memory frequently in a short period of time.
There is certainly no problem with catton based on these points.
-
-
3. Reduce the memory usage
It can be explained from the following aspects:
-
AutoBoxing: It can be used in small forms rather than large ones.
-
A memory multiplexing
-
Use the best data type
-
Enumeration type: Replace Enum with annotated enumeration restrictions
-
Image memory optimization (here can talk about how they are designed from Glide and other open source frameworks)
- Select the appropriate bitmap format
- Bitmap memory overcommitment, compression
- Multilevel caching of images
-
If you do not need to modify the basic data type, it is recommended to write static final, because it does not need to initialize work, directly packaged into dex can be used directly, does not need to apply for memory in the class
-
Don’t use += for string concatenation, use StringBuffer or StringBuilder
-
Do not refresh the UI in onMeause, onLayout, onDraw
-
Try to use C++ code to convert to YUV format. Don’t use Java code to convert to RGB or other formats. It really takes up memory
-
-
4. Reduce program exceptions
Reduce program exceptions so we can describe in terms of stability and Crash respectively.
We will introduce the stability and Crash of the program in detail in the fourth point.
If you say these, and then in the actual development of an example of how to solve the problem should be no problem.
3. Have you encountered any lag problems in the project? How do you check for lag? How is it optimized?
Programmer:
There are some examples, such as time-consuming operations in the main thread, frequent creation and destruction of objects resulting in frequent GC collection, layout hierarchy, and so on.
Interviewer:
Well, how do you optimize it?
Programmer:
Here, we can expand the explanation from the display principle and optimization suggestions, as follows:
- Display principle:
-
Drawing principle:
-
Refreshing principle:
View’s requestLayout and ViewRootImpl##setView will eventually call the requestLayout method of ViewRootImpl, Then a drawing task is submitted to Choreographer via scheduleTraversals and a vsync vsync signal is requested via DisplayEventReceiver. When the vsync signal arrives, It will call back through JNI, post an asynchronous task to the message queue through Handler, finally ViewRootImpl to perform the drawing task, and finally call performTraversals to complete the drawing.
Please refer to the following flowchart for detailed process:
-
Caton’s root cause:
The fundamental principle behind a lag in terms of the refresh principle is that there are two places where frames are dropped:
One is that there are other time-consuming operations on the main thread, so doFrame does not have a chance to call the vsync signal for 16 milliseconds after it is emitted.
Another is that the current doFrame method takes too long to draw, and when the next vsync signal comes, the frame is not finished, resulting in frame loss.
Now that we know the root cause of the lag, we can monitor the lag and optimize the lag to the best of our ability. We can monitor application stalling in four ways:
-
The lag is judged based on the time difference value of Looper’s Printer distributing message.
//1. Enable listening
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
//2. As long as the message is distributed, the message will be printed before and after
public static void loop(a) {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
.
for (;;) {
Message msg = queue.next(); // might block
.
// Print before distribution
final Printer logging = me.mLogging;
if(logging ! =null) {
logging.println(">>>>> Dispatching to " + msg.target + "" +
msg.callback + ":" + msg.what);
}
.
try {
// Distribute messages
msg.target.dispatchMessage(msg);
.
// Print after distribution
if(logging ! =null) {
logging.println("<<<<< Finished to " + msg.target + "" + msg.callback);
}
}
}
Copy the code -
Monitoring is based on the Choreographer callback function postFrameCallback
-
Monitoring is based on the open source framework BlockCanary
-
Monitoring is based on the open source framework Rabbit-Client
-
-
How can I make the program run more smoothly
1. Layout optimization:
1.1 Layout optimization analysis tool:
1.2 Optimization scheme:
-
Improved animation performance
- Try not to use tween animation and use property animation instead, because performance monitoring shows that tween redraws very frequently
- Use hardware acceleration to improve rendering speed and achieve smooth animation effects.
-
How to avoid getting stuck:
It’s important to avoid doing time-consuming tasks in the main thread. Here’s a summary of the main thread scenario in Android:
- UI lifecycle control
- Handling system events
- Message processing
- Interface layout
- Interface to draw
- Interface to refresh
- .
There is certainly no problem with catton based on these points.
4. How to ensure the stable operation of the APP?
Programmer:
To ensure the stability of the program we can from memory, code quality, Crash, ANR, background survival knowledge points to expand optimization.
Interviewer:
What exactly did you do?
Programmer:
1. The memory
This can be illustrated by the second point, memory optimization
2. Code quality
- Teams review each other’s code to ensure the quality of the code and to learn the ideas of other colleagues’ code.
- Use Link to scan the code for defects.
3. Crash
- By implementing Thread. UncaughtExceptionHandler interfaces to monitor the abnormal state, global timely upload Crash logs to the background, and through the plug-in package repair in a timely manner.
- Native Online uses Bugly framework to monitor program abnormalities in real time, while offline LAN uses Google’s open source Breakpad framework. When an exception occurs, collect logs and upload them to the server (what should be noted here is the performance problem of log uploading, which will be explained in the power saving module in the back).
4. ANR
5. Background survival
Interviewer:
Well, you’ve got a good grasp of the knowledge.
With that said, this level is also passed.
5. Tell me about your network optimization project?
Programmer:
Yes, this can actually be explained by the OKHTTP connection pool and Http cache (of course, I won’t expand the OKHTTP source code here).
Interviewer:
Tell me more about it
The programmer
Having said that, let’s talk about some of the optimizations you currently use with network frameworks such as OKHTTP(Socket connection pooling, Http caching, chain of responsibility) and Retrofit(dynamic proxy). With all that said, this is usually a pass.
6. What storage methods have you used in your projects? Has their performance been optimized?
Programmer:
Mainly used SP,File,SQLite storage mode. Sp and SQLite are optimized.
Interviewer:
What optimizations have been made?
Programmer:
If you have used other third-party databases, explain how they work and how they are accessed.
7. Have you ever made a custom View in a project? What optimizations have been made to it?
Programmer:
Have done. For example, repeat drawing, and large and long drawings have been optimized.
Interviewer:
Tell me more about it
Programmer:
Finally, I will talk about a specific one based on the real scene.
8. How about the power consumption of your project? Has it been optimized?
Programmer:
The power consumption for 30 minutes is 8% before optimization and 4% after optimization.
Interviewer:
Tell me how you optimized it.
Programmer:
As our product is a social communication software, it has audio and video calls, GPS location report and long connection scenes, so it is a little difficult to optimize. But in the end, I optimized half the battery to go down. The main optimization is as follows:
Having said this, explain it in conjunction with a real optimization point of the project.
9. Have you done log optimization?
Programmer:
With optimizations, I wrote to the file directly from the log without considering any performance before, even though I opened the thread pool to write to the file, as long as the software was running it would frequently make the CPU work. This indirectly leads to power consumption.
Interviewer:
How did you finally solve the problem?
Programmer:
After you’ve expanded on the above points, interviewers will generally not give you a hard time.
How big is your APK? Has APK volume related optimization been done?
Programmer:
There was optimization. Before optimization, the package size of the project was 80M, and after optimization, it was 50M.
Interviewer:
How do you optimize it
Programmer:
Based on these optimization schemes, generally the APK volume problem can be solved. Finally, the project APK volume optimization steps combined with the above point on the line.
conclusion
In fact, performance optimization points are closely related, such as memory, display, and startup will also involve the impact of APK dex. Therefore, performance optimization is not only a unilateral optimization, we must master the most basic optimization scheme, in order to further explore the performance principle.
Here we also establish more popular open source framework source code, such as Glide (memory), OKhttp (network connection) optimization is really extreme. Here the knowledge of performance optimization is finished, down must be good to digest.
All xmind original images click to get
About me
- Email: [email protected]
- Personal blog
- The Denver nuggets
- GitHub
Scan the code to follow my public number, let us further into some!