Android Basics

1. General knowledge

1. Android class loader

In Android development, whether plug-in or component, are based on the Android system ClassLoader ClassLoader to design. But the Android platform virtual machine runs 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 all the class file merge, optimization, The purpose is to keep only one copy of the things repeated by different class files. In early Android application development, if the Android application is not divided into dex, the apK of the last application will only have one dex file.

There are two common class loaders in Android, DexClassLoader and PathClassLoader, which inherit from BaseDexClassLoader. The difference is that when the parent constructor is called, DexClassLoader passes an additional parameter, optimizedDirectory, which must be the internal storage path used to cache the Dex files created by the system. For PathClassLoader, the parameter is null and only the Dex file of the internal storage directory can be loaded. So we can use DexClassLoader to load external APK files, which is the basis of many plug-in technologies.

2, the Service

To understand the Android Service, you can understand it from the following aspects:

  • Services are executed on main threads. Time-consuming operations (network requests, copying databases, and large files) cannot be performed on services.
  • You can set the process of a Service in XML and have it execute in another process.
  • A Service performs a maximum of 20 seconds, a BroadcastReceiver 10 seconds, and an Activity 5 seconds.
  • An Activity is bound to a Service by bindService (Intent, ServiceConnection, flag).
  • An Activity can start a Service using startService and bindService.

IntentService

IntentService is an abstract class that inherits from Service and contains a ServiceHandler (Handler) and HandlerThread (Thread). IntentService is a class that handles asynchronous requests. Within an IntentService there is a worker thread (HandlerThread) to handle time-consuming operations. IntentService is started as usual, but when the task is completed, IntentService will stop automatically. IntentService can also be started multiple times, with each time-consuming operation executed as a work queue in the onHandleIntent callback of IntentService, one worker thread at a time. IntentService is essentially an asynchronous framework that encapsulates HandlerThread and Handler.

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 callback functions, as shown in the figure below.

Generally, there are two ways to start a Service, startService and bindService.

2.2 startService Life cycle

When we call the startService method of the Context, we start the Service. The Service started by the startService method will continue indefinitely. A Service will stop running and be destroyed only if stopService of the Context is called externally or stopSelf of a Service is called internally.

onCreate

OnCreate: When the startService method is executed, if the Service is not running, the Service is created and its onCreate callback 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 a Service, the onCreate method of the Service method will be called only once when the Service is first created and will not be called again. We can do some Service initialization in the onCreate method.

onStartCommand

OnStartCommand: After executing the startService method, it is possible to call the onCreate method of the Service, after which the onStartCommand callback method of the Service must be executed. That is, if the startService method of the Context is executed multiple times, the onStartCommand method of the Service will be called multiple times. The onStartCommand method is important, where we actually do something based on the incoming Intent parameter, such as creating a thread for downloading data or playing music.

Public @startresult int onStartCommand(Intent Intent, @startargflags int flags, int startId) {} Copy codeCopy the code

When Android is running low on memory, it may destroy the Service you are currently running and then re-create it when it has enough memory. The forcible destruction and re-creation of a Service by the Android system 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 a Service.

START_NOT_STICKY

If START_NOT_STICKY is returned, the Service will not be created after the process running on it is forcibly killed by the Android system. If startService is invoked again after the process is killed, the Service will be instantiated again. When is it appropriate to return this value? If it doesn’t matter how many times one of our services is interrupted or if it’s acceptable for Android to run out of memory and need to be killed without immediately recreating, we can set the return value of onStartCommand to START_NOT_STICKY. For example, a Service needs to get the latest data from the server periodically: a timer is used to start the Service every N minutes to get the latest data from the server. When the onStartCommand of the Service is executed, a timer is planned in this method after N minutes to start the Service again and start a new thread to perform network operations. If the Service is killed by the Android system in the process of getting the latest data from the server, the Service will not be created again, which is fine because after N minutes the timer will start the Service again and get the data again.

START_STICKY

If START_STICKY is returned, the Android system will set the Service to the started state (running state) after the process running the Service is forcibly killed. Instead of saving the intent object passed in by the onStartCommand method, the Android system will try to recreate the Service and execute the onStartCommand callback. The intent parameter of the onStartCommand callback is null. The onStartCommand method executes but doesn’t get the intent information. If your Service can run or end at any time with no problem and does not require intent information, then return START_STICKY in the onStartCommand method. For example, a Service that plays background music is suitable to return this value.

START_REDELIVER_INTENT

If START_REDELIVER_INTENT is returned, the Process running the Service is forcibly killed by the Android system. If START_REDELIVER_INTENT is returned, the Android system creates the Service again. And execute the onStartCommand callback method, but the difference is, The Android system saves the Intent that the Service last passed to the onStartCommand method before it was killed and passes it back to the onStartCommand method of the newly created Service so that we can read the Intent parameters. As long as START_REDELIVER_INTENT is returned, the intent must not be null. If our Service relies on a specific Intent to run (read data from the Intent, etc.) and needs to be re-created after being forcibly destroyed, 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, so the onBind method has to be overridden, even if we don’t use it. When using Service through startService, we simply return null when overriding the onBind method. The onBind method is used primarily when calling a Service to the bindService method.

onDestroy

onDestroy: A Service started with the startService method will run indefinitely. The Service will stop running and be destroyed only when stopService of the Context is called or stopSelf is called within the Service. The Service callback is executed at destruction time.

2.3 bindService life cycle

Starting a Service in bindService mode has the following life cycle functions:

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 () :

The system calls this method when the service is no longer in use and is about to be destroyed.

OnBind () :

The system calls this method when another component binds to the service by calling bindService().

OnUnbind () :

The system calls this method when another component unbinds the service by calling unbindService().

OnRebind () :

This method is called when onUnbind() returns true after the old component is unbound from the service and another new component is bound to the service.

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, and then we need to associate it with the return method of onCreatView(). Finally we need to configure the parameters in the Activity to place the fragment in the XML file of the Activity.

 <fragment
        android:name="xxx.BlankFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"> </fragment> Copy codeCopy the code
(2) Dynamic creation

There are several steps to dynamically create a Fragment:

  1. Create the Fragment instance to be added.
  2. Get FragmentManager, can be directly in the Activity by calling getSupportFragmentManager () method.
  3. Start a transaction by calling the beginTransaction() method.
  4. Adding or replacing a fragment to a container is usually done using the repalce() method, which requires passing in the id of the container and the fragment instance to be added.
  5. Commit the transaction and call commit() to do so.

3.2 Adapter comparison

The FragmnetPageAdapter only separates fragments when switching pages. The FragmnetPageAdapter is suitable for fragments with a few pages to save some memory and has no significant impact on system memory.

The FragmentPageStateAdapter recollects fragments each time the page is switched. It is suitable for fragments with many pages and does not consume much memory

3.3. Activity lifecycle

The Activity lifecycle is shown below:

(1) Dynamic loading:

When loading dynamically, the fragment is loaded and its life-cycle method is called after onCreate() is called. Therefore, in the first life-cycle method onAttach(), you can get the component of the Activity and its layout.

(2) Static loading:

1. During static loading, the fragment is also loading during the onCreate() call of the Activity. Therefore, the fragment cannot get components in the layout of the Activity.

2. The method onInflate() is also called before the Fragment calls onAttach(). By the time this method is called, the fragment is already attached to the Activity, so it can retrieve the other, but the onCreate() call to the Activity is not complete. The component of the Activity cannot be obtained.

3. The fragment calls onCreate() and calls the onActivityCreated() lifecycle method, so it gets the component of the Activity’s layout from there.

3.4. Communicate with the Activity

The reason why fragments don’t pass values through constructors is because they don’t get values when they switch landscape.

Activity passes values to fragments:

The Activity sends a value to the Fragment and puts the value into the bundle. Create the Fragment object in the Activity, and pass it into the Fragment by calling setArguments(); Get the bundle object in that Fragment by calling getArguments(), and you can get the values inside.

Fragment sends a value to an Activity:
The first:

Call getFragmentManager() in the Activity to get the fragmentManager, and call findFragmentByTag(tag) or findFragmentById(ID), for example:

FragmentManager FragmentManager = getFragmentManager(); Fragments fragments = fragmentManager. FindFragmentByTag (tag); Copy the codeCopy the code
The second:

Using a callback to define an interface (you can define it in the Fragment class) with an empty method in the Fragment class. Call the interface’s method when needed and place the value as a parameter in the Fragment method. Then let the Activity implement the interface, which must override the method. The value is then passed into the Activity

How to transfer values between fragments:
The first:

FindFragmentByTag to get another Fragment object, so you can call another method.

The second:

By way of interface callback.

The third:

By setArguments, getArguments.

3.5. API differences

add

One way is to show and add the fragment. This way you can switch the fragment and not have it refresh, but only call onHiddenChanged(Boolean isHidden).

replace

Replace will cause the fragment to refresh, because add hides the fragment instead of destroying it and creating it, and replace creates it every time.

commit/commitAllowingStateLoss

The only difference is the second method, which allows some interface state and information to be lost. Almost all developers have encountered this error: Commit () cannot be executed after the activity calls onSaveInstanceState. The interface is recovered by the system (the interface no longer exists). In order to restore the original state when the activity opens again, the system saves all the state of the interface for us. It is theoretically impossible to modify the interface at this point, so the second method is used to avoid this exception.

3. The lazy loading

We often use fragments in conjunction with viewPager, and one of the problems we run into is that when we initialize the fragment, it will run along with the network request we wrote. This is very performance consuming. Ideally, only when the user clicks on or slides into the current fragment, To request the network operation. 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 onCreate(). It tells us whether the Fragment is visible through isVisibleToUser, so we can load the Fragment when it is visible.

SetUserVisibleHint () is called before onCreateView, so if you want to implement lazy loading in setUserVisibleHint (), you must make sure that the View and other variables are initialized and not null Pointers.

Use steps:

Declare a variable isPrepare=false, SetUserVisibleHint (Boolean isVisible) specifies whether the page has been created. Set isVisible=true To check whether isPrepare and isVisible are true to start loading data. Then restore isPrepare and isVisible to false to prevent repeated loading.

For information about lazy loading of Android Fragments, see the link below: Lazy loading of Android Fragments

4, the Activity

4.1 Activity startup process

The user clicks the application icon from the Launcher program to start the entry Activity of the application. The Activity starts with 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 a number of Binder services. Binder Services, such as ActivityManagerService, PackageManagerService, and WindowManagerService, run in different threads. ActivityManagerService manages the Activity stack, application processes, and tasks.

Click the Launcher icon to start the Activity

When a user clicks on an application icon in the Launcher program, ActivityManagerService notifies the Zygote process to start the application’s entry Activity. If ActivityManagerService finds that the application hasn’t started yet, it notifies the Zygote process to incubate the application. The Main method of ActivityThread is then executed in the Dalvik application process. The application process then notifies ActivityManagerService that the application process is started. ActivityManagerService stores a proxy object for the application process that ActivityManagerService can use to control the application process. ActivityManagerService then tells the application process to create an instance of the entry Activity and execute its lifecycle methods.

Android drawing process window startup process analysis

4.2. Activity Lifecycle

(1) The Activity form

Active/Running:

When an Activity is active, it is visible at the top of the stack and can interact with the user.

Paused:

The Activity transitions to Paused when it loses focus, is placed at the top of the stack by a new Activity that is not full-screen, or by a transparent Activity. However, we need to understand that the Activity only loses the ability to interact with the user, all its state information and its member variables are still present, and can only be reclaimed by the system if the system is running out of memory.

Stopped:

When an Activity is completely overwritten by another Activity, the covered Activity goes into the Stopped state, where it is no longer visible but holds all of its state information and its member variables as Paused.

Killed:

When an Activity is discarded by the system, it is Killed.

The Activity switches between these four modes, and how it switches varies depending on the user. Now that you know about the four forms of an Activity, let’s talk about the Activity lifecycle.

The Activity life cycle

A typical life cycle is when an Activity goes through the normal life cycle of creating, running, stopping, and destroying with the user involved.

onCreate

This method is called back when the Activity is created. It is the first method called in the lifecycle. When creating an Activity, we usually need to override this method, and then do some initialization operations in this method, such as setting the resources of the interface layout through setContentView, and initializing the required component information.

onStart

This method is called back to indicate that the Activity is being started and that the Activity is already visible, but not yet displayed in the foreground, so it cannot interact with the user. The Activity is displayed and we can’t see the pendulum.

onResume

When this method is called back, the Activity is visible in the foreground and ready to interact with the user (in the Active/Running state described above). The same thing between onResume and onStart is that both indicate that the Activity is visible. The onStart callback does not allow the Activity to interact with the user in the background, whereas the onResume callback is displayed in the foreground and can interact with the user. The onResume method is also called when the Activity stops (onPause and onStop are called) and comes back to the foreground, so we can also initialize some resources in the onResume method. Such as reinitializing resources released in onPause or onStop.

onPause

This method is called back to indicate that the Activity is stopped (Paused), and normally the onStop method will be called back soon after. If the onResume method is immediately executed after the onPause method is executed, the onResume method will be called back to the current Activity. Of course, we can do some data storage or animation stops or resource reclaiming in onPause, but this should not be too time-consuming, as 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 Activity is Stopped or completely overwritten, it is not visible and only runs in the background. Similarly, the onStop method allows you to do some resource release (not too time-consuming).

onRestart

Indicates that the Activity is being restarted. This method is called back when the Activity changes from invisible to visible. In this case, when the user starts a new Activity, the current Activity is paused (onPause and onStop are executed), and when the user 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 to execute in the lifecycle, so we can usually do some recycling and the final resource release in this method.

summary

To recap, onCreate(),onStart(), and onResume() are called when the Activity starts, and when the Activity recede into the background (invisible, hit Home or completely overwritten by a new Activity), OnPause () and onStop() are called in turn. OnRestart (), onStart(), and onResume() are called when the Activity returns to the foreground (either from the desktop or after being overwritten). When the Activity exits destruction (by clicking the back key), onPause(), onStop(), and onDestroy() are called in sequence, until the method callbacks for the Activity’s entire life cycle are complete. Now let’s go back to the previous flow chart, it should be quite clear. Well, this is the typical life cycle of an Activity.

2. View some knowledge points

The relationship between Android activities, PhoneWindow, and DecorView can be shown as follows:

2.1. DecorView Analysis

For example, a DecorView is the top-level View of the entire Window interface, which has only one child LinearLayout. Represents the entire Window interface, including the notification bar, title bar, content display bar three areas. The LinearLayout has two FrameLayout children.

The role of DecorView

A DecorView is a top-level View that is essentially a FrameLayout and it has two parts, the title bar and the interior bar, both of which are FrameLayout. The interior column ID is content, the part of the activity that sets the setContentView, and finally adds the layout to the FrameLayout 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 as the root View of the entire application Window, which is the Window implementation class. It is the most basic window system in Android. Each Activity creates a PhoneWindow object, which is the interface between the Activity and the View system. DecorView: Is the top-level View that renders the specific content to be displayed on the PhoneWindow. The DecorView is the ancestor of all views of the current Activity and does not present anything to the user.

2.2 Event distribution of View

The event distribution mechanism of a View can be represented as follows:

As shown in the figure above, the figure is divided into three layers: Activity, ViewGroup and View from top to bottom.

  1. Events start with the white arrow in the upper left corner and are dispatched by the Activity’s dispatchTouchEvent
  2. The top word of the arrow represents the method return value (return true, return false, return super.xxxxx(),super means to call the superclass implementation.
  3. The dispatchTouchEvent and onTouchEvent boxes have the word “true—-> consume” in them, which means that if the method returns true, the event will be consumed and will not go anywhere else, and the event will terminate.
  4. At present, all graph events are for ACTION_DOWN. We will analyze ACTION_MOVE and ACTION_UP at last.
  5. The Activity dispatchTouchEvent in the previous diagram was wrong (figure fixed), only the return super.dispatchTouchEvent(ev) was further down, and the event returned true or false was consumed (aborted).

ViewGroup event distribution

When a click event is generated, it is passed in the following order:

Activity -> Window -> View

Events are always passed to the Activity, which in turn is passed to the Window, which in turn is passed to the top-level View, which, upon receiving the event, distributes the event according to the event distribution mechanism. If a View’s onTouchEvent returns FALSE, its parent’s onTouchEvent will be called, and so on, and the Activity will handle the event if nothing else.

For ViewGroup event distribution, it looks something like this: If the top-level ViewGroup intercepts the event (onInterceptTouchEvent returns true), the event will be handled by the ViewGroup. If the onTouchListener of the ViewGroup is set, onTouch will be called. Otherwise onTouchEvent will be called, that is: if both are set, onTouch will block onTouchEvent, and in onTouchEvent, if onClickerListener is set, onClick will be called. If the top-level ViewGroup does not intercept, the event will be passed to the child view of the clicked event, and the child view’s dispatchTouchEvent will be called

View event distribution

dispatchTouchEvent -> onTouch(setOnTouchListener) -> onTouchEvent -> onClick

The difference between onTouch and onTouchEvent is that both are called within dispatchTouchEvent, onTouch takes precedence over onTouchEvent, if onTouch returns true, then onTouchEvent is not executed, And onClick are not executed either.

2.3. View drawing

In an XML layout file, our layout_width and layout_height parameters can be wrap_content or match_parent instead of the actual size. These two Settings do not specify the actual size, but the View we draw on the screen must have a specific width and height, and for this reason we have to handle and set the size ourselves. Of course, the View class provides the default processing, but if the default processing of the View class does not meet our requirements, we will have to rewrite the onMeasure function.

The onMeasure function is an int that contains the measurement mode and size. Ints take up 32 bits. Google uses the first two bits of ints to distinguish between different layout patterns, and the last 30 bits to store the size of the data. The use of onMeasure function is shown as follows:

MeasureSpec has three measurement modes:

Match_parent – > EXACTLY. How do you understand that? Match_parent is using all the free space that the parent View gives us, and the free space that the parent View gives us is determined, which is the size of the integer in this measurement mode.

Wrap_content – > AT_MOST. We want to set the size to wrap our view content, so the size is the parent view gives us as a reference size, as long as it does not exceed this size, the specific size according to our needs to set.

Fixed size (e.g. 100DP) — >EXACTLY. Users specify their own size, we do not have to interfere, of course, with the specified size mainly.

2.4 ViewGroup drawing

Customizing a ViewGroup is not easy, because it needs to take care of both its own and its child views. We all know that a ViewGroup is a View container that holds the Child View and is responsible for putting the Child View into the specified location.

  1. First of all, we need to know the size of each child View. Only by knowing the size of each child View can we know how big the current ViewGroup should be set to accommodate them.

  2. The size of the ViewGroup depends on the size of the subview and what our ViewGroup is going to do

  3. Once the size of the ViewGroup and subview is calculated, the next step is to put it, how to put it? It’s up to you to customize it. For example, if you want the child views to be placed next to each other in vertical order, or one on top of the other in chronological order, it’s up to you.

  4. Already know how to put ah, decided how to put is equivalent to the existing space “divided” into large and small space, each space corresponding to a sub-view, we next is to put the sub-view into the seat, put them in their place.

For details about customizing viewGroups, see Customizing ViewGroups on Android

3. System principle

3.1 packaging principle

Android package file APK is divided into two parts: code and resources, so packaging is also divided into resource packaging and code packaging two aspects, this article will analyze the principle of resource and code compilation packaging.

To be specific:

  1. Use AAPT tool to package resource files (including Androidmanifest.xml, layout files, various XML resources, etc.) to generate R.Java files.
  2. The AIDL tool is used to process AIDL files and generate corresponding Java files.
  3. Compile the project source code through Javac tools to generate Class files.
  4. DX tool is used to convert all Class files into DEX files. This process mainly completes the conversion of Java bytecode to Dalvik bytecode, compression of constant pool and removal of redundant information.
  5. Use ApkBuilder to package resource files and DEX files to generate APK files.
  6. Use KeyStore to sign the generated APK file.
  7. For official APK, the ZipAlign tool is used for alignment. The alignment process is to offset the starting distance of all resource files 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 main atmosphere of the Android APK installation process is as follows:

  1. Copy the APK to /data/app, unpack and scan the installation package.
  2. Resource manager parses resource files in APK.
  3. Parse the AndroidManifest file and create the corresponding application data directory under /data/data/.
  4. Then the dex file is optimized and saved in the dalvik-cache directory.
  5. Register the four component information parsed from the AndroidManifest file with PackageManagerService.
  6. When the installation is complete, broadcast.

It can be represented by the following diagram:

4. Third-party library parsing

4.1 Retrofit Network Request Framework

Concept: Retrofit is an encapsulation of a RESTful 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 through the Retrofit network, essentially encapsulating the request parameters, headers, urls, etc., using the Retrofit interface layer, and then OKHttp completes the subsequent requests. After the server returns the data, OKHttp sends the original results to Retrofit. Finally, the results are analyzed according to the user’s requirements.

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); } Duplicate codeCopy the code

2. Create a Retrofit instance

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/") .build(); Copy the codeCopy 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"); Callback<ResponseBody>() {Override public void onResponseBody <ResponseBody>(); Override public void onFailure(Call<ResponseBody> ResponseBody) {Override public void onFailure(Call<ResponseBody> ResponseBody) Throwable t) {// Execute error callback method}}); Copy the codeCopy the code

Retrofit dynamic proxy

Retrofit is executed as follows: 1. First, convert it to ServiceMethod using method. 2. Then, with serviceMethod, args gets the okHttpCall object. 3. Finally, wrap okHttpCall further 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 codeCopy the code

The build() method is used to create a 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} callbackExecutor = this.callbackExecutor;if(callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); // Make a defensive copy of the adapters and add the default CallAdapter. 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 newly created Retrofit object} copy codeCopy the code

This method returns a Retrofit object from which the interface to the network request is created as follows:

NetApi repo = retrofit.create(NetApi.class); Copy the codeCopy the code

The retrofit object’s create() method 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 this method directly}if (platform.isDefaultMethod(method)) {
            returnplatform.invokeDefaultMethod(method, service, proxy, args); } ServiceMethod ServiceMethod = loadServiceMethod(method); OkHttpCall OkHttpCall = new OkHttpCall<>(ServiceMethod, args); // Pass the argument to generate an okHttpCall objectreturnserviceMethod.callAdapter.adapt(okHttpCall); // execute okHttpCall}}); } Duplicate codeCopy the code

4.2 comparison of image loading libraries

Picasso was: 120 k

Glide: 475 k

Fresco: 3.4 M

Android – Universal – Image – Loader: 162 k

The choice of image library depends on the specific situation of your APP. For apps that rely heavily on image caching, such as wallpaper and image social apps, you can choose the most professional Fresco. For a general APP, Fresco is a heavy choice because of its 3.4m size. The above libraries can be sorted according to the APP’s requirements for image display and caching from lowest to highest.

Picasso < Android-Universal-Image-Loader < Glide < Fresco

2. Introduction:

Picasso: Works best with Square’s web library because Picasso can choose to hand over the caching of web requests to the OkHTTP implementation.

Glide: Copied Picasso’s API and added many extensions to it (GIF support, etc.). Glide’s default Bitmap format is RGB_565, which has half the memory overhead of Picasso’s default ARGB_8888 format. Picasso caches full-size (only one), Glide caches the same size as ImageView (56)

56 and 128

128 is two caches).

FB image loading framework Fresco: The biggest advantage is bitmap loading under 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 occupied memory will be released automatically. This will make the APP more fluid and reduce the number of OOM images. After 5.0, Ashmem is stored in the Ashmem area by default.

3. Conclusion:

Glide can do everything Picasso can do, except in different Settings. But Picasso is much smaller than Glide. If the web request itself is okHTTP or Retrofit (essentially okHTTP), then suggest Picasso, which is much smaller (Square family barrel work). Glide is the benefit of large picture stream, such as GIF, Video, if you do beauty shot, love to shoot this kind of Video application, I suggest to use.

Fresco memory up to 5.0 is very well optimized, but the trade-off is that it is also very large, Fresco>Glide>Picasso by volume

It’s also a bit tricky to use (tip: he can only use a built-in ImageView to implement these features, which is a bit tricky to use, and we usually use Fresco’s Bitmap layer instead).

4.3 Use of various JSON parsing libraries

Refer to the link: www.cnblogs.com/kunpengit/p…

(1) Gson of Google

Gson is the most fully functional Json parser. Gson was originally developed by Google for internal needs, but has been used by many companies or users since the first version was publicly released in May 2008. The application of Gson is mainly toJson and fromJson conversion functions, no dependency, no need to exception additional JAR, can run directly on JDK. Before using this object conversion, you need to create the object type and its members to successfully convert the JSON string into the corresponding object. As long as there are get and set methods in the class, Gson can convert complex types of JSON-to-bean or bean-to-JSON, which is a magic tool for JSON parsing. Gson is impeccable in functionality, but it lags behind FastJson in performance.

(2) FastJson of Alibaba

Fastjson is a high-performance JSON processor written in Java language, developed by Alibaba.

No dependencies, no extra JAR exceptions, and the ability to run directly on the JDK. FastJson has some problems converting complex types of beans to Json. The type of reference may appear, leading to Json conversion errors and the need to specify the reference. FastJson uses an original algorithm that makes Parse faster than any OTHER JSON library.

In conclusion, the comparison of Json technology shows that Google’s Gson and Alibaba’s FastJson can be used in parallel in project selection. Google’s Gson can be used if there are only functional requirements but no performance requirements. If you have performance requirements above, you can use Gson to convert the bean to JSON to ensure that the data is correct, and use FastJson to convert the JSON to bean

5. Hot technology

Reference link – Android componentization scheme

5.1 componentization

(1) Concept:

Modular: It is to divide an APP into multiple modules, each module is a component, or it can be a basic library for component dependence. During development, some components can be debugged separately, and components do not need to depend on each other but can be called each other. When finally released, all components are packaged into an APK in the form of lib by the main APP project dependency.

(2) Origin:

  1. APP versions are iterated, and new functions are constantly added. As a result, services become complicated and maintenance costs are high
  2. The business coupling degree is high, the code is bloated, and it is difficult to cooperate with many people in the team
  3. Android compilation code is slow, the code coupling under a single project is serious, modify a need to recompile packaging, time and energy consumption.
  4. Easy unit testing, a separate business module, do not need to focus on other modules.

(3) Advantages:

  1. Componentalization separates common modules for unified management to improve reuse, and breaks down pages into smaller components that contain UI implementations, as well as data and logic layers
  2. Each component can compile independently, speed up compilation, and package independently.
  3. Modifications made within each project do not affect other projects.
  4. The business library project can be quickly broken down and integrated into other apps.
  5. The business module with frequent iteration adopts the component mode. The business line research and development can not interfere with each other, improve collaboration efficiency, control product quality and strengthen stability.
  6. In parallel development, team members only focus on small modules of their own development, which reduces coupling and facilitates later maintenance.

(4) Consideration:

Mode switching: How to enable the APP to switch freely between individual debugging and overall debugging

After componentization, each business module can be a separate APP (isModuleRun=false). When releasing the package, each business module is used as a lib dependency, which is completely controlled by a variable. In the root project gradle.properties isModuleRun=true. IsModuleRun loads application and AndroidManifest differently depending on the state, to distinguish between independent APK and lib.

In build.grade:

Resource conflict

The business Module and BaseModule resource file names overlap. The solution is:

Each module has app_name. To prevent resource names from being the same, add resourcePrefix “xxx_” to build.gradle for each component to enforce resource name prefixes. Fixed the resource prefix for each component. However, the resourcePrefix value can only limit resources in the XML, not the image resources.

dependencies

How to reference some common library and utility classes between modules

Component communication

After componentization, modules are isolated from each other, and routing frameworks such as Alibaba ARouter or Meituan WMRouter can be used for UI jump and method call.

Each service Module does not need any dependency before and can jump through routes to perfectly solve the coupling between services.

Entrance parameters

We know that components are related to each other, 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 repeatedly, so we just need to define a BaseApplication. Other applications inherit directly from this BaseApplication and can define common parameters in the BaseApplication.

How to componentize, you can refer to: Anjuke Android project architecture evolution

5.2. Plug-in

Reference links – Getting started with plug-ins

(1) Overview

When it comes to plug-in, we have to mention the problem that the number of methods exceeds 65535, which can be solved by Dex subcontracting, as well as by using 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, which makes the division of labor more clear. Each module is encapsulated into a different plug-in APK, and different modules can be compiled separately to improve the development efficiency. The problem that the number of methods above exceeds the limit is solved. New plugins can be launched to solve online bugs and achieve the effect of “hot fixes”. Reduced the volume of host APK.

(3 disadvantages)

Apps developed as plug-ins cannot be launched on Google Play, which means there is no overseas market.

6, screen adaptation

6.1 Basic Concepts

The screen size

Description: The physical unit of the diagonal of a mobile phone is inch (1 inch =2.54cm)

Common Android phone sizes are 5 inches, 5.5 inches, 6 inches, 6.5 inches and so on

Screen resolution

Meaning: the sum of pixel points of mobile phone in horizontal and vertical direction

Generally described as the screen “width x height” =AxB meaning: the screen has A pixels in the horizontal direction (width), in the vertical direction

Example: 1080×1920, 1080 pixels in width and 1920 pixels in height

Unit: px (Pixel), 1px=1 pixel point

UI designers will use PX as a unified unit of measurement in their drawings

Common Android phone resolutions: 320×480, 480×800, 720×1280, 1080×1920

Screen pixel density

Definition: Dots per ich dpi (dots per ich)

Assuming 160 pixels per inch inside the device, the screen pixel density of the device =160dpi

6.2 adaptation method

1. Support various screen sizes: use wrap_content, match_parent, weight. To ensure the layout is flexible and accommodates screen sizes, use “wrap_content”, “match_parent” to control the width and height of certain view components.

2. Use relative layout and disable absolute layout.

3. Use the weight attribute of the LinearLayout

What if our width is not 0dp(wrap_content has the same effect as 0DP), but match_parent?

Android :layout_weight: If the View has this property set and it is valid, then the width of the View is equal to the original width (Android :layout_width) plus 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, each Button should also be L, and the remaining width is L- (L+L) = -L.

Button1’s weight=1, and the ratio of remaining width 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 scheme ultimate version

7. Performance optimization

Android performance optimization, mainly from the following aspects of optimization: Stable (memory overflow and crash) Smooth (lag) Consumption (power consumption and traffic) Installation package (THIN APK) Many reasons may affect application stability, for example, improper memory usage, poorly considered code exception scenarios, and unreasonable code logic. Two of the most common scenarios are Crash and ANR, which make the program unusable. Therefore, do a good job of global monitoring Crash, deal with flash back and collect and record Crash information and abnormal information for subsequent analysis; Use the main thread properly to process services. Do not perform time-consuming operations in the main thread to prevent ANR program from being unresponsive.

(1) stability — memory optimization

(1) Memory Monitor:

It’s a memory monitoring tool that comes with Android Studio, and it’s a great tool for real-time memory analysis. By clicking the Memory Monitor TAB in the lower right corner of Android Studio, open the tool and you can see that the lighter blue represents the free Memory, while the darker part represents the used Memory. When memory is suddenly depleted, GC and so on can occur, as shown in the figure below.

LeakCanary tool: LeakCanary is an open source framework developed by Square based on MAT to monitor Android memory leaks. Here’s how it works: The monitoring mechanism makes use of Java WeakReference and ReferenceQueue. By packaging the Activity into WeakReference, if the Activity object packaged by WeakReference is recovered, The WeakReference reference will be put into the ReferenceQueue. By monitoring the content in the ReferenceQueue, we can check whether the Activity can be recycled (in the ReferenceQueue, it can be recycled, there is no leakage; Otherwise, there may be a leak, LeakCanary is performed once, if it is not in the ReferenceQueue, it will be considered as a leak).

If the Activity is identified as leaking, the memory dump file (debug.dumphprofData) is grabbed; After HeapAnalyzerService. Analyze runAnalysis memory file analysis; Memory leak analysis is then performed using HeapAnalyzer (checkForLeak — findLeakingReference– findLeakTrace). Finally, display the memory leak through DisplayLeakService.

Android Lint tools:

The Android Lint Tool is an integrated Android code prompt Tool that can help you layout your code. For example, write the text to display directly in the TextView. Use the font size in dp instead of SP. You will see the warning on the right of the editor.

(2) Fluency — Caton optimization

Catton’s scenarios usually take place in the most immediate aspect of the user’s interactive experience. The two main factors affecting the lag are interface rendering and data processing.

Interface drawing: The main reasons are the deep level of drawing, complex page and unreasonable refresh. Due to these reasons, the scene of lag appears more in UI and initial interface after startup, as well as jump to page drawing.

Data processing: This scenario is caused by the large amount of data processing, which is generally divided into three situations: first, the UI thread is processing data; second, the main thread cannot get time slices due to the high CPU usage of data processing; third, the memory increase leads to frequent GC, which causes the lag.

(1) Layout optimization

In the Android system for View measurement, layout and drawing, are through the View number traversal operation. If the height of a View number is too high, it can seriously affect the speed of measurement, layout, and drawing. Google also recommends in its API documentation that views be no higher than 10 layers. In the current version, Google uses RelativeLayout instead of LineraLayout as the default root layout in order to reduce the height of the LineraLayout nesting layout tree and thus improve the efficiency of UI rendering.

Reuse layout, reuse layout with tags; Improve display speed, use delayed View loading; Reduce hierarchies and replace parent layouts with labels; Note that using wrAP_content increases measure computing cost. Delete useless properties from the control.

(2) Rendering optimization

Overdrawing is when a pixel on the screen is drawn more than once in the same frame. In the multi-level overlapping UI structure, if the invisible UI is also drawing, some pixel regions will be drawn multiple times, thus wasting redundant CPU and GPU resources. How do I avoid overdrawing?

Layout optimization. Remove non-essential background from XML, remove Window’s default background, and display placeholder background images on demand

Custom View optimization. Use Canvas.cliprect () to help the system identify the visible areas within which it will be drawn.

(3) Start optimization

Applications generally have SplashActivity, which optimizes the UI layout of the splashpage and detects frame loss through Profile GPU Rendering.

(3) saving — optimization of power consumption

Prior to Android5.0, testing app Battery consumption was cumbersome and inaccurate, but since then Google has introduced an API to retrieve information about Battery consumption on devices, Battery Historian. Battery Historian is an Android power analysis tool from Google that visually displays your phone’s Battery consumption process, as data can be imported from another application.

Finally, some methods of power consumption optimization are provided for reference:

(1) Computational optimization. Algorithms, for loop optimization, Switch.. Case alternative if.. Else, avoid floating point arithmetic.

Floating-point arithmetic: in computers, integers and decimals are stored in a common format, such as 1024, 3.1415926, etc. This has no special features, but such numbers are not precise or comprehensive. In order to have a general representation of numbers, floating point numbers were invented. Floating-point numbers are represented somewhat like scientific notation (

.

X 10 ^

), and its representation is 0.

X 10 ^

, in computer form is.* e –

**), where the leading asterisk represents a fixed-point decimal, that is, a pure decimal with an integer part of 0, and the trailing exponent is a fixed-point integer. Any integer or decimal can be expressed in this form. 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. Floating-point numbers perform operations called floating-point operations. Floating-point operations are more complex than regular operations, so computers can perform them much slower than regular operations.

(2) Avoid improper use of Wake Lock.

Wake Lock is a locking mechanism, which is mainly related to the sleep of the system. As long as someone holds the Lock, the system cannot enter sleep. It means that the system will not sleep after my program adds this Lock to the CPU. In some cases, failure to do so can lead to problems, such as the heartbeat packets of instant communication, such as wechat, stopping Internet access shortly after the screen goes down. Therefore, Wake_Lock is widely used in wechat. To save power, the CPU automatically goes to sleep when no task is busy. Wake_Lock is added to the CPU when a task needs to be woken up for efficient execution. A common mistake, 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 executed 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.

(IV) Installation package — APK slimming

(1) Composition of the installation package

Assets folder. Some configuration files and resource files are stored. The ID of assets is not automatically generated, but obtained through the interface of AssetManager.

Res. Res is short for resource. This directory stores resource files. Ids are automatically generated and mapped to.r files.

Meta-inf. Saves application signature information, which verifies the integrity of APK files.

Androidmanifest.xml. This file is used to describe the configuration information of the Android application, registration information of some components, permission to use, etc.

Classes. Dex. Dalvik bytecode program, which makes the Dalvik VIRTUAL machine executable. Generally, The Android application converts Java bytecode to Dalvik bytecode through the DX tool in the Android SDK during packaging.

Resources. Arsc. It records the mapping between resource files and resource ids to search for resources based on resource ids.

(2) Reduce the installation package size

Code confusion. Use the proGuard code obfuscation tool that comes with the IDE, which includes compression, optimization, obfuscation, and more. Resource optimization. For example, using Android Lint to remove redundant resources, minimizing resource files, etc. Image optimization. For example, using PNG optimization tools to compress images. Google Open Source library Zopfli, the most advanced compression tool, is recommended. If the application is in version 0 or later, the WebP image format is recommended. Third-party libraries that avoid duplication or useless functionality. For example, Baidu Map can be connected to basic maps, IFlytek does not need to be connected to offline, Glide, Picasso, etc. Plug-in development. For example, function modules can be downloaded on the server to reduce the size of the installation package. You can use the wechat open source resource file obfuscation tool — AndResGuard. Generally can compress APK about 1M large.

7.1. Cold start and hot start

Refer to the link: www.jianshu.com/p/03c0fd3fc…

Cold start When an application is started, the system creates a new process and assigns it to the application.

Hot start When you start an application, an application process is running in the system (for example, if you press the Back or home keys, the application exits, but the application process remains in the background).

Cold start: The system does not have the process of the Application, and a new process needs to be created and assigned to the Application. Therefore, the Application class is first created and initialized, and then the MainActivity class (including a series of measurement, layout, and drawing) is created and initialized, and finally displayed on the interface. Hot start: Starts from an existing process, does not create and initialize the Application class, directly creates and initializes the MainActivity class (including a series of measurements, layout, drawing), and displays it on the interface.

Cold start Zygote process fork creates a new process; Create and initialize the Application class and create MainActivity. Inflate layout, when onCreate/onStart/onResume method; Measure /layout/draw of contentView is displayed on the interface.

Cold-start optimization reduces the amount of work in the onCreate() method of the Application and the first Activity; Do not let Application participate in business operations; Do not perform time-consuming operations in Application; Do not store data in Application as static variables; Reduce layout complexity and depth;

8. 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 (Model) : Mainly capture data function, business logic and entity Model.

View layer: Corresponding to an Activity or Fragment, responsible for part of the View’s presentation and business logic user interaction

Control layer (Presenter) : Is responsible for completing the interaction between View layer and Model layer. It obtains data from M layer through P layer and returns it to V layer so that there is no coupling between V layer and M layer.

In MVP, the Presenter layer completely separates the View layer from the Model layer, and puts the main program logic in the Presenter layer. Presenter is not directly associated with the specific View layer (Activity), but interacts with it by defining interfaces. This allows Persenter to remain unchanged when the View layer (Activity) changes. The View layer interface class should only have set/ GET methods, some interface display content and user input, and nothing else. The View layer is never allowed to directly access the Model layer, which is the biggest difference from MVC and a core merit of MVP.

9. Virtual machines

9.1 Comparison between Android Dalvik VM and ART VM

Dalvik

Android4.4 and before use Dalvik vm, we know that Apk will first compile Java and other source files into a. Class file through javac during packaging process, but our Dalvik vm will only execute a. Dex file. At this point dx will convert the.class file to the.dex file executed by the Dalvik VM. Dalvik VM will first convert the dex file into the fast running machine code when it is started. Due to the problem of 65535, we have a packet closing process when the application is cold started, and one result is that our APP starts slowly. This is the JIT feature (Just In Time) of the Dalvik virtual machine.

ART

ART VIRTUAL machine is an Android VIRTUAL machine that was only used in Android5.0. ART virtual machine must be compatible with the features of Dalvik VIRTUAL machine, but ART has a very good feature AOT (Ahead of time). This feature is that when we install APK, we will directly process dex into machine code that can be directly used by ART virtual machine, ART virtual machine will convert. Dex file into. Oat file that can be run directly. Therefore, ART virtual machine can greatly improve the speed of APP cold startup.

ART strengths:

Speed up the cold startup of APP

Increase GC speed

Provides comprehensive debugging features

ART faults:

APP installation is slow because a runnable.oat file is generated during APK installation

APK takes up a lot of space because runnable.oAT files are generated during APK installation

Arm processor

For a more detailed introduction to ART, please refer to Android ART

conclusion

Familiar with Android performance analysis tools, UI lag, APP startup, package slimming and memory performance optimization

Familiar with Android APP architecture design, modular, componentized, plug-in development

Proficient in Java, design pattern, network, multithreading technology

Java Basics

1. Java class loading process

The process by which the JVM loads. Class file information into memory and parses it into the corresponding class object. Note that the JVM does not load all classes into memory at first, but only once when it encounters a class that needs to be run

It is mainly divided into three parts: 1, loading, 2, link (1. Verification, 2. Preparation, 3. Parse), 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) in the constant pool with direct references (memory addresses). During parsing, the JVM replaces all class, method, and field names with specific memory addresses or offsets.

3: initialization

It primarily initializes class variables, performing the procedures of the class constructor; in other words, it initializes only variables or statements that are static fixes.

Example: Person Person = new Person(); Take as an example.

In Java programming, the initialization process of a class mainly includes the following points:

  1. Find the class file and load it into memory
  2. Allocates memory addresses in heap memory
  3. Initialize the
  4. Refers the heap memory address to the p variable in stack memory

2, String, StringBuilder, StringBuffer

Many methods in StringBuffer add the synchronized keyword to indicate thread-safety, so use it in multithreaded situations.

Execution speed:

StringBuilder > StringBuffer > String Copy codeCopy the code

StringBuilder sacrifices performance in exchange for speed. These two objects can be modified directly on the original object, eliminating the need to create new objects and recycle old objects. Strings are final String constants, and the other two are String variables. Variables can be modified, so operations on strings involve the following three steps:

  1. Create a new object with the same name as the original
  2. Make changes on the new object
  3. The original object is garbage collected

3. JVM memory structure

In the process of Java object instantiation, virtual machine stack, Java heap and method area are mainly used. Java files are first loaded into the JVM method area after compilation. The heavy part of the JVM method area is the runtime constant pool, which stores version, field, method, interface, and compile time constants and static constants for class file classes.

3.1. Basic structure of JVM

The classLoader, which loads the required. Class files into memory when the JVM starts or when the class is running. An execution engine that executes bytecode instructions contained in class files. Local method interface, mainly calls C/C++ implementation of local methods and returns results. The memory area (runtime data area), which is the area of memory allocated for operations while the JVM is running, is divided into the following five parts, as shown below:

  • Method area: A place to store class structure information, including constant pools, static variables, constructors, and so on.
  • Java heap: A place where Java instances or objects are stored. This is the main area of gc.
  • Java stack: Java stacks are always associated with threads, and each time a thread is created, the JVM creates a Java stack for that thread. This Java stack contains multiple stack frames, one created for each method run, to store local variables, operation stacks, method return values, and so on. The process of each method from invocation to completion corresponds to the process of a stack frame being pushed into and out of the Java stack. So the Java stack is thread private.
  • The program counter is used to store the memory address of the current thread execution. Since the JVM is multithreaded, to ensure that the thread can be switched back to the original state, a separate counter is needed to record the previous interrupt. 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 code analysis

www.jianshu.com/nb/12554212

4. GC mechanism

Garbage collectors generally do two things

  1. Detection of garbage;
  2. 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 new are not actively collected by the GC for garbage collection, even if they run out of memory.

Object obj = new Object(); Copy the codeCopy the code

Soft references: When out of memory, the GARBAGE collection is collected by the GC.

Object obj = new Object(); SoftReference<Object> softReference = new SoftReference<>(obj); Copy the codeCopy the code

Weak references: Whether memory is sufficient or not, the GC will collect it when it does garbage collection.

Object obj = new Object(); WeakReference<Object> weakReference = new WeakReference<>(obj); Copy the codeCopy 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 codeCopy the code

Reference queue: If soft and weak references are collected by GC, the JVM will add the reference to the reference queue, or if it is a virtual reference, it will be added to the reference queue before being collected.

Garbage detection method:

Reference counting: add a reference counter to each object, each place it is referenced, the counter is +1, when invalid -1. If two objects reference each other, they cannot be reclaimed. Reachability analysis algorithm: searches the root set object as the starting point. If the object is unreachable, it is junk. Root sets (objects referenced in the Java stack, objects referenced in the constant pool in the method area, objects referenced in local methods, and so on. During garbage collection, the JVM checks whether 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

Mark: mark all objects that need to be recovered first, and collect all marked objects after the mark is completed. Its marking process is the reachability analysis algorithm above. Clear: Clear all marked objects disadvantages: Low efficiency, low efficiency of both marking and clearing Space problems, after clearing marks will generate a large number of discontinuous memory fragments, resulting in large object allocation can not find enough space, garbage collection in advance.

The copy reclamation algorithm divides the available memory into two equal chunks according to the capacity. Only one chunk is used up at a time. When the memory of this chunk is used up, the surviving objects are copied to another chunk and the used memory space is cleared up at a time.

Disadvantages:

Reduced the memory of the original general, the cost is relatively high most of the object is “toward the birth of the evening”, so do not have to divide according to the ratio of 1:1. Now commercial virtual machines use this algorithm to reclaim the new generation, but instead of 1:1 ratio, the memory area is divided into three parts: 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 role exchange for replication. From and to Spaces, also known as survivor Spaces, are used to hold objects that have not been reclaimed.

At garbage collection, living objects in Eden space are copied to the unused survivor space (assuming to), and young objects in the used survivor space (assuming from) are copied to the TO space (large objects, If the to space is full, the object will enter the old age directly. At this point, the remaining objects in Eden space and from space are garbage objects and can be directly emptied, while to space stores the surviving objects after the reclamation. This improved replication algorithm not only ensures the continuity of the space, but also avoids a large amount of memory space waste.

Mark-tidy

In the old age, most objects are living objects, and the efficiency of the replication algorithm will become low when the survival rate of objects is high. According to the characteristics of the old days, someone proposed “Mark-compact algorithm”.

The marking process is the same as mark-clean marking, but instead of cleaning up the recyclable objects afterwards, all objects are moved to one end and memory is cleaned up directly beyond the end boundary.

This method not only avoids fragmentation, but also does not require two identical memory Spaces, so it is cost-effective.

Band collection algorithm

The memory is divided into several blocks according to the different life cycle of the object, generally the Java heap is divided into old and new generation, so that the appropriate collection algorithm is adopted according to the characteristics of each generation.

A large number of objects die and only a few survive in each collection of the new generation, so the replication algorithm is selected, and the collection can be completed with a small number of objects copied. Old age object survival rate is high, use mark-compression algorithm to improve garbage collection efficiency.

Class loaders

When the program is started, it does not load all the class files used by the program at one time. Instead, it dynamically loads a certain class file into the memory through the Java ClassLoader as required by the program. Therefore, only the class file is loaded into the memory. Can be referenced by other classes. So the ClassLoader is used to dynamically load class files into memory.

5.1 Principle of parental delegation

Each ClassLoader instance has a reference to a parent ClassLoader (not an inheritance relationship, but an containing relationship). The built-in Bootstrap ClassLoader does not have a parent ClassLoader itself, but can be used as a parent ClassLoader for other ClassLoader instances.

When a ClassLoader instance needs to load a class, it will try to delegate the task to its parent ClassLoader before searching for the class itself. This process is checked from top to bottom, starting with the top-level ClassLoader Bootstrap ClassLoader. Then the task is transferred to the Extension CLassLoader view for loading. If not, the task is transferred to the AppCLassLoader for loading. If not, the delegate initiator is handed over to the specified file system or network URL for loading the class. If not, a CLassNotFoundException is thrown. Otherwise, the Class generates a Class definition, loads it into memory, and returns an in-memory Class instance object of the Class.

5.2. Why use the parent Delegation model

When determining whether two classes are the same, the JVM determines not only whether they have the same class name, but also whether they were loaded by the same classloader.

Avoid reloading. If the parent class has already been loaded, there is no need to load the child CLassLoader again. For safety reasons, if a user defines a String class, the default search algorithm for the CLassLoader in the JDK is changed. Otherwise, the user defines a String class. Because the String class is loaded by the Bootstrap CLassLoader at startup.

For details about the Android parental delegation mechanism, see the Android ClassLoader parental delegation mode

6, collections,

Java Collection 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. There is no direct implementation class for this interface in Java. Instead, it inherits two interfaces, Set and List. A Set cannot contain duplicate elements. A List is an ordered collection that can contain repeating elements, providing access by index.

Map is another interface in the java.util package. It is separate from the Collection interface, but both are part of the Collection class. The Map contains key-value pairs. A Map cannot contain duplicate keys, but it can contain the same values.

6.1, the difference between

List and Set inherit from Collection interface, Map does not. List features: Elements can be placed in order, elements can be repeated; The position of the elements in a Set is determined by the element’s HashCode. Objects added to a Set must define equals(). LinkedList, ArrayList, and HashSet are thread-safe; Vector is thread-safe; HashMap is thread-safe, HashTable is thread-safe;

6.2. Comparison between List and Vector

Vector is multithread safe, which means that multiple threads accessing the same code can produce no uncertain results. ArrayList does not. As can be seen from the source code, many of the methods in the Vector class are modified by synchronized, so that Vector cannot compare with ArrayList in efficiency. Both use linear contiguous space to store elements, but when space runs out, the two classes grow differently. Vector can set growth factors, whereas ArrayList cannot. Vector is an old dynamic array that is thread-synchronized, inefficient and generally frowned on.

6.3 How can hashsets be guaranteed to be non-repetitive

The underlying implementation of a HashSet is a HashMap, where you add elements to a HashSet

public boolean add(E e) {
return map.put(e, PRESENT)==null;
}


// Dummy value to associate with an Object inthe backing Map private static final Object PRESENT = new Object(); Copy the codeCopy the code

If the key exists in a HashMap, the value is always the same.

  • If the hash code values are different, it is a new element and is saved.
  • If the hash code values are the same and the EQules judgment is equal, it indicates that the elements already exist and do not exist.
  • If the hash code values are the same and the EQules judgments are not equal, it indicates that the elements do not exist and exist.
  • If there are elements that are equal to the hash value of the incoming object, then proceed with the equles() judgment. If they are still equal, then the incoming elements are considered to already exist and are not to be added again, end, otherwise the incoming elements are still added;

6.4 Application scenarios of HashSet and Treeset

  • A HashSet is implemented based on a Hash algorithm and generally performs better than TreeSet. For sets designed for quick lookups, we should usually use hashSets, and TreeSet is used only when we need sorting capabilities.
  • TreeSet is implemented by binary tree (tree data structure of red-black tree). 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, and null can be placed in a HashSet, but only one NULL can be placed in a HashSet. The values in both cannot be repeated, just like a unique constraint in a database.
  • A HashSet is implemented based on a Hash algorithm and generally performs better than TreeSet. For sets designed for quick lookups, we should usually use hashSets, and TreeSet is used only when we need sorting capabilities.

6.5 Differences and application scenarios of HashMap, TreeMap and HashTable

HashMap is a non-thread-safe implementation based on hash tables (hash tables). The key classes required to be added using 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 conflict handling of hash table, one is open addressing method and the other is linked list method. The implementation of HashMap uses a linked list method. TreeMap: Non-thread-safe is implemented based on a red-black tree. TreeMap has no tuning options because the tree is always in balance

Constant pool

7.1 128(-128~127) in Interger

If the value ranges from -128 to 127: If two new objects come out with the same value, the result will be false by “==”, but the result will be “true” by “==”, much like String. When the value is not in the range of -128 to 127, the result is false even if the two objects have the same value. When an Integer object is directly compared with an int base datatype by “==”, the result is the same as in the first point; Integer The hash value of the object is the value itself;

@Override
public int hashCode() {
returnInteger.hashCode(value); } Duplicate codeCopy the code

7.2、为什么是-128-127?

The Integer class has a static inner class, IntegerCache, and an Integer array in the IntegerCache class to cache Integer objects in the range -128 to 127.

8 and generic

Generics are a new feature in Java SE 1.5. The nature of generics is parameterized typing, which means that the data type being operated 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 benefit of the introduction of generics into the Java language is security and simplicity.

The benefit of generics is 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 runtime.

When using Java generics, note the following:

  • The type parameters of a generic type can only be class types (including custom classes), not simple types.
  • There can be multiple versions of the same generic (because parameter types are indeterminable), and different versions of generic class instances are not compatible.
  • A generic type can have multiple type parameters.
  • Parameter types of generics can use extends statements, for example. It is conventionally called a bounded type.
  • Parameter types of generics can also be wildcard types. Such as Class
    classType = Class.forName(“java.lang.String”);

8.1T and wildcard generics

  • ? Represents an indeterminate Java type.
  • T stands for Java type.
  • K and V represent Key values in Java.
  • E is for Element.

8.2 Generic erase

Generics in Java are basically implemented at the compiler level. The type information in generics is not contained in the generated Java bytecode. Type parameters added when using generics are removed by the compiler at compile time. This process is called type erasure.

Generics are implemented through type erasure, where the compiler erases all type-related information at compile time, so there is no type-related information at run time. For example, List is represented at run time by a single List. The goal is to ensure compatibility with the binary libraries developed prior to Java 5. You cannot access type parameters at run time because the compiler has converted generic types to primitive types.

8.3 Qualifying wildcards

One is <? Extends T> This extends T> sets an upper bound on a type by ensuring that it must be a subclass of T. The other is <? Super T> it sets the lower bound of the type by ensuring that it must be a parent of T. On the other hand, unqualified wildcards are represented because they can be replaced by any type. For example the List <? Extends Number> can take a List or List.

8.4 Generic interview questions

Can you pass a List to a method that takes a List argument? For anyone not familiar with generics, this Java generics topic may seem confusing, because at first glance String is an Object, so List should be used where List is needed, but it isn’t. Doing so will result in a compilation error. If you think a little bit deeper, you’ll see that this makes sense because lists can store any type of object including Strings, integers, and so on, whereas lists can only store Strings.
Can generics be used in Array?

Array doesn’t actually support generics, which is why Joshua Bloch, in Effective Java, recommends using lists instead of arrays, because lists provide compile-time type safety, whereas arrays don’t.

9, reflection

9.1, concepts,

The JAVA reflection mechanism allows you to know all the properties and methods of any class in the running state. For any object, you can call any of its methods; This ability to dynamically retrieve information and invoke methods on objects is called the Reflection mechanism of the Java language.

9.2,

Java reflection provides the following functions: determine the class of any object at runtime; Construct an object of any class at runtime; Determine which member variables and methods any class has at run time. Call a method of any object at runtime; Generate dynamic proxies.

Data structures and algorithms

Zhuanlan.zhihu.com/p/27005757?…

Crazyandcoder. Tech / 2016/09/14 /…

1, sorting,

Sort internal sort and external sort, internal sort is the data records in memory sort, and external sort is because the sort of data is very large, can not accommodate all sort records, in the sort process need to access external memory.

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. For number four, number five… Repeat step 2 until the last number. Code:

Int I =1; for(int I =1; i<length; I++), I don’t have to insert that one. Sets the insertion number and gets the number of digits of 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:

  1. A singleton class has only one instance
  2. A singleton class must create its own unique instance
  3. The singleton class must provide this instance to all other objects.

In computer systems, things like thread pools, caches, log objects, dialogs, printers, and so on are often designed as singletons.

Lazy singleton:

Singleton avoids being instantiated externally by limiting the constructor to private; within the same virtual machine scope, the only instance of a Singleton can be accessed only through the getInstance() method. (In fact, it is possible to instantiate classes with private constructors through Java reflection, which essentially invalidates all Java singleton implementations.

It is thread-unsafe, and multiple Singleton instances are likely to occur in concurrent cases. There are three ways to achieve thread-safe Singleton: 1. Add synchronization to the getInstance method

2. Double-check lock

Static inner classes

Compared with the previous two methods, this method not only achieves thread safety, but also avoids the performance impact caused by synchronization.

Hangry singleton:

The hungry type at the same time of creating a class has created a static object for the use of system, won’t change, so naturally is the security system.

other

Juejin. Im/post / 5 a3717… Github.com/Mr-YangChen…