Android Basics
1, regular knowledge
1. Android class loader
In The Android development, whether the plug-in or the componentization, is based on the Android system ClassLoader to design. But the Virtual machine running on the Android platform is Dex bytecode, a product of class file optimization, the traditional class file is a Java source file will generate a. Class file, and Android is to merge and optimize all class files, Then it is regenerated into a final class.dex, the purpose of which is to keep only one copy of the duplicate of different class files. In the early Android application development, if the Dex of Android applications is not divided, then the APK of the last application will only have one dex file.
There are two types of classloaders commonly used in Android, DexClassLoader and PathClassLoader, both of which inherit from BaseDexClassLoader. The difference is that when the parent class constructor is called, the DexClassLoader passes an extra parameter optimizedDirectory. This directory must be the internal storage path to cache the Dex files created by the system. If this parameter is null for PathClassLoader, only the Dex file of the internal storage directory can be loaded. So we can use a DexClassLoader to load external APK files, which is the basis of many plug-in technologies.
2, the Service
Android services can be understood from the following aspects:
- Service is executed in the main Thread. Time-consuming operations (network requests, database copies, large files) cannot be performed in the Service.
- You can set the process of the Service in the XML so that the Service executes in a different process.
- The maximum number of operations performed by the Service is 20s, the BroadcastReceiver is 10s, and the Activity is 5s.
- Activities are bound to services through bindService (Intent, ServiceConnection, flag).
- An Activity can start a Service with startService and bindService.
IntentService
IntentService is an abstract class that inherits from Service and contains a ServiceHandler (Handler) and HandlerThread (Thread). IntentService is dealing with a class of asynchronous request, there is a job in the IntentService thread (HandlerThread) to handle the time-consuming operation, start the IntentService way and ordinary, but after when performing the tasks, IntentService stops automatically. In addition, IntentService can be started multiple times, and each time-consuming operation will be executed as a work queue in the IntentService’s onHandleIntent callback, one worker at a time. IntentService is an asynchronous framework that encapsulates handlerThreads and handlers.
2.1 schematic diagram of life cycle
As one of the four components of Android, Service is widely used. Like activities, services have a series of lifecycle callbacks, as shown below.
In general, there are two ways to start a Service: startService and bindService.
2.2 life cycle of startService
When we start the Service by calling the startService method of the Context, the Service started by the startService method will run indefinitely. The Service will only stop running and be destroyed if the Context stopService is called externally or if the Service stopSelf method is called internally.
onCreate
OnCreate: When the startService method is executed, the Service is created if it is not running and the onCreate callback method of the Service is executed; If the Service is already running, executing the startService method does not execute the onCreate method of the Service. That is, if the startService method of the Context is executed multiple times to start the Service, the onCreate method of the Service method will only be called once the first time the Service is created, and will never be called again. We can do some Service initialization in the onCreate method.
onStartCommand
OnStartCommand: After the startService method is executed, it is possible to call the onCreate method of the Service, which must be followed by the onStartCommand callback method of the Service. That is, if the startService method of the Context is executed multiple times, then the onStartCommand method of the Service will also be called multiple times. The onStartCommand method is important because it’s where we do the actual operations based on the Intent parameter passed in, such as creating a thread here to download data or play music.
public @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {
}
Copy the code
When Android is running out of memory, it may destroy the Service you are currently running, and then re-create the Service when memory is sufficient. The behavior of the Service being forcibly destroyed and rebuilt by Android depends on the return value of the onStartCommand method in the Service. There are three common return values, START_NOT_STICKY, START_STICKY, and START_REDELIVER_INTENT, which are static constants in the Service.
START_NOT_STICKY
If START_NOT_STICKY is returned, the Service will not be recreated after the process in which it is running has been forcibly killed by Android. Of course, if startService is called some time after it has been killed, the Service will be instantiated again. So what’s a good situation to return this value? We can set the return value of onStartCommand to START_NOT_STICKY if it is not important for a Service to perform work that is interrupted several times or if it needs to be killed and not recreates immediately in the case of Android memory constraints. For example, if a Service needs to obtain the latest data from the server on a regular basis, a timer is used to start the Service every N minutes to obtain the latest data from the server. When the onStartCommand of the Service is executed, schedule a timer within the method for N minutes to start the Service again and create a new thread to perform network operations. Assuming that the Service is forcibly killed by Android in the process of retrieving the latest data from the server, the Service will not be recreated, which is ok because the timer will start the Service again in N minutes and retrieve the data again.
START_STICKY
If START_STICKY is returned, Android will keep the Service in the started state after the process was forcibly killed. Instead of saving the intent object passed in by the onStartCommand method, Android tries to recreate the Service again and executes the onStartCommand callback method with the intent parameter null. The onStartCommand method executes but does not get the intent information. If your Service can run and end at any time without any problems, and doesn’t need intent information, you can return START_STICKY in the onStartCommand method. For example, a Service that plays background music is a good fit.
START_REDELIVER_INTENT
If START_REDELIVER_INTENT is returned, Android will re-create the Service after the process was forcibly killed. If START_REDELIVER_INTENT is returned, Android will re-create the Service. And execute the onStartCommand callback method, but the difference is, Android will take the Intent that was passed to the onStartCommand method the last time the Service was killed and pass it back to the onStartCommand method of the newly created Service so that we can read the Intent parameter. As long as START_REDELIVER_INTENT is returned, the onStartCommand weight must not be null. If a Service needs to rely on an Intent to run (read data from the Intent, etc.) and needs to be re-created to run after being forced to destroy it, then it is appropriate to return START_REDELIVER_INTENT.
onBind
The onBind method in a Service is abstract, so the Service class itself is abstract, which means that the onBind method must be overridden, even if we don’t need it. When using a Service with startService, we override the onBind method by simply returning null. The onBind method is primarily used to call Service to the bindService method.
onDestroy
onDestroy: A Service started with the startService method runs indefinitely and is only stopped and destroyed when the stopService of the Context is called or when the stopSelf method is called inside the Service. The Service callback is executed upon destruction.
2.3 bindService Life Cycle
The onCreate () :
This method is called when the service is first created. If the service is already running, this method is not called and is called only once.
OnStartCommand () :
This method is called when another component requests to start the service by calling startService().
OnDestroy () :
This method is called when the service is no longer in use and will be destroyed.
OnBind () :
This method is called when another component is bound to a service by calling bindService().
OnUnbind () :
This method is called when another component unbinds the service by calling unbindService().
OnRebind () :
This method is called when the old component is unbound from the service and a new component is bound to the service, with onUnbind() returning true.
3, fragemnt
3.1 Creation method
(1) Static creation
First we need to create an XML file, then we need to create the corresponding Java file, which is associated with the onCreatView() return method, and finally we need to configure parameters in the Activity, that is, the location of the fragment in the Activity XML file.
<fragment
android:name="xxx.BlankFragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
</fragment>
Copy the code
(2) Dynamic creation
The steps for dynamically creating fragments are as follows:
- Example Create a fragment instance to be added.
- Get FragmentManager, can be directly in the Activity by calling getSupportFragmentManager () method.
- Start a transaction by calling the beginTransaction() method.
- To add or replace a fragment to a container, use the repalce() method and pass in the container ID and the fragment instance to be added.
- Commit the transaction by calling the commit() method.
3.2 Adapter comparison
FragmnetPageAdapter in each switch page, just Fragment separation, suitable for page less Fragment use to save some memory, system memory will not have much impact.
FragmentPageStateAdapter in each switch page, is the Fragment recycling, suitable for the page more Fragment use, so that it will not consume more memory
3.3. Activity Lifecycle
The life cycle of an Activity is shown below:
(1) Dynamic loading:
During dynamic loading, the fragment is loaded and its lifecycle method is called after the Activity’s onCreate() call, so the first lifecycle method onAttach() gets the Activity and its layout components;
(2) Static loading:
The fragment cannot retrieve components in the layout of the Activity, but why can it retrieve the Activity?
2. There is also a method onInflate() called before the fragment calls onAttach(). When this method is called, the fragment is already attached to the Activity, so it can access it, but the Activity’s onCreate() call has not yet completed. The component of the Activity cannot be obtained.
3. When the Activity’s onCreate() call is complete, the fragment calls the onActivityCreated() lifecycle method, so you can start here to get the component of the Activity’s layout;
3.4 Communicate with the Activity
The reason fragment does not pass values through the constructor is because the landscape switch does not retrieve values.
The Activity passes values to the Fragment:
The Activity passes values to the Fragment and places them in the bundle object. Create the Fragment object for this Fragment in your Activity and pass it to the Fragment by calling setArguments(); You can get the value inside the Fragment by calling getArguments() to get the bundle object.
Fragment Sending values to an Activity:
The first:
Call getFragmentManager() in the Activity to get the fragmentManager, call findFragmentByTag(tag) or pass findFragmentById(ID), for example:
FragmentManager FragmentManager = getFragmentManager(); Fragments fragments = fragmentManager. FindFragmentByTag (tag);Copy the code
The second:
Define an interface (which can be defined in the Fragment class) with an empty method in the interface. Call the method of the interface when needed in the Fragment, put the value in the method as an argument, and then have the Activity implement the interface, overriding the method. The value is then passed to the Activity
How to pass values between fragments:
The first:
FindFragmentByTag gets you another Fragment object, so you can call another method.
The second:
Through the interface callback mode.
The third:
Through setArguments, getArguments.
3.5 API Differences
add
One is the add method to show and add. This way, you can switch the fragment and it will not refresh the fragment. It will only call onHiddenChanged(Boolean isHidden).
replace
Replace causes the fragment to refresh because add hides the fragment instead of destroying it and creating it again. Replace recreates the fragment every time.
commit/commitAllowingStateLoss
Both can submit fragments. The only difference is that the second method allows for the loss of some interface state and information. Almost all developers have encountered this error: The activity cannot commit () after onSaveInstanceState has been called. This exception is understandable. The interface is reclaimed by the system, and the system saves all the state of the interface for us to restore when we open it next time. It is theoretically not allowed to modify the interface at this time, so to avoid this exception, use the second method.
3. The lazy loading
One of the problems we run into when we use fragments, often in conjunction with a ViewPager, is that when we initialize the fragment, we execute it with the network request that we’re writing, which is very performance consuming. Ideally, only when the user clicks or slides to the current fragment, To request the network. Hence the term lazy loading.
Viewpager is used with fragments. The first two fragments are loaded by default. It is easy to cause network packet loss and congestion.
There is a setUserVisibleHint method in the Fragment, and this method is superior to the onCreate() method. It will tell us through isVisibleToUser whether the current Fragment is visible to us, and we can network load it when it is.
SetUserVisibleHint () is called before onCreateView, so if setUserVisibleHint () is to be lazy loaded, you must make sure that the View and other variables are initialized and avoid null Pointers.
Use steps:
Declare a variable isPrepare=false, SetUserVisibleHint (Boolean isVisible) indicates whether the current page isVisible or not Set isVisible=true to determine whether isPrepare and isVisible are true to start loading data, then restore isPrepare and isVisible to false to prevent repeated loading.
For more information on lazy loading of Android Fragments, see the following link: Lazy Loading of Android Fragments
4, the Activity
4.1. Activity Startup process
The user clicks the application icon from the Launcher program to launch the entry Activity of the application. When the Activity starts, it needs the interaction between multiple processes. In the Android system, there is a Zygote process dedicated to incubating the process of the Android framework layer and the application layer. There is also a system_server process that runs many binder services. For example, ActivityManagerService, PackageManagerService, and WindowManagerService. These binder services run in different threads. ActivityManagerService manages the Activity stack, application process, and task.
Click the Launcher icon to launch the Activity
When the user clicks on the application icon in the application Launcher, it tells ActivityManagerService to start the application’s entry Activity. When ActivityManagerService finds that the application has not started yet, it tells the Zygote process to incubate the application. Then execute the Main method of the ActivityThread in the Dalvik application process. The application process then notifies ActivityManagerService that the application process is started. ActivityManagerService holds a proxy object for the application process so that ActivityManagerService can control the application process through this proxy object. ActivityManagerService then notifies the application process to create an instance of the entry Activity and execute its lifecycle methods.
Android drawing process window start process analysis
4.2. Activity Lifecycle
(1)
Active/Running:
An Activity is active. The Activity is on the top of the stack, visible, and can interact with the user.
Paused:
An Activity becomes Paused when it loses focus, is placed by a new, non-full-screen Activity, or is placed on top of the stack by a transparent Activity. However, the Activity only loses the ability to interact with the user. All of its state information and its member variables still exist and can only be reclaimed by the system when memory is tight.
Stopped:
When an Activity is completely overwritten by another Activity, the overwritten Activity enters the Stopped state, where it is no longer visible, but retains all of its state information and its member variables just as Paused state does.
Killed:
An Activity is in the Killed state when it is recovered by the system.
Activities switch between these four forms, and how they do so varies depending on what the user is doing. Now that you’ve seen the four forms of Activity, let’s talk about the Activity lifecycle.
The lifecycle of an Activity
A typical life cycle is an Activity that goes through the normal life cycle of creation, running, stopping, and destruction with user participation.
onCreate
This method is called when the Activity is created. It is the first method called in the lifecycle. We usually override this method when we create an Activity.
onStart
This method is called back to indicate that the Activity is starting. The Activity is already visible, but not in the foreground and therefore unable to interact with the user. This simply means that the Activity is displayed and we can’t see the pendulum.
onResume
When this method calls back, the Activity is visible in the foreground and ready to interact with the user (in the Active/Running form described earlier). The onResume method is similar to onStart in that both indicate that the Activity is visible. When the onStart callback is called, the Activity still cannot interact with the user in the background, while onResume is displayed in the foreground and can interact with the user. Of course, we can also see from the flowchart that the onResume method is called when the Activity comes back to the foreground after it has been stopped (onPause and onStop methods have been called), so we can initialize some resources in the onResume method as well. For example, reinitialize resources released in onPause or onStop methods.
onPause
When this method is called, it indicates that the Activity is stopping (Paused). Normally, the onStop method is called right after. If the onResume method is executed immediately after the onPause method is executed, the onResume method will be called back. If the onPause method is executed immediately after the onPause method is executed, the onResume method will be called back. Of course, we can do some data storage or animation stopping or resource reclaiming in the onPause method, but it should not take too long because it may affect the display of the new Activity — the onResume method of the new Activity will not be executed until the onPause method is finished.
onStop
When the onPause method is executed, the Activity is either Stopped or completely overwritten (Stopped form). At this time, the Activity is not visible and only runs in the background. Similarly, you can do some resource release in the onStop method (not too time-consuming).
onRestart
Indicates that the Activity is restarting. This method is called back when the Activity changes from invisible to visible. When the user starts a new Activity, the current Activity is paused (onPause and onStop are executed), and then returns to the current Activity page, the onRestart method is called back.
onDestroy
At this point, the Activity is being destroyed and is the last method executed in the lifecycle, so we can usually do some recycling and final resource release in this method.
summary
To summarize, when an Activity starts, onCreate(),onStart(),onResume() are called in turn, and when the Activity is in the background (invisible, click Home, or completely overwritten by a new Activity), OnPause () and onStop() are called in turn. OnRestart (), onStart(), and onResume() are called in turn when the Activity is brought back to the foreground (from the desktop or when it has been overwritten). When the Activity exits destruction (by clicking the Back key), onPause(), onStop(), and onDestroy() are called in turn, and the callback for the entire lifecycle of the Activity is complete. Now let’s go back to the flow chart. It should be pretty clear. Well, that’s the typical lifecycle of an Activity.
2, View part of knowledge points
The relationship between an Android Activity, A PhoneWindow, and a DecorView can be represented by the following diagram:
DecorView (DecorView
For example, if you have the following View, DecorView is the top View of the entire Window interface, and it has only one child, LinearLayout. Represents the entire Window interface, including notification bar, title bar, and content display bar. There are two FrameLayout children in the LinearLayout.
The role of DecorView
DecorView is a top-level View, which is essentially a FrameLayout and it has two parts, the title bar and the container bar, which are both FrameLayout. The content bar id, which is the part of the activity that sets the setContentView, adds the layout to the FrameLayout with the ID content. Get content: ViewGroup Content =findViewById (Android.id.content) Get the set View: getChildAt(0).
Used to summarize
Each Activity contains a Window object, which is typically implemented by PhoneWindow. PhoneWindow: Sets the DecorView to the root View of the entire application Window, which is the implementation class of Window. It is the most basic windowing system in Android. Every Activity creates a PhoneWindow object, which is the interface between the Activity and the entire View system. DecorView: is the top-level View that renders the specific contents to be displayed on the PhoneWindow. DecorView is the ancestor of all the views in the current Activity and does not present anything to the user.
2.2 Event distribution of View
The event distribution mechanism of View can be shown in the following figure:
- Events start with the white arrow in the upper left corner and are distributed by the Activity’s dispatchTouchEvent
- The top word of the arrow represents the method return value, (return true, return false, return super.xxxxx(), where super means to call the superclass implementation.
- There is a “true—-> Consume” in the dispatchTouchEvent and onTouchEvent boxes, which means that if the method returns true, the event will be consumed and will not be sent anywhere else.
- At present, all graph events are for ACTION_DOWN, and ACTION_MOVE and ACTION_UP are analyzed at last.
- The Activity in the previous diagram had an incorrect dispatchTouchEvent(the diagram has been fixed). Only return super.DispatchTouchEvent (EV) will go down and return true or false to consume the event (the transmission is terminated).
ViewGroup Event distribution
When a click event occurs, it is passed in the following order:
Activity -> Window -> View
The event is always passed to the Activity, which in turn is passed to the Window, which in turn is passed to the top-level View, which receives the event and distributes it according to the event dispatch mechanism. If a View’s onTouchEvent returns FALSE, the onTouchEvent of its parent container will be called, and so on. If none of them handle the event, the Activity will handle it.
The ViewGroup event distribution process looks something like this: If the top-level ViewGroup intercepting event (onInterceptTouchEvent) returns true, the event will be given to the ViewGroup. If the ViewGroup’s onTouchListener is set, then onTouch will be called. Otherwise, onTouchEvent will be called. In other words, onTouch will mask onTouchEvent if both are set, and onClick will be called if onClickerListener is set. If the top-level ViewGroup does not intercept, then the event will be passed to its click event subview and the subview’s dispatchTouchEvent will be called
View event distribution
dispatchTouchEvent -> onTouch(setOnTouchListener) -> onTouchEvent -> onClick
The difference between onTouch and onTouchEvent is that both of them are called within dispatchTouchEvent, onTouch takes precedence over onTouchEvent, and if onTouch returns true, then onTouchEvent is not executed, And onClick are not executed.
2.3 Drawing of View
In an XML layout file, our layout_width and layout_height arguments can be wrap_content or match_parent instead of the specific size. These two Settings do not specify the actual size, but the View we draw onto the screen must have a specific width and height, and because of this, we have to handle and set the size ourselves. Of course, the View class gives the default handling, but if the View class’s default handling doesn’t meet our requirements, we have to override the onMeasure function.
The onMeasure function is an int that contains the measurement mode and size. An int takes 32 bits, but Google uses the first two bits of the int to distinguish between different layout patterns, and the last 30 bits to store the size of the data. The onMeasure function is used as follows:
Match_parent – > EXACTLY. How do you understand that? So match_parent is just going to take advantage of all the remaining space that the parent View gives us, and the remaining space of the parent View is defined, which is the size that’s stored in the integer of this measurement mode.
Wrap_content – > AT_MOST. If we want to set the size to wrap the contents of our view, then the size is the size that the parent view gives us as a reference, as long as it does not exceed this size, the specific size can be set according to our needs.
Fixed size (e.g. 100dp) — >EXACTLY. The user specified the size, we do not need to interfere, of course, is the size of the specified.
2.4 drawing ViewGroup
Customizing a ViewGroup isn’t that easy, because it has to manage not only its own views but also its subviews. We all know that a ViewGroup is a View container that holds a Child View and is responsible for putting the Child View in the specified location.
-
First, we need to know the size of each subview. Only by knowing the size of the subview will we know how big the current ViewGroup should be set to accommodate them.
-
The size of the ViewGroup depends on the size of the child View and what function our ViewGroup is trying to implement
-
Now that you have the size of the ViewGroup and the child View, the next thing to do is to place it. How do you place it? For example, you want the child views to be placed next to each other in vertical order, or on top of each other in sequential order. That’s up to you.
-
Already know how to put is not good ah, decided how to put is equivalent to the existing space “split” into large and small space, each space corresponds to a child View, we next is to put the child View, put them in their place to go.
For details about how to customize a ViewGroup, see Android Custom ViewGroup
3. System principle
3.1 Packaging principle
The Android package file APK is divided into two parts: code and resources, so the packaging aspect is also divided into resource packaging and code packaging two aspects, this article will analyze the compilation and packaging of resources and code principles.
To be specific:
- Through AAPT tool, resource files (including Androidmanifest.xml, layout files, various XML resources, etc.) are packaged and r.java files are generated.
- The AIDL file is processed by the AIDL tool to generate the corresponding Java file.
- Compile the project source code through the Javac tool to generate the Class file.
- All Class files are converted into DEX files by DX tool. This process mainly completes the conversion of Java bytecode to Dalvik bytecode, compression of constant pool and removal of redundant information.
- Use ApkBuilder to package the resource file and DEX file to generate an APK file.
- Use the KeyStore to sign the generated APK file.
- The ZipAlign tool is also used to align all the resource file examples in the APK file by an integer multiple of 4 bytes, so that the APK file can be accessed faster through memory mapping.
3.2 Installation Process
The installation process of Android APK consists of the following steps:
- Copy the APK file to the /data/app directory, decompress the APK file, and scan the installation package.
- Resource manager parses the resource files in APK.
- Parse the AndroidManifest file and create the corresponding application data directory under /data/data/.
- Then optimize the dex file and save it in the Dalvik-cache directory.
- Register the four components parsed in the AndroidManifest file to the PackageManagerService.
- When the installation is complete, broadcast is sent.
This can be represented by the following diagram:
4. Third-party library parsing
4.1 Retrofit Network request Framework
Concept: Retrofit is a RESTful encapsulation of the HTTP web request framework, where the essence of the web request is done by OKHttp, and Retrofit is only responsible for the encapsulation of the web request interface.
Principle: The App requests the network through Retrofit, essentially using the Retrofit interface layer to encapsulate the request parameters, headers, URLS, and so on, and then OKHttp completes the subsequent request. After the server returns the data, OKHttp delivers the original results to Retrofit. Finally, the results are analyzed according to the needs of users.
Retrofit using
1. Use an interface in Retrofit as an API for HTTP requests
public interface NetApi {
@GET("repos/{owner}/{repo}/contributors")
Call<ResponseBody> contributorsBySimpleGetCall(@Path("owner") String owner, @Path("repo") String repo);
}
Copy the code
Create a Retrofit instance
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
Copy the code
3. Invoke the API
NetApi repo = retrofit.create(NetApi.class); / / step 3: Call a network interface to get network request retrofit2. Call < ResponseBody > Call = repo. ContributorsBySimpleGetCall ("username"."path"); Call.enqueue (new Callback<ResponseBody>() {@override public void onResponse(call <ResponseBody> call, } @override public void onFailure(Call<ResponseBody> Call, Throwable t) {// execute error callback method}});Copy the code
Retrofit dynamic proxy
Retrofit works as follows: 1. First, convert it to ServiceMethod using method. 2. Then, get the okHttpCall object through serviceMethod, args. 3. Finally, we further wrap okHttpCall and return the Call object. First, create a Retrofit object as follows:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
Copy the code
The build() method is used to create the Retrofit object, which is implemented as follows:
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if(callFactory == null) { callFactory = new OkHttpClient(); // Set kHttpClient} Executor callbackExecutor = this.callBackExecutor;if(callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); } // Make a copy of the adapters and add the default Call adapter. List< callAdapter.factory > adapterFactories = new ArrayList<>(this.adapterFactories); adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); // Make a defensive copy of the converters. List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);returnnew Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly); // Return the new Retrofit object}Copy the code
This method returns a Retrofit object that creates the interface to the network request as follows:
NetApi repo = retrofit.create(NetApi.class);
Copy the code
The create() method of the Retrofit object is implemented as follows: ‘
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return(T) Proxy.newProxyInstance(service.getClassLoader(), new Class<? >[] { service }, newInvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
returnmethod.invoke(this, args); // Call the method directly}if (platform.isDefaultMethod(method)) {
returnplatform.invokeDefaultMethod(method, service, proxy, args); // Call the method from the platform object} ServiceMethod ServiceMethod = loadServiceMethod(method); // Get the ServiceMethod object OkHttpCall OkHttpCall = new OkHttpCall<>(ServiceMethod, args); // Pass arguments to generate an okHttpCall objectreturnserviceMethod.callAdapter.adapt(okHttpCall); // Execute okHttpCall}}); }Copy the code
4.2. Image loading library comparison
Picasso was: 120 k
Glide: 475 k
Fresco: 3.4 M
Android – Universal – Image – Loader: 162 k
The selection of the image library depends on the specific situation of the APP. For apps that rely heavily on the image cache, such as wallpaper and photo social apps, you can choose the most professional Fresco. For the general APP, Fresco will be a heavy choice, after all, Fresco 3.4m volume is placed here. The above libraries can be sorted according to the APP’s requirements for image display and cache from the lowest to the highest.
Picasso < Android-Universal-Image-Loader < Glide < Fresco
2. Introduction:
Picasso: Works best with Square’s network library, since Picasso can optionally hand over cached portions of network requests to the OKHTTP implementation.
Glide: Mimics Picasso’s API and adds a lot of extensions (such as GIF support) to it. Glide’s default Bitmap format is RGB_565, which has half the memory overhead of Picasso’s default ARGB_8888 format. Picasso caches the full size (only one cache), while Glide caches the same size as ImageView (5656 and 128128 are two caches).
FB image loading framework Fresco: The biggest advantage is bitmap loading below 5.0 (minimum 2.3). On systems below 5.0, Fresco places images in a special memory area (the Ashmem area). Of course, when the image is not displayed, the memory will be automatically freed. This will make the APP smoother and reduce the OOM impact caused by image memory usage. After 5.0, the system is stored in Ashmem by default.
3. Conclusion:
Glide can do anything Picasso can do, except for the different Settings required. However, Picasso is much smaller than Glide. If the web request itself used okHTTP or Retrofit (essentially okHTTP), then it would be much smaller to suggest Picasso (Square’s family bucket work). Glide is good for large image streams, such as GIFs, videos, and if you are working on a Video application, it is recommended to use it.
Fresco’s memory optimization below 5.0 is very good, but the price is also very large in size, Fresco>Glide>Picasso
However, it’s a bit cumbersome to use (tip: it can only use the built-in ImageView, which is a bit cumbersome to use, so we usually use Fresco’s own Bitmap layer).
4.3 Use of various JSON parsing libraries
Refer to the link: www.cnblogs.com/kunpengit/p…
(1) Google’s Gson
Gson is currently the most versatile Json parsing artifact. Gson was originally developed by Google to meet the internal needs of Google, but since its first release in May 2008, it has been used by many companies or users. Gson application is mainly toJson and fromJson conversion functions, no dependency, no need to exception additional JAR, can run directly on the JDK. Before using this kind of object conversion, you need to create the object type and its members before you can successfully convert the JSON string to the corresponding object. As long as there are get and set methods in the class, Gson can completely convert complex types of JSON to beans or beans to JSON, which is the artifact of JSON parsing. Gson is fine in terms of functionality, but performance is not as good as FastJson.
(2) Alibaba’s FastJson
Fastjson is a high-performance JSON processor written in Java language, developed by Alibaba.
No dependencies, no need to exception extra JARS, can run directly on the JDK. FastJson has some problems with converting Json from beans of complex types. The type of the reference may appear, resulting in errors in the Json conversion and the need to specify the reference. FastJson uses ingenious algorithms to speed Parse to the Max, outpacing all json libraries.
In summary, the comparison of Json technology above makes it possible to use Google’s Gson and Alibaba’s FastJson in parallel when selecting a project. If only functional requirements but no performance requirements are required, Google’s Gson can be used. If you have performance requirements above, you can use Gson to convert beans into JSON to ensure correct data, and FastJson to convert JSON into beans
5. Hot technology
See link – Android componentization Solution
5.1 componentization
(1) Concept:
Modular: An APP is divided into multiple modules, each module is a component, or it can be a base library for component dependency, development can be independently debug some components, components do not need to depend on each other but can call each other, the final release of all components in the form of lib by the main APP project dependency package into an APK.
(2) Origin:
- APP versions are iterated, new functions are added constantly, and services become complicated with high maintenance costs
- Business coupling degree is high, code is bloated, team internal multi-person collaboration development is difficult
- Android compiler code is slow, code coupling is serious in a single project, and a modification needs to be recompiled and packaged, which takes time and effort.
- Convenient unit testing, a separate business module, do not need to focus on other modules.
(3) Advantages:
- Componentization separates generic modules and manages them in a unified way to improve reuse. It splits pages into smaller components that contain UI implementations and can also contain data and logic layers
- Each component can be compiled independently, speed up compilation, and packaged independently.
- Modifications within each project will not affect other projects.
- Business library projects can be quickly split off and integrated into other apps.
- Business module with frequent iteration adopts component mode, business line research and development can not interfere with each other, improve collaboration efficiency, control product quality, and strengthen stability.
- In parallel development, team members only pay attention to their own development of small modules, reduce the coupling, convenient maintenance, and so on.
(4) Questions to consider:
Mode switching: How can I switch between single debugging and overall debugging
Each module of a componentized service can be a separate APP (isModuleRun=false). When releasing a package, each module is a lib dependency, which is completely controlled by a variable. In the root project gradle.properties isModuleRun=true. The isModuleRun state is different, and the application and AndroidManifest are loaded differently to distinguish between independent APK and lib.
In build.grade:
Resource conflict
When we create multiple modules, how to solve the conflict of merging the same resource file name? The business Module and the BaseModule resource file have the same name. The solution is:
Each module has app_name. To prevent resource names from being the same, add resourcePrefix “xxX_” to the build.gradle of each component to forcibly check the prefix of resource names. Fix the resource prefix for each component. However, the resourcePrefix value can only limit resources in XML, not image resources.
dependencies
How do modules refer to common library and utility classes
Component communication
After componentization, modules are isolated from each other, and how to make UI jump and method call can be specified by using alibaba ARouter or Meituan WMRouter and other routing frameworks.
Service modules do not need any dependencies before and can be perfectly coupled between services through routing.
Entrance parameters
We know that components are related, so how do we get parameters passed by other modules when debugging separately
Application
When components run separately, each Module has its own APK, which means multiple applications. Obviously we don’t want to write so much code over and over again, so we just need to define a BaseApplication. Other applications inherit from this BaseApplication. BaseApplication can also define common parameters.
For how to carry out componentization, please refer to: Anjuke Android Project Architecture evolution
5.2 plug-in
Reference link – Getting Started with plugins
(1) Overview
When it comes to pluginization, we have to mention the problem that the number of methods exceeds 65535, which can be solved by Dex subcontracting or plug-in development. The concept of plug-in is that the host APP loads and runs the plug-in APP.
(2) Advantages
In a large project, in order to clarify the division of labor, different teams are often responsible for different plug-in apps, so that the division of labor is more clear. Each module is encapsulated into a different plug-in APK, and different modules can be compiled separately, improving the development efficiency. Solves the above problem of the number of methods exceeding the limit. A “hot fix” can be achieved by launching new plugins to solve online bugs. The volume of host APK is reduced.
(3) Disadvantages
Add-on apps are not available on Google Play, which means there is no overseas market.
6. Screen adaptation
6.1 Basic Concepts
The screen size
Meaning: The diagonal of a mobile phone is measured in inches. One inch equals 2.54cm
Common Android phone sizes are 5 “, 5.5 “, 6 “, 6.5 “and so on
Screen resolution
Meaning: Mobile phone in the horizontal, vertical total number of pixels
Generally described as “width x height” =AxB what it means: The screen has A pixels in the horizontal direction (width) and A pixels in the vertical direction
(height) has B pixels Example: 1080×1920, that is, there are 1080 pixels in the width direction and 1920 pixels in the height direction
Unit: px (pixel), 1px=1 pixel
UI designers will use px as a uniform unit of measurement in their drawings
Common resolution of Android phone: 320×480, 480×800, 720×1280, 1080×1920
Screen pixel density
Dpi (dots per ich)
Assuming 160 pixels per inch in the device, the screen pixel density of the device =160dpi
6.2 adaptation method
1. Support for various screen sizes: use WRap_content, match_parent, weight. To ensure that the layout is flexible and accommodates screens of various sizes, use “WRap_Content” and “match_parent” to control the width and height of certain view components.
2. Use relative layouts and disable absolute layouts.
3. Use the weight attribute of LinearLayout
What if instead of having a width of 0dp(wrap_content has the same effect as 0dp), we have a width of match_parent?
What android:layout_weight really means is that if the View has this property set and is valid, the width of the View is equal to the original width (Android :layout_width) plus the percentage of the remaining space.
Let’s explain the above phenomenon from this perspective. In the code above, we set the width of each Button to match_parent. Assuming the screen width is L, then each Button should also have the width L, and the remaining width is equal to L- (L+L) = -L.
The weight of Button1 =1 and the remaining width ratio of Button1 is 1/(1+2)= 1/3, so the final width is L+1/3*(-L)=2/3L. The calculation of Button2 is similar, and the final width is L+2/3(-L)=1/3L.
4. Use.9 pictures
6.3 Toutiao screen adaptation
Reference link: Toutiao screen adaptation ultimate version
7. Performance optimization
The performance of Android is optimized from the following aspects: Stability (memory overflow, crash) Smooth (lag) consumption (power consumption, traffic) Installation package (APK thin) There are many reasons that affect the stability of an application. For example, improper memory usage, inconsiderate code exceptions, and unreasonable code logic all affect the stability of an application. Two of the most common are Crash and ANR, which make the program unusable. Therefore, perform global Crash monitoring to handle the flash exit and collect and record Crash information and exception information for subsequent analysis. Use the main thread reasonably to process business, do not do time-consuming operations in the main thread, to prevent ANR program without response.
(1) Stability — memory optimization
(1) Memory Monitor
It’s a memory monitoring tool that comes with Android Studio, and it’s a great way to do real-time memory analysis. Click the Memory Monitor TAB in the lower right corner of Android Studio, open the tool, and you can see that the light blue part represents free Memory, and the dark part represents the transformation of the Memory from the Memory transformation graph, which can judge the state of Memory usage. For example, when the Memory continues to increase, Memory leaks may occur. When memory is suddenly reduced, things like GC can happen, as shown in the figure below.
LeakCanary Tool: LeakCanary is an open source framework for Monitoring Android memory leaks based on MAT developed by Square. Here’s how it works: The monitoring mechanism uses Java WeakReference and ReferenceQueue to package the Activity into WeakReference. If the Activity object wrapped by WeakReference is recycled, The WeakReference reference will be put into the ReferenceQueue. By monitoring the contents in the ReferenceQueue, we can check whether the Activity can be recycled (it can be recycled in the ReferenceQueue, there is no leak; Otherwise, there may be a leak, LeakCanary is performing a GC, and if it is not already in the ReferenceQueue, it will be considered a leak).
If the Activity is determined to be leaked, grab the memory dump file (debug.dumphprofdata); After HeapAnalyzerService. Analyze runAnalysis memory file analysis; The memory leak analysis is then performed with the HeapAnalyzer (checkForLeak — findLeakingReference– findLeakTrace). Finally, display the memory leak through DisplayLeakService.
Android Lint:
Android Lint Tool is an Android code hint Tool integrated with The Android Sutido. It can give you very powerful help with layout and code. Hard-coding prompts with level warnings, such as writing a three-layer redundant LinearLayout layout in the layout file, writing text to display directly in TextView, and using font sizes in DP instead of SP, will prompt you on the right side of the editor.
(2) Fluency — Caton optimization
Caton’s scenarios usually occur in the most immediate aspect of the user’s interactive experience. The two main factors that affect the caton are interface drawing and data processing.
Interface drawing: The main reasons are the deep level of drawing, the complexity of the page, and the unreasonable refresh. Due to these reasons, the scene that is stuck more appears in the UI, the initial interface after startup, and the drawing of the jump to the page.
Data processing: The reason for this kind of lag is that the amount of data processing is too large, which is generally divided into three cases: first, the data is processed in the UI thread; second, the data processing occupies a high CPU, which leads to the main thread can not get the time slice; third, the increase of memory leads to frequent GC, which leads to lag.
(1) Layout optimization
In The Android system, the View is measured, laid out and drawn by traversing the number of views. If the number of views is too high, it can seriously affect the speed of measurement, layout, and drawing. Google also recommends in its API documentation that views should be no higher than 10 layers. Google uses a RelativeLayout layout to reduce the height of the nested layout tree and improve UI rendering efficiency.
Layout reuse, using labels to reuse layout; Improve display speed and use delayed View loading; Reduce the hierarchy and replace the parent layout with labels; Note that using WRAP_content will increase the calculation cost of measure; Delete useless properties in the control;
(2) Drawing optimization
Overdraw is when a pixel on the screen is drawn multiple times in the same frame of time. In a multi-layered and overlapping UI structure, if the invisible UI is also drawing, some pixel areas will be drawn multiple times, wasting extra CPU and GPU resources. How to avoid overdrawing?
Layout optimization. Remove unnecessary background from XML, remove default background of Window, and display placeholder background image as needed
Custom View optimization. Use canvas.cliprect () to help the system identify areas that are visible and only within these areas will be drawn.
(3) Start optimization
Apps usually have SplashActivity. Optimize the UI layout of SplashActivity and detect frame loss using Profile GPU Rendering.
(3) Saving – power consumption optimization
Before Android5.0, testing an application’s power consumption was cumbersome and inaccurate, but since then Google has introduced an API — Battery Historian — to obtain information about the power consumption on a device. Battery Historian is an Android power analysis tool provided by Google that visually displays how your phone is using electricity. The data can be accessed via input data from a Historian.
Finally, some power consumption optimization methods are provided for reference:
(1) Calculation and optimization. Algorithm, for loop optimization, Switch.. Case alternative if.. Else, avoid floating point operations.
Floating point operation: in the computer, the integer and decimal form is stored in ordinary format, such as 1024, 3.1415926, etc., this has no characteristics, but the accuracy of such numbers is not high, the expression is not comprehensive, in order to be able to have a general representation of the number, the invention of floating point number. Floating-point numbers are expressed somewhat like scientific notation (.×10^), in the form of 0.×10^, in the computer form of.* e ±**), where the first asterisk represents a fixed-point decimal, that is, a pure decimal with the integer part being 0, and the second exponential part is a fixed-point integer. Use this form to express any integer and decimal, for example 1024 can be expressed as 0.1024×10^4, which is.1024e+ 004,3.1415926 can be expressed as 0.31415926×10^1, which is.31415926e+001, which is a floating point number. An operation performed on a floating point number is a floating point operation. Floating-point operations are more complex than regular operations, so computers are much slower to perform floating-point operations than regular operations.
(2) Avoid improper use of Wake Lock.
A Wake Lock is a mechanism that allows the system to sleep. If someone is holding the Lock, the system will not sleep. This means that my program has added this Lock to the CPU so that the system will not sleep. In some cases, failure to do so can lead to problems, such as the problem of instant messaging packets such as wechat stopping Internet access shortly after the screen is off. Wake_Lock is widely used in wechat. In order to save power, the CPU will automatically go to sleep when it is not busy with tasks. Wake_Lock is added to the CPU when a task needs to wake it up for efficient execution. It’s easy to wake up the CPU to work, but it’s easy to forget to release Wake_Lock.
(3) Use Job Scheduler to manage background tasks.
In Android 5.0 API 21, Google provides a component called the JobScheduler API to handle scenarios where a task is performed at a certain point in time or when certain conditions are met. For example, when the user is resting at night or the device is connected to the power adapter and WiFi to start the task of downloading updates. This reduces resource consumption and improves application efficiency.
(4) Installation package – APK thin body
(1) Composition of the installation package
Assets folder. Some configuration files and resource files are stored. Assets does not automatically generate the corresponding ID, but obtains it through the interface of the AssetManager class.
Res. Res is an abbreviation of resource. This directory stores resource files. The corresponding IDS are automatically generated and mapped to.r files.
Meta-inf. The signature information of the application is saved to verify the integrity of the APK file.
Androidmanifest.xml. This file is used to describe the Android application configuration information, some component registration information, permissions, etc.
Classes. Dex. The Dalvik bytecode program is executable on the Dalvik VIRTUAL machine. In general, Android applications are packaged using the DX tool in the Android SDK to convert Java bytecode to Dalvik bytecode.
Resources. Arsc. Records the mapping between resource files and resource ids, and is used to find resources based on resource ids.
(2) Reduce the installation package size
Code obfuscation. Use the IDE’s own proGuard code obfuscator tool, which includes compression, optimization, obfuscation, and more. Resource optimization. For example, using Android Lint to remove redundant resources, minimize resource files, and so on. Image optimization. For example, the use of PNG optimization tools to do compression of the image. Recommend the most advanced compression tool, Googlek open source library Zopfli. If the application version is 0 or older, use the WebP image format. Avoid third-party libraries with duplicate or useless features. For example, Baidu maps can be connected to the basic map, XIFi voice does not need to access offline, and photo library Glide/Picasso, etc. Plug-in development. For example, the function module is placed on the server and downloaded on demand, which can reduce the size of the installation package. You can use the wechat open source file obfuscation tool — AndResGuard. Generally, the APK can be compressed by about 1M.
7.1 Cold Start and Hot Start
Refer to the link: www.jianshu.com/p/03c0fd3fc…
Cold start When an application is started, if no process of the application exists in the system, the system creates a new process and assigns it to the application.
Hot start When you start an application, the process of the application already exists in the system. For example, if you press the Back and Home buttons, the application exits, but the process of the application remains in the background.
The Application class is created and initialized, followed by the MainActivity class (which includes a series of measurements, layouts, and drawings), which is displayed on the interface. Hot start: Start from an existing process. Instead of creating and initializing the Application class, create and initialize the MainActivity class (which includes a series of measurements, layouts, and drawings) and display it on the interface.
The fork in the Zygote process creates a new process; Create and initialize the Application class, create MainActivity; Inflate layout, when onCreate/onStart/onResume method; ContentView measure/ Layout /draw is displayed on the interface.
Cold start optimization reduces the amount of work in the Application and the onCreate() method of the first Activity; Do not involve applications in business operations; Do not perform time-consuming operations in the Application. Do not store data in the Application as static variables; Reduce the complexity and depth of the layout;
MVP architecture
8.1 MVP mode
The MVP architecture evolved from MVC. In MVP, M stands for Model, V for View, and P for Presenter.
Model layer: Capture data functionality, business logic, and entity Model.
View layer: Corresponding to an Activity or Fragment, it is responsible for displaying part of a View and user interaction with business logic
Presenter: Is responsible for the interaction between the View layer and the Model layer. It retrives data from the M layer through the P layer and returns it to the V layer, so that the V layer and M layer are not coupled.
In MVP, the Presenter layer completely separates the View layer from the Model layer, and implements the main program logic in the Presenter layer. There is no direct correlation between the Presenter and the specific View layer (Activity), and they interact with each other by defining interfaces. This allows Persenter to remain unchanged when the View layer (Activity) changes. The View layer interface class should have only the set/get method, some interface display content and user input, and no more content than that. Never allow the View layer to directly access the Model layer. This is the biggest difference from MVC and the core advantage of MVP.
9. Vm
9.1 Comparison between Android Dalvik VM and ART VM
Dalvik
We know that Apk first compiles Java source code into. Class files via Javac, but our Dalvik virtual machine only executes. Dex files. At this point, dx will convert the.class file to the.dex file executed by the Dalvik vm. Dalvik VIRTUAL machine will first convert the. Dex file into fast running machine code when it is started, and because of the problem of 65535, we have a package closing process when the application is cold started, and the final result is that our app starts slowly. This is the Just-in-time (JIT) feature of the Dalvik VM.
ART
ART virtual machine is an Android virtual machine used only in Android5.0. ART virtual machine must be compatible with Dalvik virtual machine features, but ART has a very good feature AOT (Ahead of time), The ART virtual Machine converts the. Dex file into a. Oat file that can be run directly. The ART virtual machine naturally supports multiple dex, so there is no package combination process. Therefore, ART virtual machine can greatly improve the cold startup speed of APP.
ART strengths:
Speed up cold startup of APP
Increase GC speed
Provides comprehensive Debug features
ART faults:
APP installation is slow because running.oAT files need to be generated during APK installation
APK takes up a lot of space because running.oAT files are generated when APK is installed
Arm processor
For a more detailed introduction to ART, please refer to Android ART
conclusion
Familiar with Android performance analysis tools, UI lag, APP launch, package slimming and memory performance optimization
Familiar with Android APP architecture design, modular, componentized, plug-in development
Familiar with Java, design pattern, network, multi-thread technology
Basic Knowledge of Java
1, Java class loading process
The process by which the JVM loads the.class file information into memory and parses it into the corresponding class object. Note: The JVM does not load all classes into memory initially. The JVM loads only the first time it encounters a class that needs to be run, and only once
There are three main parts: 1, loading, 2, link (1. Verification, 2. Preparation, 3. 3. Initialize
1: loading
Class loaders include BootClassLoader, ExtClassLoader, and APPClassLoader
2: link
Validation :(verifies that the byte stream of a class file conforms to the JVM specification)
Preparation: Allocates memory for class variables and assigns initial values
Parsing: The process of replacing symbolic references (variable names) with direct references (memory addresses) in the constant pool. During the parsing phase, the JVM replaces all class names, method names, field names, and symbolic references with specific memory addresses or offsets.
3: initialization
The class constructor is initialized. In other words, only static modifiers or statements are initialized.
Example: Person Person = new Person(); As an example.
Java programming ideas in the class initialization process mainly has the following points:
- Locate the class file and load it into memory
- Allocate memory addresses in heap memory
- Initialize the
- Refers the heap memory address to the stack memory P variable
2, String, StringBuilder, StringBuffer
Many of the methods in StringBuffer add the synchronized keyword to represent thread-safety, so use it in multithreaded situations.
Execution speed:
StringBuilder > StringBuffer > String
Copy the code
StringBuilder trades performance for speed. These two can be modified directly on the original object, eliminating the need to create new objects and recycle old objects. String is final, and the other two are String variables, which cannot be modified once they are created. Variables are modifiable, so working with a String consists of three steps:
- Create a new object with the same name as the original
- Make changes on the new object
- The original object is garbage collected
3. JVM memory structure
During Java object instantiation, the virtual machine stack, Java heap, and method area are used. After compilation, Java files are first loaded into the JVM method area. A heavy part of the JVM method area is the runtime constant pool, which stores the class version, fields, methods, interfaces, and compile-time constants and static constants.
3.1 Basic Structure of the JVM
ClassLoader, which loads the required.class files into memory when the JVM starts or the class runs. The execution engine that executes the bytecode instructions contained in the class file. The native method interface, which mainly calls the local method implemented by C/C++ and returns the result. The memory area (runtime data area) is the memory area allocated during the operation of the JVM. It is mainly divided into the following five parts, as shown in the figure below:
- Method area: a place to store information about a class structure, including constant pools, static variables, constructors, and so on.
- Java heap: The place where Java instances or objects are stored. This is the main region of GC.
- Java stack: A Java stack is always associated with threads. Whenever a thread is created, the JVM creates a Java stack for that thread. This Java stack contains multiple stack frames, and each time a method is run, a stack frame is created to store local variable tables, operation stacks, method return values, and so on. Each method from the call to the completion of the execution corresponds to a stack frame in the Java stack to the stack of the process. So the Java stack is thread private.
- Program counter: The memory address used to hold the current thread execution, because the JVM is multi-threaded execution, so in order to ensure that the thread switch back to the original state, you need a separate counter to record the previous interruption, so the program counter is also thread private.
- Native method stack: Similar to the Java stack, but serves native methods used by the JVM.
3.2. JVM source analysis
www.jianshu.com/nb/12554212
4. GC mechanism
Garbage collectors typically do two things
- Waste is detected;
- Recycling garbage;
4.1 Java object references
In general, references to Java objects fall into four categories: strong references, soft references, weak references, and virtual references. Strong references: Objects that are usually thought of as coming out of new and will not be actively collected by GC even when memory is out.
Object obj = new Object();
Copy the code
Soft reference: When out of memory, it is collected by GC when GC does garbage collection.
Object obj = new Object();
SoftReference<Object> softReference = new SoftReference<>(obj);
Copy the code
Weak references: Garbage collection is collected by GC regardless of whether memory is sufficient.
Object obj = new Object();
WeakReference<Object> weakReference = new WeakReference<>(obj);
Copy the code
Virtual references: Similar to weak references, the main difference is that virtual references must be used with reference queues.
Object obj = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference<Object> phantomReference = new PhantomReference<>(obj, referenceQueue);
Copy the code
Reference queues: If a soft or weak reference is collected by GC, the JVM will add the reference to the reference queue. If it is a virtual reference, it will be added to the reference queue before collection.
Garbage detection method:
Reference counting: add a reference counter to every object. Every place it is referenced, the counter is +1, and when it expires, it is -1. If two objects reference each other, the collection will not be possible. Reachability analysis algorithm: search with the root set object as the starting point. If the object is unreachable, it is garbage object. The root set (objects referenced in the Java stack, objects referenced in the constant pool in the method area, objects referenced in local methods, etc. During garbage collection, the JVM checks to see if all objects in the heap are referenced by these root set objects. Objects that cannot be referenced are collected by the garbage collector.
Garbage collection algorithm:
Common garbage collection algorithms are:
Mark-clear
Marking: First, all the objects to be reclaimed are marked. After the completion of marking, all the marked objects are collected statistically. The marking process is the accessibility analysis algorithm above. Clear: clear all marked objects shortcomings: inefficient, marking and clearing efficiency are not high space problems, marking will generate a large number of discontinuous memory fragmentation, resulting in large object allocation cannot find enough space, garbage collection in advance.
The replication recovery algorithm divides the available memory into two blocks of equal size according to the capacity, using only one block at a time. When the memory of this block is used up, the surviving objects are copied to another block, and then the used memory space is cleared up at a time.
Disadvantages:
Most objects are “born in the morning”, so you don’t have to divide them in a 1:1 ratio. Commercial virtual machines now use this algorithm to reclaim the new generation, but instead of a 1:1 ratio, the memory region is divided into Eden space, from space, and to space. The From space and to space can be regarded as two space blocks of the same size, equal status, and interchangeable roles used for replication. The From and to Spaces are also known as survivor Spaces, or survivor Spaces, for objects that have not been reclaimed.
At garbage collection, surviving objects in the Eden space are copied to the unused Survivor space (assuming to), and young objects in the survivor space in use (assuming from) are also copied to the TO space (large objects, Or the aged object will go directly to the aged zone, if the to space is full, then the object will go directly to the aged zone). In this case, the remaining objects in the Eden space and from space are garbage objects and can be directly emptied, while the to space stores the surviving objects after the reclamation. This improved replication algorithm not only ensures the continuity of space, but also avoids the waste of a lot of memory space.
Tag-finish
In the old days, objects were mostly survivable, and the replication algorithm became less efficient when the survivability of objects was high. According to the characteristics of the old age, someone proposed the mark-compact algorithm.
The marking process is the same as the mark-clear marking, but instead of cleaning up the recyclable object, all objects are moved to one end and the memory outside the end boundary is cleaned up directly.
This method avoids fragmentation and does not require two identical memory Spaces, so it is more cost-effective.
Band collection algorithm
Memory is divided into chunks depending on how long an object lives, usually by dividing the Java heap into old and new, so that the collection algorithm is appropriate for each generation.
In each collection, a large number of objects die and only a small number of objects survive, so the collection can be completed by using the replication algorithm. The survival rate of old objects is high, and mark-compression algorithm is used to improve garbage collection efficiency.
Class loaders
Instead of loading all the class files at once when the program starts, the Java ClassLoader dynamically loads a class file into memory according to the needs of the program. Only after the class file is loaded into memory. Can be referenced by other classes. So a ClassLoader is used to dynamically load a class file into memory.
5.1 The principle of parent delegation
Each ClassLoader instance has a reference to its parent ClassLoader. The vm’s built-in Bootstrap ClassLoader does not have a parent ClassLoader of its own, but can be used as a parent ClassLoader for other ClassLoader instances.
When a ClassLoader instance needs to load a class, it will attempt to delegate the task to its parent ClassLoader before searching for the class itself. This process is checked from top to bottom. The top-level ClassLoader Bootstrap ClassLoader first loads the class. If it is not found, the task is transferred to the Extension CLassLoader view. If it is not found, the task is transferred to the AppCLassLoader to load the class. If it is not found, the task is transferred to the delegate initiator to load the class in the specified file system or network URL. If not, a CLassNotFoundException will be thrown. Otherwise, the Class generates a Class definition, loads it into memory, and returns the in-memory Class instance object of the Class.
Why use the parent delegate model
When determining whether two classes are the same, the JVM must not only determine whether the two classes have the same name, but also whether they were loaded by the same class loader.
Avoid repeated loading. If the parent class is already loaded, there is no need for the child CLassLoader to load it again. For security reasons, assume a custom String class. Unless you change the DEFAULT algorithm for searching for classloaders in the JDK, a user-defined CLassLoader might load a String class written by itself. This is because the String class is loaded at startup by the Bootstrap CLassLoader.
For Android’s parent delegation mechanism, see the Android ClassLoader parent delegation model
6, collections,
Java collections classes are derived primarily from two interfaces: Collection and Map, which are the root interfaces of Java collections.
The Collection interface is the root interface of the Collection class. Java does not provide a direct implementation class for this interface. But let it be inherited to produce two interfaces, Set and List. A Set cannot contain duplicate elements. A List is an ordered collection that can contain duplicate elements, providing access by index.
Map is another interface in the java.util package. It is separate from the Collection interface, but is part of the Collection class. The Map contains key-value pairs. A Map cannot contain duplicate keys, but it can contain the same value.
6.1, the difference between
List and Set are inherited from the Collection interface, Map is not. List features: Elements are placed in order, elements can be repeated; < span style = “color: RGB (0, 0, 0); color: RGB (0, 0, 0); color: RGB (0, 0, 0); LinkedList, ArrayList, and HashSet are non-thread-safe; Vector is thread-safe; HashMap is non-thread-safe, HashTable is thread-safe;
6.2 Comparison between List and Vector
Vector is multithreaded safe. Thread-safe means that multiple threads accessing the same code do not produce uncertain results. ArrayList is not synchronized, and many of the methods in the Vector class are modified with synchronized. Both classes use linear contiguous space to store elements, but they grow differently when space runs out. A Vector can set a growth factor, but an ArrayList cannot. Vector is an old dynamic array, thread synchronous, inefficient, generally deprecated.
6.3. How can hashSets not be repeated
The underlying implementation of a HashSet is a HashMap, and adding elements to a HashSet is
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
Copy the code
The value of the key is always the same in the HashMap, mainly in the following cases:
- If the hash code values are different, the hash code is a new element.
- If the hash code values are the same and equles judgments are the same, the elements already exist.
- If the hash code values are the same and equles judgments are not equal, the elements do not exist.
- If there are elements whose hash values are equal to those of the passed object, then continue with equles(). If they are still equal, then the passed elements are considered to have already existed and are not added, and the end is reached. Otherwise, add again.
6.4 Application scenarios of HashSet and Treeset
- Hashsets are implemented based on the Hash algorithm, which generally outperforms TreeSet. For sets designed for quick lookup, we should always use HashSet, and we’ll use TreeSet only when we need sorting functionality.
- TreeSet is a binary tree (red-black tree data structure) implementation. Data in TreeSet is automatically sorted and null values are not allowed
- A HashSet is an implementation of a hash table. The data in a HashSet is unordered. It can be put into a NULL, but only one NULL, and the value in both cannot be repeated, just like a unique constraint in a database.
- Hashsets are implemented based on the Hash algorithm, which generally outperforms TreeSet. For sets designed for quick lookup, we should always use HashSet, and we’ll use TreeSet only when we need sorting functionality.
6.5 Differences between HashMap, TreeMap, and HashTable and applicable scenarios
HashMap is a non-thread-safe implementation based on a hash table (hash table). The key classes required to be added with HashMap explicitly define hashCode() and equals()[you can override hashCode() and equals()], and you can tune the initial capacity and load factor to optimize the use of HashMap space. There are two kinds of hash table conflict processing, one is open address method, the other is linked list method. The implementation of HashMap uses the linked list method. TreeMap: Non-thread-safe implementation based on a red-black tree. TreeMap has no tuning options because the tree is always in equilibrium
7. Constant pool
7.1. 128(-128~127) in Interger
When the value is in the range -128 to 127: If two new Integer objects come out, even if the values are the same, the result is false by “==”, but if two objects are directly assigned, the result is “true” by “==”, which is very similar to a String. If the value is not between -128 and 127, the result of “==” is false even if the values of two objects are equal. When an Integer object is directly compared with an int base data type by “==”, the result is the same as the first point; Integer Indicates the hash value of the object itself.
@Override
public int hashCode() {
return Integer.hashCode(value);
}
Copy the code
7.2. Why -128-127?
In the Integer class, there is a static inner class IntegerCache. In the IntegerCache class, there is an Integer array to cache Integer objects with values ranging from -128 to 127.
8 and generic
Generics are a new feature in Java SE 1.5. The essence of generics is that they are parameterized, meaning that the data type you operate on is specified as a parameter. This parameter type can be used in the creation of classes, interfaces, and methods, called generic classes, generic interfaces, and generic methods, respectively. The advantage of introducing generics into the Java language is safety and simplicity.
The benefits of generics are that type safety is checked at compile time, and all casts are automatic and implicit, increasing code reuse.
It provides compile-time type safety, ensuring that you can only put objects of the correct type into collections, avoiding classcastexceptions at run time.
The following points should be noted when using Java generics:
- Type arguments for generic types can only be class types (including custom classes), not simple types.
- There can be multiple versions of the same generic type (because parameter types are uncertain), and different versions of generic class instances are incompatible.
- A generic type can have more than one type parameter.
- Generic parameter types can use the extends statement, for example. It is conventionally called a “bounded type”.
- The parameter types of generic types can also be wildcard types. Such as Class
classType = Class.forName(“java.lang.String”);
8.1 T generics and wildcard generics
- ? Represents an indeterminate Java type.
- T stands for Java type.
- K and V respectively represent Key values in Java Key values.
- E is for Element.
8.2 Generic erasure
Generics in Java are basically implemented at the compiler level. Type information in generics is not contained in the generated Java bytecode. Type arguments that are added when using generics are removed by the compiler at compile time. This process is called type erasure.
Generics are implemented by type erasing, where the compiler erases all type – related information at compile time, so there is no type – related information at run time. List, for example, is represented at run time as just a List. The purpose of this is to ensure compatibility with the binary libraries developed prior to Java 5. You cannot access the type parameters at run time because the compiler has converted the generic type to the primitive type.
8.3 Wildcard qualifiers
One is <? Extends T> Sets an upper bound on a type by ensuring that the type must subclass T. The other is <? Super T> Sets a lower bound on a type by ensuring that the type must be the parent of T. On the other hand, the table shows unqualified wildcards because they can be replaced with any type. For example the List <? Extends Number> can accept a List or a List.
8.4 Generic interview questions
Can you pass a List to a method that takes a List argument?
To anyone unfamiliar with generics, this Java generics title may seem confusing, because at first glance a String is an Object, so a List should be used where a List is needed, but that’s not the case. Doing so will result in a compilation error. And if you think a little bit deeper, you’ll see that it makes sense for Java to do this, because a List can store any kind of object including Strings, integes, and so on, whereas a List can only store Strings.
Can I use generics in Array?
Array doesn’t actually support generics, which is why Joshua Bloch in the book Effective Java recommends using List instead of Array, because List provides type-safety at compile time, whereas Array does not.
9, reflection
9.1, concepts,
JAVA reflection mechanism is in the running state, for any class, can know all the properties and methods of that class; You can call any method on any object; This ability to dynamically retrieve information and dynamically invoke methods on objects is called the Reflection mechanism of the Java language.
9.2,
The Java reflection mechanism provides the following functions: Determine the class to which any object belongs at run time; Construct an object of any class at run time; Determine at run time which member variables and methods any class has; Calls methods on any object at run time; Generate dynamic proxies.
Data structures and algorithms
Zhuanlan.zhihu.com/p/27005757?…
Crazyandcoder. Tech / 2016/09/14 /…
1, sorting,
Sorting has internal sorting and external sorting. Internal sorting means that data records are sorted in memory, while external sorting means that because the sorted data is very large, it cannot hold all the sorted records at one time, and it needs to access external memory in the sorting process.
1.1. Direct insertion sort
Thought:
You sort the first and the second, and you make an ordered sequence and you insert the third, and you make a new ordered sequence. The fourth number, the fifth number… To the last number, repeat step 2. Code:
For (int I =1; i<length; I++), I don’t have to insert one. Sets the number of insertions and the number of bits to get the last number in the sorted sequence. InsertNum and j = I – 1.
2. Design patterns
Reference: Some design patterns in Android development
2.1. Singleton Design pattern
Singletons are mainly divided into lazy singletons, hungry singletons and registered singletons.
Features:
- A singleton class has only one instance
- A singleton class must create its own unique instance
- The singleton class must provide this instance for all other objects.
In computer systems, things like thread pools, caches, log objects, dialog boxes, and printers are often designed as singletons.
Lazy singleton:
Singleton prevents classes from being instantiated externally by limiting constructors to private. Within the same virtual machine scope, a single instance of Singleton can only be accessed via the getInstance() method. In fact, it is possible to instantiate classes with private constructors via Java reflection, which would essentially invalidate all Java singleton implementations.
Hungry Han singleton:
Han style in the creation of a class at the same time has created a static object for the system to use, no longer change, so natural system security.
other
Juejin. Cn/post / 684490… Github.com/Mr-YangChen…