Computer Fundamentals


1. Source code inverse code complement

1. The original and complementary codes of positive numbers are the same, which are converted to binary form and then added with 0. For example, for 8 bits:

  • 10 corresponds to the source code’s inverse complement is 0000 1010

2. For negative numbers, the source code of a negative number is the binary corresponding to its absolute value, and the highest bit is 1. So:

  • The source code for 10 is 1000, 1010

3. The inverse of a negative number is the inverse of all bits except the highest bits of its source code, so:

  • The inverse of 10 is 1111 0101

4. The complement of negative numbers is the inverse value +1, so:

  • The complement of 10 is 1111 0110

2. The percentage of the eight basic Data types in JAVA

3. Move left and right

There are three types of shift operators in Java:

  • The left < <

To move the left operand is to move the binary data in memory to the left by a specified number of bits, and to fill the left part with zeros. Num << n is the same thing as num times 2 to the n

  • Moves to the right > >

Right shift: truncate the right side and fill the left side with sign bits (1 for negative and 0 for positive). Num >> n is the same thing as num divided by 2 to the n

  • Unsigned move right >>>

Unsigned right shift whatever the highest bit is, the space fills zero, right

4. Three handshakes

The main purpose is to ensure that the ability of the server and client to receive and send data is normal.

  • First time: The client sends data to the server
  • Second: After receiving data, the server sends data to the client. These two prove: client sending capability, server sending and receiving capability is good
  • Third time: The client sends data to the server to tell the server that the data is received, indicating that the client is good at receiving data

Java based


1. How to implement HashMap, what if hashCode conflicts, why is thread unsafe, what is the difference from Hashtable

  • Inserts are done primarily by calculating the hashCode of the data
  • HashCode is stored in array and linked list only when the same element is inserted into the same linked list.
  • Multiple threads can simultaneously put data, and if the same hashCode is pushed at the same time, subsequent data can override the previous data. Hashtable uses synchronized on almost every method to make it thread-safe
  • The HashMap thread is not safe, and it is possible to create a linked list for concurrent inserts, causing an infinite loop for the next read
  • ConcurrentHashMap is thread-safe and uses a segmented lock. Each Segment has its own lock. It reduces the granularity of locks while ensuring thread safety, making concurrent operations more efficient
  • What is a HashMap
  • HashMap at high concurrency
  • What is a ConcurrentHashMap
1.1 Initial length of a HashMap

A Hash function is used to map the Key to the corresponding position in the HashMap array: index = HashCode (Key) & (length-1). The initial Length of the HashMap is 16 or some other power of 2, and the Hash algorithm is uniform

2. What are the differences between synchronized and synchronized methods

public synchronized void run(a)  {
    System.out.println(1);
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
    }
    System.out.println(2);
}
Copy the code
  • Synchronized modifies ordinary methods with the this object and uses two objects to access them, not the same lock
Demo demo = new Demo();
new Thread(() -> demo.run()).start();
Demo demo2 = new Demo();
new Thread(() -> demo2.run()).start();
Copy the code

The result is: 1, 1, 2, 2

Out of sync. But if you use the same object access, the results are synchronous

Demo demo = new Demo();
new Thread(() -> demo.run()).start();
new Thread(() -> demo.run()).start();
Copy the code

Output: 1 2 1 2

  • When synchronized modifies static methods, the lock object is the bytecode file object of the current class. With different object access, the result is synchronous, because when modifying static methods, the lock object is a class bytecode file object, and the two objects are the same class file, so one lock is used

3. Final, finally, Finalize difference

  1. The final keyword is used before basic data types: this indicates that the variable modified by the keyword is a constant and its value cannot be modified after definition. The final keyword is used before a method declaration: this means that the method is the final method and can only be called, not overridden, but can be overridden. The final keyword is used before the class name: the class is called final and cannot be inherited by other classes.

  2. With the try {

} Catch (){} When an exception is caught, the code in the finally block executes regardless of the roommate’s exception.

  1. Finalize method comes from java.lang.Object and is used to recycle resources.

You can add finalize methods to any class. The Finalize method will be called before the garbage collector cleans up the object

4. Java into static inner class and non-static inner class characteristics

  • Static inner classes: They have no “strong dependencies” on external classes and are not coupled enough to create separate instances. Since static inner and outer classes don’t keep references to each other, you can save a bit of memory to some extent
  • The inner class requires access to all properties and methods of the outer class

5. Strong, weak, soft, and virtual references

  • Strong references: When running out of memory, the Java virtual machine would rather throw outofMemoryErrors than reclaim them
  • Soft references: When there is enough memory, the garbage collector does not reclaim it; If you run out of memory, the objects are reclaimed. \

When out of memory, the JVM first sets the object reference in the soft reference to NULL, and then notifies the garbage collector for collection

  if(JVM out of memory) {// Set object references in soft references to NULL
        str = null;
        // Notify the garbage collector to collect
        System.gc();
   }
Copy the code
  • Weak references: When the garbage collector thread scans the memory area under its control, once it finds an object with only weak references, it reclaims its memory regardless of whether the current memory space is sufficient. However, because the garbage collector is a low-priority thread, objects that have only weak references are not necessarily found quickly
  • Virtual reference: Virtual reference, as its name implies, is a virtual reference. Unlike the other references, virtual references do not determine the lifetime of the object. If an object holds only virtual references, it can be collected by the garbage collector at any time, just as if there were no references at all

They are Atomic

Still using Synchronized? Atomic, do you understand?

7. Multithreading concurrency problem

Multithreaded concurrency problem

volidate

  • The cause of double void call in singleton
    • 1. First nullates: Improves efficiency by eliminating the need to execute synchronized blocks every time
    • 2. Second null: prevents new multiple instances
  • The reason for the double empty and volidate of a singleton is that the value of the instance’s member variables may not be correct in order to prevent the instruction from reordering when the instance is initialized and another thread gets the instance when the new operation is only half completed
  • Volidate only guarantees visibility and order, not atomicity. Volidate does not guarantee thread-safety when multiple threads simultaneously write to a variable modified by Volidate (for example, when multiple threads simultaneously work on a modified by Volidate a++, the resulting number may not be the same as expected, if a=1 and a++ is refreshed twice to 2, Because a++ is actually multiple operations.)
7.1 Thread sleep method
  • Lock not released

    throughsynchronizedSynchronized blocks implement locking mechanisms. threadtv1Three seconds after sleep, the threadtv2In therun()Method code is executed because it can’t get the lock and is blocked
        var t1: Thread = object : Thread() {
        override fun run(a) {
              synchronized(any){
                  println("The thread starts sleeping.")
                  Thread.sleep(3000)
                  println("Thread one sleep over.")}}}var t2: Thread = object : Thread() {
            override fun run(a) {
               synchronized(any){
                   println("Thread 2 goes to sleep.")
                   Thread.sleep(3000)
                   println("Thread 2 sleep finished")
               }
            }
        }
        t1.start()
        t2.start()
        
        // Log output
        14:13:24.660 1805-1836/ I/System.out: The thread starts sleeping14:13:27.663 1805-1836/ I/System.out: Thread one sleep is over14:13:29.555 1805-1837/ I/System.outThread:2Began to sleep14:13:32.556 1805-1837/ I/System.outThread:2Sleep overCopy the code
  • Threads can be interrupted during sleep

    Thread 1 is interrupted by thread 2 during sleep
        var t1: Thread = object : Thread() {
            override fun run(a) {
                println("The thread starts sleeping.")
                try {
                    Thread.sleep(30000)}catch (e: InterruptedException) {
                    println("===error=== ")
                }
                println("Thread one sleep over.")}}var t2: Thread = object : Thread() {
            override fun run(a) {
                Thread.sleep(3000)
                t1.interrupt()
            }
        }
        t1.start()
        t2.start()
    Copy the code
  • sleep(0)
    • Before a thread exits, it has three states: ready, running, and wait
    • The reason why sleep(n) does not participate in CPU contention for n seconds is that, when the thread calls sleep(n), the thread changes from the running state to the wait state and is put into the wait queue. After n seconds, the thread changes from the wait state to the ready state and is put into the ready queue. The thread in the wait queue does not participate in CPU contention. Only threads in the ready queue compete for the CPU
    • The so-called CPU scheduling is based on a certain algorithm (priority, FIFO, etc…). To allocate CPU time, select a thread from the ready queue.
    • The reason why sleep(0) goes right back into the CPU race is because when sleep(0) is called, the thread goes straight back to the ready queue because of 0, instead of going into the wait queue, as long as it’s in the ready queue, it’s in the CPU race

8. Can the main thread catch child thread exceptions directly?

try{
    new Thread(){
        public void run(a){
            if(...).throw new RuntimeException(); 
        }
    }.start();
}catch(Exception e){
}
Copy the code

The answer is no.

  • Threaded code cannot throw any checked exceptions. All checked exceptions in a thread can only be digested by the thread itself
  • The thread interrupts after the child thread code throws a run-level exception. The main thread is unaffected by this, does not handle the RuntimeException, and does not catch it at all. Will continue to execute their own code

9.The thread pool

Thread pool resolution

How does a thread pool reuse idle threads to perform tasks? The core thread blocks and does not close when there is no task

10. Difference between TreeMap and HashMap

  • The Key value of TreeMap

    requires java.lang.Comparable. Therefore, TreeMap iterates in ascending order by default. TreeMap’s implementation is based on a red-black tree structure. It is applicable to traverse keys in natural or custom order.
    ,v>
  • HashMap

    implements hash hashCode(). The distribution is hash, uniform, and does not support sorting; Data structures are mainly buckets (arrays), linked lists, or red-black trees. Suitable for inserting, deleting, and positioning elements in a Map
    ,v>
  • You should use TreeMap if you want to get an ordered result (because the order of elements in a HashMap is not fixed). In addition, since HashMap has better performance, we use HashMap most of the time when sorting is not required

11. Difference between synchronized and ReentrantLock

  • ReentrantLock can implement a fair lock mechanism, while synchronized is a non-fair lock mechanism
  • Synchronized will automatically release the lock occupied by the thread when an exception occurs, so the deadlock phenomenon will not occur. If the Lock is abnormal, a deadlock may occur if it is not actively released. Therefore, use unLock() in finally to release the Lock

Kotlin


1. Process, thread, coroutine

Coroutine coroutines

  • Process: When you open a piece of software, you start a process. There is a separate memory space.
  • Thread: The smallest unit of operation performed by the operating system, with a separate stack. It is included in the process. A process can have multiple threads

Threads can share resources, but processes cannot

  • Coroutines: Just as a process can have multiple threads, a thread can have multiple coroutines

The suspension of the coroutine is completely controlled by the program. The blocking state of the thread is switched by the operating system kernel. The suspension of the coroutine does not block the thread. Therefore, switching between coroutines does not consume resources as thread switching does.

2. Create a blocking difference between launch and runBlocking

The delay in runBlocking does not block the thread created by launch

     GlobalScope.launch {
            delay(1000) // Does not block
            println("111111111111111")
        }
        Thread.sleep(200)
        println("2222222222")


        runBlocking {
            delay(1000) / / blocking
            println("33333333")
        }
        Thread.sleep(200)
        println("44444444444") Output results2020-12-11 1809:41.178 29211-29211/ I/System.out: 2222222222
    2020-12-11 1809:41.980 29211-29279/ I/System.out: 111111111111111
    2020-12-11 1809:42.181 29211-29211/ I/System.out: 33333333
    2020-12-11 1809:42.383 29211-29211/ I/System.out: 44444444444
Copy the code

3. Async () and launch() can both get a return value. What’s the difference

If a page needs to request two interfaces, the data returned by both interfaces is used to render the page. Launch () is serialized. Time consuming

mainScope.launch {
    / / access token
    val token = getToken()
    // Obtain userInfo by token
    val userInfo = getUserInfo(token)
    // Login succeeded
    Logger.i("login success, token: $token, userInfo is null: ${userInfo == null}")} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -suspend fun getUserInfo(token: String): UserInfo {
    return withContext(Dispatchers.Default) {
        Logger.i("get userInfo, token: $token")
        val userInfo = api.getUserInfo(token)
        userInfo
    }
}
suspend fun getToken(a): String {
    return withContext(Dispatchers.Default) {
        Logger.i("get token")
        val token = api.getToken()
        token
    }
Copy the code

Async () allows two requests to be made simultaneously, which is more efficient


Android Basics


1. The stars

  • The Looper is instantiated using the prepare method, which is used to fetch a new Looper from the sThreadLocal member. Only one Looper instance can be created per thread
private static void prepare(boolean quitAllowed) {
    if(sThreadLocal.get() ! =null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}
Copy the code
  • Looper uses the loop method to open the loop queue, which opens an infinite loop and blocks if there is no MSG
  • The looper.PrepareMainLopper () method is already called in the Main method of the ActivityThread when the Activity starts
  • It is not possible to use new Handle() in a child thread, because looper.prepare () is not called beforehand, so null is obtained

2. Use of ThreadLocal in Looper

To solve the problem of multiple threads accessing the same data, the idea of a synchronous lock is that threads cannot access an area of memory at the same time. The idea with ThreadLocal is to give each thread a Copy of exactly the same object, and each thread plays with its own object without affecting the other

  • ThreadLocal’s set method
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if(map ! =null)
            map.set(this, value);
        else
            createMap(t, value);
}
Copy the code
  • Get method of ThreadLocal
 public T get(a) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if(map ! =null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if(e ! =null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                returnresult; }}return setInitialValue();
 }
Copy the code

In short: Get the current thread, then get a ThreadLocalMap from the current thread to store data. (ThreadLocalMap is a Thread member variable.)

  • Handler. postDelay inserts messages directly into MessageQueue, in a combination of MessageQueue chronology and wake up.
  • Each thread has a threadLocals variable of type ThreadLocalMap, where the key is the instance reference of ThreadLocal and the value is the corresponding local variable. If the thread doesn’t die and the developer doesn’t use remove to remove variables that are no longer in use, those variables will stay in the map until they overwhelm your memory and cause an overflow problem

3. The Service and the IntentService

The Activity responds to events in less than 5 seconds, the BroadcastReceiver executes them in less than 10 seconds, and the Service takes 20 seconds. Otherwise, the system reports ANR

  • After the service is enabled using the startService() method, there is no connection between the caller and the service. If the caller simply exits without calling stopService, the Service will always run in the background
  • Using the bindService() method to enable the service, the caller is bound to the service and the service terminates automatically once the caller exits
  • IntentService is a subclass of Service that creates child threads to handle all intEnts. The code that implements the onHandleIntent() method does not need to handle multithreading

4. The difference between FragmentPageAdapter and FragmentPageStateAdapter

  • The FragmentPageAdapter does not completely destroy the Fragment each time the page is switched. It works for fixed, small fragments. The default notifyDataSetChanged() refresh is invalid

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

5.Sqlite database, what are transactions

A transaction is a whole composed of one or more SQL statements. If all statements are executed successfully, the changes will all take effect. If one SQL statement will add sales +1, the next one will add sales +1, and if the second one fails, the sales will cancel the +1 operation of the first SQL statement. Sqlite database operations will be added to the database only after all statements in the transaction have been successfully executed. These operations include creating, adding, deleting, modifying, and searching transactions

6. How to upgrade Sqlite database

  1. Delete the old database directly, but data loss may occur. Therefore, do not delete the old database directly
  2. To upgrade the database, see Upgrading the SQLite Database version

7. Invalidate differs from requestLayout

  • A view call to invalidate causes a redraw of the current view, and a viewGroup call to invalidate causes a subview of the viewGroup to call draw
  • The requestLayout method only results in measures and layouts of the current view, and draw is not necessarily executed. The draw method is executed only when the view’s position changes

8. Difference between View and ViewGroup

  • ViewGrouptheonInterceptTouchEventThe default returns false, that is, events are not intercepted,ViewThere is no intercept event method,ViewConsumes events by default
  • ViewGroupThe onDraw method is not called by default,ViewThe onDraw method is called by default. Can be achieved bysetWillNotDraw(boolean willNotDraw)To specify whether to call the onDraw method
    /**
     * If this view doesn't do any drawing on its own, set this flag to
     * allow further optimizations. By default, this flag is not set on
     * View, but could be set on some View subclasses such as ViewGroup.
     *
     * Typically, if you override {@link #onDraw(android.graphics.Canvas)}
     * you should clear this flag.
     *
     * @param willNotDraw whether or not this View draw on its own
     */
    public void setWillNotDraw(boolean willNotDraw) {
        setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
    }
Copy the code

9. New features in the Android version

  • 5.0
    • Introduce the Material Design theme
  • 6.0
    • Runtime permissions
  • 7.0
    • File read and write permissions are adapted to the FileProvider
    • Remove support for the Apache HTTP client and use HttpURLConnection instead. To continue using the Apache HTTP API, you must first configure it in the build.gradle file:
        android {
            useLibrary 'org.apache.http.legacy'
        }
    Copy the code
  • 8.0
    • Allocate channels for all notifications
    • Update the downloaded APK file within the APP, requiring the user to enable the unknown application installation permission
  • 9.0
    • Using secure network access, an error is reported if an HTTP request is used. Android 9.0 network adapter
  • 10.0
    • Storage space partitioned storage, sandbox mode

10. How to calculate the memory size of an image in Android

How to calculate the memory size of an image in Android

  • When images are from different resource directories in res, the system performs a resolution conversion based on the current DPI value of the device and the corresponding DPI value of the resource directory. The rules are as follows: New resolution = Horizontal resolution of original image * (DPI of the device/directory) * Vertical resolution of original image * (DPI of the device/directory)
  • Other image sources, such as disk, file, stream, etc., are used to calculate the image memory size according to the resolution of the original image
  • The memory size of an image is calculated by the following formula: resolution * pixel size; But the resolution is not necessarily the resolution of the original image, it needs to be discussed in combination with some scenes, pixel size is in several cases: ARGB_8888(4B), RGB_565(2B) and so on

11. Optimized APP startup speed

  • The adb command can be used to check the startup time as shown in the following example:
adb shell am start -W [packageName]/[.MainActivity]
./adb shell am start -W "com.hchstudio.dict"/".MainActivity"
Copy the code

WaitTime is the startup time we care about

  • The startup process of app mainly needs to reduce the onCreate method of Application and startup interface
  • Add android:windowBackground and put the background picture of the app, so that even if the app starts slowly, the background will be loaded first, which will give the user an illusion that the app has been started
<! --AppTheme.Launcher is the theme style for the launch screen -->
<style name="AppTheme.Launcher">
    <item name="android:windowBackground">@color/colorLauncher</item>
</style>
Copy the code

12. Memory jitter

Memory jitter is caused by a large number of objects in and out of the new area in a short time. It is accompanied by frequent GC, which will occupy a large amount of UI threads and CPU resources, resulting in the overall app lag.

Tips for avoiding memory jitter:

  • Try to avoid creating objects inside the loop and move object creation outside the loop.
  • Note that the onDraw() method of a custom View is called frequently, so objects should not be created frequently in this View.
  • When you need to use a lot of Bitmaps, try caching them in arrays or containers for reuse.
  • For objects that can be reused, you can also cache them using object pools.

13.Android ClassLoader types & features:

  • BootStrap ClassLoader (Java) :

Used to load the Android Framework layer class file.

  • PathClassLoader (Java App ClassLoader) :

Only the dex file of apK that has been installed can be loaded

  • DexClassLoader (Java Custom ClassLoader) :

Dex files can be loaded from a JAR package or from an uninstalled APK

  • BaseDexClassLoader:

Is the parent of PathClassLoader and DexClassLoader.

14. Why can’t SharePreference store large values

  • The main thread is blocked when fetching data (for example, wait() is called in getString())
    public String getString(String key, @Nullable String defValue) {
    	synchronized (this) {
        		awaitLoadedLocked();
        		String v = (String)mMap.get(key);
        		returnv ! =null? v : defValue; }}private void awaitLoadedLocked(a) {
    	while(! mLoaded) {try {
            	wait();
        	} catch (InterruptedException unused) {
    	}
    }
    Copy the code
  • When SharePreference stores values, there’s a static map inside that holds all of your keys and values
    private ArrayMap<File, SharedPreferencesImpl> getSharedPreferencesCacheLocked(a) {
    	if (sSharedPrefsCache == null) {
        		sSharedPrefsCache = new ArrayMap<>();
    	}
    
    	final String packageName = getPackageName();
    	ArrayMap<File, SharedPreferencesImpl> packagePrefs = sSharedPrefsCache.get(packageName);
    	if (packagePrefs == null) {
        		packagePrefs = new ArrayMap<>();
        		sSharedPrefsCache.put(packageName, packagePrefs);
    	}
    
    	return packagePrefs;
    }
    Copy the code

15. Several ways to achieve View sliding

  • The View itself provides scrollTo() and scrollBy methods. But it’s only good for swiping the contents of a View
  • Use animations. However, the View click after sliding has no effect, so it is suitable for the View without interaction
  • Change layout parameters, such as layoutparams.left. Slightly more complex than animation, suitable for interactive views

Use Scroller. Call the startScroll method, and then invidate() –> View will call onDraw(), which will call computeScroll(). This method defaults to an empty implementation and needs to be implemented itself –> Override computeScroll() to slide. Redrawn postInvalidate ()

16. Distribution of events

  • The source code
// 1. the Activity's dispatchTouchEvent() method
public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        // Call PhoneWindow
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
}

// 2. PhoneWindow superDispatchTouchEvent() method
public boolean superDispatchTouchEvent(MotionEvent event) {
		// Pass it to the DecorView
        return mDecor.superDispatchTouchEvent(event);
}
// 3. Since DecorView is a FrameLayout subclass, the event is passed to a child of the DecorView (setContentView)
Copy the code
  • View event distribution

17. The View of measurement

View presentation process

  • Create a Window
  • Create a DecorView
  • The Window is displayed on the screen through the WindowManager.addView() method, which creates ViewRootImpl objects for each Window to connect to the WindowManager and DecorView, And all the operations that The Window wants to do to the View are done via View View PL
  • Call the measure method of the DecorView, which in turn calls the onMeasure method to pass the measurement to the child View. Call the Layout method, which calls the onLayout method to pass the layout process to the child View. The darw method is called and the dispatchDraw method is called from the DRAW method to pass the drawing process to the child View
  • DecorView’s MeasureSpc is simply derived from its LayoutParams
    • Match_parent Exact mode, where the size is the size of the window
    • Wrap_content Maximum mode. The size is variable and cannot exceed the window size
    • Fixed value exact mode, size as specified in LayoutParams
  • A child View’s MeasureSpec is a parent View’s MeasureSpec and a child View’s LayoutParams

  • The onMeasure() task is to calculate the exact measuredWidth and measuredHeight. So subviews need to override the onMeasure method to store their desired measurements

Difference between getWidth() and getMeasuredWidth()

18. Memory leaks

Make a mountain out of a molehill | memory leak simple ask, can you answer

Why a memory leak occurs: A memory leak occurs when an object should be destroyed but cannot be destroyed because it is held by another object. For example, memory leaks caused by handlers. The Activity is destroyed, but the handleMessage method is called after the destruction, and the inner class still holds a reference to the external class Activity. Solution: 1. Declare the inner class static (kotlin inner classes are static by default) 2. 3. Replace the activity with a longer lifetime such as applicationContext

  • Why does an inner class hold an outer class reference

This is because a reference to the outer class is passed into the inner class constructor at compile time

/ / the original code
class InnerClassOutClass{
    class InnerUser {
       private int age = 20; }}/ / class code
class InnerClassOutClass$InnerUser {
    private int age;
    InnerClassOutClass$InnerUser(InnerClassOutClass var1) {
        this.this$0 = var1;
        this.age = 20; }}Copy the code

19.Activity, View,Window

  • An Activity contains a Window object, which is implemented by PhoneWindow
  • PhoneWindow uses the DecorView as the root View of the entire application window
  • In turn, the DecorView divides the screen into two areas: the TitleView and the ContentView, which is what we normally write to display

Fragment life cycle

Android Framework Knowledge


Implementation principle of Buttnife

The findViewById and setOnClickListener operations are performed in Java files dynamically generated by the annotation processor

Implementation principle of EventBus

  • When you register, pass in this, get the class, and then reflect all the methods of the class to find the subscription method
  • Store subscribed methods of different event types together in the same list(event type determines how subscribed methods execute when notified, MAIN thread calls, POSTING default mode, publisher and subscriber execute in the same thread)
  • How can messages be processed in the main thread after child threads publish them? Looper through main thread (mainLooper)
  • Called by reflection after receiving a notification
  • How do you prioritize? In 2, methods are added according to their priorities. The higher the priority, the first method is added
  • How are sticky events saved and sent? After sending a sticky event, the event is cached, and when the class that subscribed to the event calls the register() method, it receives the saved event

LiveData principle

The principle of LiveData notification to other components is primarily the observer design pattern. MutableLiveData is commonly used on Android

 public class MutableLiveData<T> extends LiveData<T> {
    // not used in the main thread
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    // used in the main thread
    @Override
    public void setValue(T value) {
        super.setValue(value); }}Copy the code

Notifies the Observer of data changes and requests observable change data to pass through the Observer’s postValue or setValue method of LiveDataonChangedConduction out

Its advantages are

  • Follow the application lifecycle. For example, LivaeData does not notify the Activity(Observer) when data is updated in an Activity but the Activity is already in the destroy state.
  • There is no memory leak (LiveData only notifies active Observers to update the UI. Inactive observers will not be notified of updates even if they subscribe to LiveData.

LiveDatatheobservemethods

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if(existing ! =null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if(existing ! =null) {
            return;
        }
        // Associate LifecycleBoundObserver with the activity or fragment's lifeCycle
        owner.getLifecycle().addObserver(wrapper);
    }
Copy the code

A decorator LifecycleBoundObserver

 class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive(a) {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
                // Data changes. If the activity or fragment has been destroyed, unsubscribe to avoid memory leaks
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return; } activeStateChanged(shouldBeActive()); }...Copy the code
public interface Observer<T> {
    /**
     * Called when the data is changed.
     * @param t  The new data
     */
    void onChanged(@Nullable T t);
}

Copy the code

The first parameter can pass the activity directly, return if the activity has been destroyed, otherwise owner.getlifecycle ().addobServer (wrapper); ,LiveData calls the postValue or setValue method to call back the Observer onChanged method

  • The LiveData Observe method receives the activity’s getLifeCycle(aware of the activity lifecycle) and Observer(adding an Observer to the LiveData’s internal collection).
  • LiveData’s setValue method notifies all observers of the data and unsubscribs between them if actiivty has been destroyed. Otherwise the onChange(T T) method for all observers will be executed

This data processing logic resides in the ViewModel and notifies the observer when the UI needs to be updated, without worrying about memory leaks

ViewModel

  • Processing logic
  • The ViewModel stores data that is not lost after the activity rotates
  • Data sharing

Lifecycle

App optimization

  • Memory optimization: Use LeakCanary to capture memory leaks, or use Android Studio to capture memory information and analyze memory leaks through Profiler
  • Volume optimization
    • Use SVG instead of PNG for uncomplicated images. Use shaders when peels to reduce image resources
    • Build file Configuration
      • Preserve the specified language
      • Retain the specified SO library schema
      • Turn on obfuscation compression

Glide

  • Glide cache
    • Glide caching mechanism is roughly divided into three layers: Lru algorithm cache, weak reference cache, disk cache
    • The order of reading is: Lru algorithm cache, weak reference cache, disk cache.
  • Glide.with(this) .load("http://www.baidu.com/img/bdlogo.png") .into(imageView);
    • The with() method configures the RequestManager
    public static RequestManager with(FragmentActivity activity) {
         return getRetriever(activity).get(activity);
    }
    Copy the code
    • The load() method configures the RequestBuilder
    public RequestBuilder<Drawable> load(@Nullable Object model) {
         return asDrawable().load(model);
    }
    Copy the code
    • The into() method sets up the imageView to load images from the thread pool
  • Small memory footprint
    • The default format is RGB_565
  • Support the GIF
  • Bind to the Activity lifecycle without memory leaks
      1. When Glide is bound to an Activity, a UI-free Fragment is generated
      1. LifeCycle of a UI-free Fragment is passed into the RequestManager
      1. In the constructor of the RequestManager, the RequestManager is put into the Fragment’s LifeCycle, which is passed in before LifeCycle is called back to the corresponding method of Glide

Android serial port

See Android Serial communication: Sorry, learn it can really do anything with serial programming that allows Android apps to communicate with peripherals, developed through a library provided by Google. Through that library, open the serial port. To obtain the input and output streams, you can use the serial port to receive and send data

Path: indicates the physical address of the serial port, which hardware engineers will tell you, such as ttyS0, ttyS1, etc., or use the SerialPortFinder class to find the available serial port address. Baudrate: indicates the baudrate, consistent with that of external devices. Flags: set this parameter to0, the reasons are more complex, see the bottom of the articleCopy the code

Breakpoint upload and download implementation

Breakpoint downloading

  • Use database real-time storage during local downloads to see where the file is stored
  • SetRequestProperty (“Range”,”bytes= startindex-endIndex “) in the HTTP GET request can only be passed the next time the pass continues; Method that tells the server, where does the data start and where does it end
  • While writing to a local file, RandomAccessFile’s seek() method also supports writing anywhere in the file
  • Finally, the progress of the child thread is told to the Activity’s progress bar via a broadcast or event bus mechanism. The HTTP status code for disconnected continuations is 206

Breakpoint uploader

  • The file is divided into blocks. Before each upload, the server learns which blocks are not uploaded and uploads these blocks
  • After uploading all blocks, notify the server to merge all blocks

Hot repair

  • What is DEX subcontracting
    • When you unpack an APK, you’ll have a classes.dex file that contains all the class files in our project
    • DVM uses short to store method ids, so the number of methods in dex cannot exceed 65535
  • Principle of subcontracting
    • The compiled class file is split and packaged into multiple dex
    • With the exception of the first dex file (the only dex file that exists in normal APK), all other dex files are placed in APK as resources and loaded by the system ClassLoader in the onCreate callback of the Application.
    • Note: Classes that have been referenced before injection must be placed in the first dex file or they will be prompted that the file cannot be found
  • ClassLoader dynamic loading
    • Each dex file is an Element, and multiple dex files arranged in an ordered array are dexElements
    • Add the dex file we fixed the Bug to the front of the dexElements array by reflection

Message mechanism

Handler mechanism for whole family buckets

  • MessageQueue data structure –> linked list (linked list insert and delete is O(1), array is O(n))
  • Position of Message insertion –> Traverse MessageQueue, compare when of the inserted Message and Message in MessageQueue, and ensure that when of MessageQueue is arranged from small to large after insertion
  • When does the message fetch –> A loop fetches the message from the MessageQueue, blocks based on when of the first message, and wakes up the next method to fetch the message
  • How does Handle send Runnable wrapped as Message, which has a member variable of type Runnable
  • Looper.prepare(), looper.loop (), start MessageQueue in child thread
  • Looper.loop() –> The Activity starts with a call to prepare() and loop() to start MessageQueue that has passed the main thread
  • Each thread has a ThreadLocal member variable, which is used to store Loop instances when looper.prepare () is used. So different threads have different loopers, different MessageQueue(MessageQueue is a member variable of Loop)
  • Handle the use of
    • ActivityThread main method, which prepareMainLopper () (which the child thread calls. Prepare ()), Looper.loop() stores the Looper instance in the current thread and starts rotating its own MessageQueue
    • Handler handle = new Handler(), remove the Looper from the main thread, remove the MessageQueue from the Looper (sendMessage requires MessageQueue)

OkHttp

  • Interceptor class
    • RetryAndFollowUpInterceptor: failed to retry and redirect the interceptor
    • BridgeInterceptor: a BridgeInterceptor, an interceptor that handles some of the required request headers
    • CacheInterceptor: a CacheInterceptor used to handle caches
    • ConnectInterceptor: a connection interceptor that establishes available connections. It is the basic of the CallServerInterceptor
    • CallServerInterceptor: The request server interceptor writes the HTTP request to the IO stream and reads the Response from the IO stream
  • What are OkHttp optimizations for web requests, and how are they implemented
    • In OKHTTP, every request we make is understood as a connection, and every time we send a request we go through a TCP three-way handshake, then transfer data, and finally release the connection. In the case of high concurrency or multiple client requests, multiple creations can lead to poor performance. If you canThe connection of reuseIf so, we can solve this problem very well. The key to being able to reuse is the ability of clients and servers to maintain long connections and reuse one or more connections. How do I keep a long connection? Requestbuilder.header (“Connection”, “keep-alive “), We added key-value pairs (“Connection”, “keep-alive “) to the request header to Keep the Connection long. The connection pool ConnectionPoll is the class that manages these long connections. Note that when we initialize the ConnectionPoll, we set the maximum number of idle connections to five, with a maximum lifetime of five minutes each
    • Seamless support for GZIP to reduce data traffic, add “accept-encoding “,” GZIP “to request header

Leakcanary

  • Garbage collection mechanism is divided into “reference counting” and “reachability analysis”
    • Python, object-c, Swift uses a counter to count the number of times an Object is referenced. If the number of references is reduced to zero, the Object is junk. (Reference counts have problems with circular references)

    • “Accessibility analysis” Java. The Jvm searches down through some GC Roots, and if an object can be referenced by GC Roots, that object is not garbage, whereas that object is garbage even if it references each other

  • This is done by registering lifecycle callbacks on applications and Fragments to start observing activities and fragments when they are destroyed
  • The monitoring principle

  • After a memory leak is detected, analyze the dump file to find the memory leak

BlockCanary

  • How it works: UI drawing for the main thread is ultimately done in the handleMessage() callback of the Handle of the ActivityThread. Count the execution time of the dispatchMessage method to determine whether the application is sluggish
  • Disadvantages: inaccurate positioning. Will concatenate strings

Design patterns


1. Decoration design mode

  • When it is not appropriate to extend an existing class by subclassing it, the decorator design pattern can extend the functionality of an object and make it more powerful
  • It is not suitable to extend an existing class by subclassing it. Reason: It makes the class more bloated. Subclasses inherit all non-private variables and methods from their parent class and then extend them. For classes that are extended using the decorator design pattern, you only need to increase the functionality of the extended part
  • Usage scenario :RecyclerView itself is not supported to add the bottom and head, so the use of decorative design mode can be used to expand its function. Add head and bottom in Decorative design mode RecyclerView

2. Differences between MVC, MCP and MVVP

Android traditionally uses MVC mode, Modle(logic) and V(View) to interact directly. The coupling degree is too high.MVC allows Model and View to interact

2.MVP The interaction between the Model and View is done by Presenter. The other thing is that presenters interact with views through interfaces. When a View needs to update its data, it goes to the Presenter first. The Presenter then goes to the Model and asks for the data. When the Model gets the data, it notifies the Presenter and the Presenter notifies the View to update the data. Instead of interacting directly with the Model and View, all interaction is done by the Presenter, who acts as a bridge. Obviously, Presenter must hold a reference to both View and Model objects in order to communicate between themExisting problems:

  • Memory leak: Because presenters often need to perform time-consuming operations, shutting down the Activity before the operation is complete will cause the Presenter to hold the Activity object, causing memory leak
  • As the business logic increases and the UI changes a lot, this will result in a very large View interface. MVVM solves this problem

Solution: use weak references in the Presenter, add the reference of the view to a weak reference Each Activity has BaseActivity BaseActivity

3.MVVM is automatically completed by data-driven. After data changes, IT will automatically update the UI, and the CHANGES of THE UI can also be automatically fed back to the data layer

  • ActivityResponsible for UI operations,ViewModelResponsible for data logic. Both byLiveDataAssociation.ViewModelreturnLiveDataInstance andActivityBinding,ViewModelYou can automatically update the UI when it changes,ActivityAlso throughViewModelInitiating a data request
  • Question:

MVVM seems to solve the MVC and MVP problems well, but due to the two-way binding of data and view, it is not easy to locate the source of problems, either caused by data problems or the modification of view attributes in the business logic

Take logging in as an example. When logging in, you only need to request the server with the user name and password

  • MVC, you need to find the input box, and then get the user name and password from the input box, and then log in
  • MVPthroughPresenterGet your username and password and log in. So it’s sort of by introducingPresenterwillMLayer and theVLayer separation reduces coupling
  • MVVMIn, after the user enters the user name and password in the input box, this UI change is directly synchronized to the data, directly login

3. Strategy design pattern

Application scenario: In some services, there are multiple implementation classes for a certain behavior, and the current service only chooses one implementation class. Refer to the cartoon to explain the strategy design pattern, which can be understood at a glance

4.Double Check Lock implements singletons

public static TestInstance getInstance(a){ / / 1
    if (mInstance == null) {/ / 2
        synchronized (TestInstance.class){ / / 3
            if (mInstance == null) {/ / 4
                mInstance = new TestInstance(); / / 5}}}return mInstance;
}
Copy the code

The first level of determination is mainly to avoid unnecessary synchronization and the second level of determination is to create instances in the case of NULL. mInstance = new TestInstance(); This step is actually performed in the JVM in three steps: 1. Create memory space in the heap; 2. Initialize the object. 3. Point the object to the heap memory space. Since prior to JDK 1.5 the Java compiler allowed processors to execute out of order. Volatile: Private volatile static DaoManager3 sinstance; DCL failure can be solved

5. Responsibility chain in OkHttp

public interface Interceptor {
    // Each layer of interceptor interface needs to implement Chain: a Chain of interceptors
    Response intercept(Chain chain) throws IOException;

    // The chain has two main methods: get the Request; Get Response from Request
    interface Chain {
        Request request(a);

        Response proceed(Request request):Response throws IOException;// Take charge of executing down}}Copy the code

chain

public class RealInterceptorChain implements Interceptor.Chain {
    final List<Interceptor> interceptors;// List of nodes
    final int index;// The index of the current node. You can get all nodes by interceptors and index
    final Request request;/ / request

    public RealInterceptorChain(List<Interceptor> interceptors, int index, Request request){
        this.interceptors = interceptors;
        this.index = index;
        this.request = request;
    }
    @Override
    public Request request(a) {
        return request;
    }

    @Override
    public Response proceed(Request request) throws IOException {
        RealInterceptorChain next = new RealInterceptorChain(interceptors,  index + 1, request);

        // Next passes the request to the current node. After the current node has processed the request, next executes the proceed method to proceed to the next node
        Interceptor interceptor = interceptors.get(index);
        Response response = interceptor.intercept(next);
        returnresponse; }}Copy the code

The interceptor

public class BridgeInterceptor implements Interceptor{

    @Override
    public Response intercept(Chain chain) throws IOException {
        Log.e("TAG"."BridgeInterceptor");
        Request request = chain.request();
        // Add some headers
        request.header("Connection"."keep-alive");
        // Do something else
        if(request.requestBody()! =null){
            RequestBody requestBody = request.requestBody();
            request.header("Content-Type",requestBody.getContentType());
            request.header("Content-Length",Long.toString(requestBody.getContentLength()));
        }
        Response response = chain.proceed(request);// Chain is next, index of next is incremented by 1

        returnresponse; }}Copy the code

Excute () method in RealCall

protected void execute(a) {
            final Request request = orignalRequest;
            try {
                List<Interceptor> interceptors = new ArrayList<>();
                interceptors.add(new BridgeInterceptor());
                interceptors.add(new CacheInterceptor());
                interceptors.add(new CallServerInterceptor());

                Interceptor.Chain chain = new RealInterceptorChain(interceptors,0,orignalRequest);
                Response response = chain.proceed(request);

                callback.onResponse(RealCall.this,response);
            } catch (IOException e) {
                callback.onFailure(RealCall.this,e); }}Copy the code

algorithm


1. Reverse single-linked lists

class Node{
    private int data;
    private Node next;
    public Node(int data,Node next){
        this.data=data;
        this.next=next; }}Copy the code
Node node4 = new Node(4.null);
Node node3 = new Node(3, node4);
Node node2 = new Node(2, node3);
Node node1 = new Node(1, node2);
Node pHead = node1;/ / head node
Copy the code

This set of lists is sorted from 1 to 4, requiring the reverse of the last 4 to 1

public static Node reverseList(Node pHead) {
        Node pReversedHead = null; // The inverted single linked list stores the headers
        Node pNode = pHead; // The current node
        Node pPrev = null; // the previous node
        while(pNode ! =null) {
            //1. Record next, next: Update the previous node and itself of the current node. Last move one bit
            Node pNext = pNode.next;
            if (pNext == null) {
                // Get to the last node
                pReversedHead = pNode;
            }
            pNode.next = pPrev;
            pPrev = pNode;
            pNode = pNext;
        }

        return pReversedHead;
}

 // Reverse the recursive mode (node1->node2->node3->node4->node5)
 public static ListNode reverseR(Node head){ 
    // An empty list and a node list need not be reversed
    if(head == null || head.next == null) {return head; 
    } 
    // When recursing to node4(head),reverseR(node4.next) returns directly to node5
    Node res = reverseR(head.next); 
    // Recursively, head points to node4, next for node4(node5) points to node4(head)
    head.next.next = head; 
    // point node4.next to null
    head.next = null; 
    return res; 
 }
Copy the code

The output

pHead = reverseList(pHead);// reverse the header
while(pHead ! =null) {
    System.out.println(pHead.key);
    pHead = pHead.next;
}
Copy the code

Android review information — common interview algorithm questions summary (a) Android review information — common interview algorithm questions summary (two) binary tree order traversal, order traversal, order traversal

2.LRU algorithm (least recently used algorithm)

  • The least recently used data can be removed when storage is insufficient
  • Use a LinkedHashMap to sort data by last used time. The most recently used data is inserted (moved) to the front of the list

other


1.Https

Understand HTTPS once and for all!

  • Use symmetric keys: Encryption and decryption use the same key. Cons: How do you send the symmetric key in the first place? If the symmetric key is intercepted at the time it is sent, the message can still be tampered with and accessed
  • Use asymmetric keys: Both parties must negotiate a pair of keys, one private and one public. Only the corresponding public key can decrypt the data encrypted with the private key, and only the corresponding private key can decrypt the data encrypted with the public key. User A sends its own public key to USER B. User B encrypts the message with the public key and sends the message to USER A. User A decrypts the message with its own private key. Disadvantages: Asymmetric key (RSA) encryption and decryption speed is slow
  • Asymmetric key + symmetric key: USER A sends its public key to USER B, and User B uses the public key to encrypt the symmetric key to user B. In this way, the symmetric encrypted key is securely transmitted between the two parties. This solves both key transmission and RSA slow speed problems. Disadvantages: The first time you pass a public key is risky
  • Digital certificates. If A sends his public key to B at the beginning, it is intercepted, and the interceptor replaces it with his own public key, there will still be A security problem. Solution: Digital certificates

2. Three handshakes

When establishing a TCP connection, the client and the server need to send three packets. The main purpose of the three-way handshake is to check whether the receiving and sending capabilities of the two parties are normal.

  • First handshake: The client sends a network packet and the server receives it. In this way, the server can conclude that the sending capability of the client and the receiving capability of the server are normal.
  • Second handshake: The server sends the packet and the client receives it. In this way, the client can conclude that the receiving and sending capabilities of the server and the client are normal. However, the server cannot confirm whether the client’s reception capability is normal.
  • Third handshake: The client sends the packet and the server receives it. In this way, the server can conclude that the receiving and sending capabilities of the client are normal, and the sending and receiving capabilities of the server are also normal.

Therefore, three handshakes are required to confirm the normal receiving and sending capabilities of both parties.

3. The 2.0

A short-term token allows a user to give third-party applications access to private resources stored on a site without the need for a user name or password

If the token expires, you need to jump to the login page to re-log in. Token and password can both enter the system, but there are three differences

  • The token is time-limited and expires automatically. The password is valid for a long time unless the user changes it.

  • The token can be revoked by the data owner and is immediately invalidated. In the above example, the owner can cancel the Courier’s token at any time. Passwords cannot be revoked by others.

  • The token has scope, for example, it can only enter the no.2 gate of the community. Read-only tokens are more secure than read-write tokens for network services. Passwords are generally full permissions.

4. ReactNative principle

In the React Native framework, JSX source code is compiled using the React Native framework and communicates with the Native framework through the Bridge of the corresponding platform. If we call the React Native API in our application, the React Native framework calls the methods in the Native framework through the Bridge. If it is the change of UI layer, diff algorithm will be performed after mapping to virtual DOM. Diff algorithm will calculate the changed JSON mapping file, and finally the Native layer will map and render this JSON file to the page elements of the Native App. Finally, the project only needs to control changes of state and props to cause UI changes on iOS and Android platforms. The React Native code is eventually packaged to generate a main.bundle.js file for the App to load. This file can be stored locally on the App device or stored on the server for the App to download and update. Hot updates in subsequent chapters will involve setting the location of main.bundle.js

5. Compare the advantages and disadvantages of Java and Kotlin

1. Kotlin syntax candy is more comfortable than Java after proficiency 2. Null pointer safety. For a variable that may be null, you need to add? 3. Support method extension. You can add methods to a class that it doesn’t have

6. Sharing interview questions with others