Android based article

Application

Briefly describes the Application

Purpose: Performs initialization and provides context. It inherits from ContextWarpper and gets the context object in ContextWrapper

  • One and only one in an application
  • The life cycle is as long as the application
  • Application’s onCreate method is the entry point to the entire Application
  • It’s only instantiated once, so it’s inherently a singleton

Life cycle:

  • OnCreate: executed at creation time
  • OnTerminate: Executes when terminating
  • OnLowMemory: Execute when the memory is low

Application initialization process

With AMS coordination, activitythreads are first created and an ApplicationThread is created with the Binder to communicate with AMS. AMS then informs the ActivityThread to bindApplication. The message is sent back to messageQueue to initialize the Application, and attachBaseContext is called to bind the Context to the Application. The application.onCreate () method is finally called to initialize the subsequent Activity

AMS notifies zygote to fork a new process to open our target App

ActivityLifecycleCallbacks understand

ActivityLifecycleCallback is the Application of an interface that can be monitored all the Activity in the Application of life cycle, can be done by the method of some special requirements, such as monitoring the current App shows that the Activity is that? Whether the App has a foreground

public class MyApplication extends Application {
     private ActivityLifecycleCallbacks activityLifecycleCallbacks = new ActivityLifecycleCallbacks() {
        @Override
        public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {}@Override
        public void onActivityStarted(@NonNull Activity activity) {}@Override
        public void onActivityResumed(@NonNull Activity activity) {}@Override
        public void onActivityPaused(@NonNull Activity activity) {}@Override
        public void onActivityStopped(@NonNull Activity activity) {}@Override
        public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}@Override
        public void onActivityDestroyed(@NonNull Activity activity) {}};@Override 
    public void onCreate(a) {
        super.onCreate(); 
        
        / / register the CallbackregisterActivityLifecycleCallbacks(callbacks); }}Copy the code

Activity

Brief life cycle

The Activity:
  • OnCreate () is being created
  • OnRestart () is not visible
  • OnStart () Activity is being started and is already visible
  • OnResume () Acitivty is already visible and displayed in the foreground
  • OnPause () Acitivty is stopping and will not be visible afterwards
  • OnStop () Activity is about to stop
  • OnDestory () Activity is destroyed

OnStart and onResume are both visible, onStart is not displayed in the foreground, onResume is displayed in the foreground

OnResume or another onResume is displayed after onPause. Therefore, time-consuming operations cannot be performed, which affects the screen display

OnPause and onStop cannot be time-consuming

If the new Activity has a transparent theme, the current Activity does not call onStop

Whether the corresponding activities of onStart and onStop are visible

Whether activities corresponding to onResume and onPause are displayed in the foreground

In abnormal cases, the onSaveInstance method is executed to save data

Brief startup Mode

  • Standard: Standard mode, let’s add one by one
  • SingleTop: reuse at the top of the stack, reuse the Activity if it is at the top of the stack,onNewIntentWill be executed instead of onCreate()
  • SingleTask: in-stack reuse. If the Activity is in the stack, reuse the Activity, and all of the Activity above the stack, onNewIntent, will be executed
  • SingleInstance: single-instance mode. The enhanced singleTask will create a new stack for itself and reuse within that stack

LauncherMode and startActivityForResult


Prior to 5.0, when starting an Activity, the system first checks the Activity’s launchMode, If you set SingleInstance for page A or singleTask or SingleInstance for page B, FLAG_ACTIVITY_NEW_TASK will be added to LaunchFlags. With FLAG_ACTIVITY_NEW_TASK, onActivityResult will immediately receive a cancle message. This method was modified after 5.0. OnActivityResult will work even if the launchMode of the page is set to singleTask or singleInstance. The StartActivityForResult and onActivityResult() combinations are both valid

When does a new Activity stack start?

  • AllowTaskReparenting:
  1. SingleInstance, used alone, creates a new stack
  2. SingleTask is used in conjunction with taskAffinity
  3. TaskAffinity is performed with an Intent.FLAG_ACTIVITY_NEW_TASK.
  4. TaskAffinity works with the allowTaskReparenting attribute to move activities from the start stack to the used stack and display them

How do I control the animation switch of my Activity

  1. Through the overridePendingTransition (state Richard armitage nim slide_in_right, state Richard armitage nim. Slide_out_left) control method after startActivity method or finish after the call to take effect
  2. Use style to define the toggle animation

How to control the animation switch of fragments

FragmentTransaction fragmentTransaction = mFragmentManager
                .beginTransaction();

fragmentTransaction.setCustomAnimations(
                R.anim.in_from_right,
                R.anim.out_to_left);
Copy the code

Use FragmentTransaction to turn on Fragment animation, set custom animation toggle, animate and push animation

ActivityA jump to ActivityB and press back to return to ActivityA.

ActivityA jump to ActivityB: onPauseA () — — — — — > onCreateB () — — — — — > onStartB () — — — — — > onResumeB () — — — — — > onStopA ()

ActivityB press back to return to ActivityA:

onPauseB()—–>onRestartA()—–>onStartA()—–>onResumeA()—–>onStopB()—–>onDestoryB()

What if ActivityB is a window Activity?

ActivityA jump to ActivityB: onPauseA () — — — — — > onCreateB () — — — — — > onStartB () — — — — — > onResumeB ()

ActivityB press back to return ActivityA: onPauseB()—–>onResumeA()—–>onStopB()—–>onDestoryB()

Is the Activity lifecycle affected by Dialog?

No, the Activity lifecycle does not change with the display of the Dialog

An Activity’s life cycle is called by AMS, whereas a dialog is not an Activity, so it is not controlled by AMS, so it does not trigger the Activity’s life cycle

Service

How many ways can a Service be created? What’s the difference?

  1. StartService (), stopService() when not needed
  2. BindService (), bound to the life cycle, is recycled on destruction. Unbind ()

How to understand IntentService? What is the life cycle? What is a HandlerThread?

IntentService is a class that handles asynchronous operations. When asynchronous operations are complete, intentService is automatically closed. StartService () is executed several times, but onStartCommand is executed. Adds a message to a message queue.

The essence is to start a mainline-like Handler to maintain asynchronous operations.

Life cycle: Execute onStart() in onStartCommand() and add handler.sendMessage() to onStart()

HandlerThread: a set of logic that wraps Handler and Looper to allow direct use of handlers in child threads.

IntentService is more like a background thread, but it is a service that is not easily recycled, which is its advantage

JobIntentService

JobIntentService is a subclass of IntentService. On Android 8.0 (26) and above, all background execution tasks of IntentService are restricted, so use JobIntentService.

Service background services cannot be used, need to use ContextCompat startForegroundService start at the front desk service, this will start a notification, for the user experience is not very good, So start a background service using JobIntentService

StartService is not required when using JobIntentService. StopService is called when needed

DownLoadJobIntentService.enqueueWork(MainActivity.this,DownLoadJobIntentService.class,jobId(8),intent);
Copy the code

The logic in the onHandleWork method is then executed and destroyed automatically

What are the three callbacks in onStartCommand?

  • START_NOT_STICKY: the Service is not processed after being reclaimed
  • START_STICKY: Service Creates a new Service after it is reclaimed, butDo not saveintent
  • START_REDELIVER_INTENT: Servicesaveintent
  • START_STICKY_COMPATIBILITY: Compatible with START_STICKY, but it is not guaranteed that the service can be restarted after being killed.

Service keep alive

  1. Set to Foreground service, bind Notification, startForeground(1, getNotification());
  2. Individually set as a server process
  3. OnStartCommand returns START_STICKY, START_REDELIVER_INTENT to ensure that the service is restarted after it is destroyed
  4. OnDestory sends a broadcast, and the broadcast receiver picks up the broadcast and pulls up the service
  5. Added system broadcast pull up
  6. Improve service priorities

Fragment

The life cycle

What is the difference between FragmentPagerAdapter and FragmentStatePagerAdapter?

FragmentPagerAdapter: Switching pages only separates fragments. If there are few fragments, memory will not be affected

FragmentStatePagerAdapter: switch the page will Fragment recycling, more suitable fragments, it doesn’t consume too much memory resources

3 ways to switch fragments

  1. Add method: Just go back to the fragment
  2. Replace method: Rebuilds the fragment every time

Why can’t we use the Fragment constructor to pass parameters? What are the disadvantages? What should I do? Why is that?

When a Fragment is rebuilt after an exception crash, the Fragment constructor will be called by default. This will cause the values of the parameter constructs in the Fragment not to be executed and the data will be abnormal

Call setArguments in Fragment to pass the parameters, and when the Activity builds the Fragment, instantiate a new Fragment through the reflection lunch construct, and initialize the mArguments to the original value

In what life cycle is the Fragment rebuilt?

Store Framgent in the FragmentActivity’s onSaveInstanceState, store Framgent by serializing Parcelable, and restore it in the Activity’s onCreate

When the configuration changes, the Activity enters the destruction process. The FragmentManager destroys the Fragment view in the queue and then checks the retainInstance property of each Fragment. If retainInstance is false, the FragmentManager destroys the Fragment instance. If retainInstance is true, the Fragment instance is not destroyed, and after the Activity is rebuilt, the new FragmentManager finds the remaining Fragment and creates a view for it.

BroadCastReceiver

Describe the startup methods and differences of broadcast

  • Static registration: Register in AndroidManifest, resident broadcast
  • Dynamic registration: Uses intentFilter to filter broadcasts and registerReceiver to register broadcasts, following the lifecycle

Android8.0 and above parts of the broadcast does not allow static registration

The difference between disordered broadcast and ordered broadcast

  • Unordered broadcast: all broadcast receivers can obtain, can not intercept, can not be modified
  • Ordered broadcast: transmission down according to priority, can intercept broadcast, modify broadcast

Local broadcast and global broadcast

Local broadcast receiver only receives local broadcast, reducing the interference of out-of-application broadcast. Local broadcast is deprecated in androidx 1.1.0-alpha01. It is officially recommended to use LiveData or responsive stream

The IPC mechanism

Describe the IPC mechanism in Android

Interprocess communication

Architecture: Client/Server architecture, Binder mechanism, communication through proxy interface

Client, Server, serverManager

The Android: Process attribute is specified in the AndroidManifest

  • Package name: Remote Indicates an application private process and is inaccessible to other applications
  • Package name. Remote is the global process, others should be good through ShareUID and it can run in the same process

Problems caused by multiple processes: When the four components fail to share data, each process creates a separate memory space to store information

  1. Static members and singletons are completely invalidated
  2. The thread synchronization mechanism has completely failed
  3. SharedPreferences reliability deteriorates and does not support multiple processes
  4. Application will be created multiple times

Serializable and Parcelable differences

Serializable: Java built-in, reflection generates a large number of temporary variables, easy to cause GC, mainly used for persistent storage and serialization of network transport

Parcelable: Android specific, high performance, split the complete object into parts of the object, each part of the intent transmission, can be used for IPC, internal implementation of the Bundle, mainly used for memory serialization

Why did Android introduce Parcelable?

  1. Serializable through reflection, poor performance,
  2. Serializable reflection produces a large number of temporary variables that are prone to GC, causing memory jitter
  3. Serializable uses a large number of IO operations and also affects time consumption

Parcelable is complex to use but efficient for memory serialization

Is Parcelable necessarily faster than Serializable?

Parcelable can be faster than Serializable, but Parcelable has no concept of caching. Serializable has a cache, which places parsed content in HandleTable and can be directly used the next time it is parsed to the same type of object

Why does Java use Serializable serialization objects instead of JSON or XML?

Serializable was designed in Java before JSON and XML came out because of a legacy issue, and it is not easy to change this problem in Java’s large architecture. The Java documentation also recommends using the JSON library because it is simple, easy to read, and efficient

A brief analysis of Binder mechanisms

Not all process communication in Android uses Binder. When fork(), Socket() is used. Because fork does not allow multithreading, Binder is not allowed because it is multithreaded

Process space partition

A process space is divided into user space and kernel space

User space: Data is exclusive and cannot be accessed by other processes

Kernel space: Data is shared and accessed by other processes

All processes share 1 kernel space

What about the ServiceManager?

ServiceManager Manages all services in the system and registers them when needed. Similar to the DNS, ServiceManager provides clients with access to a service.

Principle of Binder

Binder drivers belong to the kernel space in the process, that is, the shared space. When the client initiates a request, data needs to be copied from the user space to the kernel space. Binder transmits the reference of the data stored in the kernel space to the server for the server to call. The reference is passed through binder and mapped to the client for processing

Brief Communication Process

The overall communication flow is:

  • The client sends requests to the server through a proxy object.
  • Proxy objects are sent to the server process through Binder drivers
  • The server process processes the request and returns the result to the proxy object through Binder drivers
  • The proxy object returns the result to the client.
Detailed communication process
  • All server-side classes inherit from Binder classes, which are the server’s corresponding Binder entities. This class is not a real remote Binder object, but a Binder reference (that is, a server class reference) that will be mapped again in the Binder driver.
  • When a client calls a remote object function, it simply writes data to the Parcel, calling the Transact () function it holds with its Binder reference
  • Binder drivers read data from the Client’s shared memory, including parameters and identifiers (which mark remote objects and their functions), to find the shared memory of the corresponding remote process.
  • It then copies the data to the remote process’s shared memory and tells the remote process to execute onTransact(), which is also a Binder class.
  • The Binder driver copies the shared memory data of the remote process to the shared memory of the client and wakes up the client thread.

Binder reads and writes data in the shared memory of the client and server into the shared memory of the other side and notifies them.

Binder for Android?
  • System services and the four components of the start call work: system services are obtained by getSystemService, internal is through the ServiceManager. The Binder mechanism is passed to ActivityManagerService, which then feeds back to Zygote. And we usually get the service through getSystemService(getApplication().window_service) code.
  • Android Interface Definition Language (AIDL). For example, if we define an iserver. aidl file, the AIDL tool will automatically generate a Java interface class for iserver. Java (including Stub, Proxy and other internal classes).
  • OnServiceConnected (Interface) returns an IBinder object. In addition, you can use iserver.stub. asInterface(service) to obtain the Proxy object of IServer, which implements the IServer interface.

Why Binder mechanism? What are his strengths?

  1. High performance and efficiency: Traditional IPC (socket, pipe, message queue) copies memory twice, Binder copies memory only once, shared memory does not need to copy data, only need to pass references
  2. Good security: ADD UID/PID to C/S communication for convenient verification and perfect security mechanism.
  3. C/S architecture is used to control a server with multiple clients through multi-threading

Android IPC in several ways of detailed analysis and analysis of the advantages and disadvantages

  1. Bundle
  2. File sharing
  3. Messenger: Internal implementation of AIDL mechanism, C/S architecture, through the handler to receive message objects
  4. AIDL
  5. ContentProvider
  6. Binder connection pool

Handler

The Android Handler mechanism is the main directory

Android interview question: Handler

Not every time you add a message, you wake up the thread. When the message is inserted into the queue header, the thread is woken up; If there is a delay message inserted into the header, it will also wake up the thread after sleep

Summarize Handler in one sentence and explain how it works

Android for communication between the main thread and child thread tool

Mainly contain Handler, stars, MessageQueue, ThreadLocal.

Handler: Encapsulates the sending and receiving of messages sent by Looper

Looper: Coordinates the bridge between Handler and MessageQueue. Looper circulates messages from MessageQueue and distributes them

To the corresponding Handler, which is stored in the target in Message

Message: a single node that stores data transmitted by the Handler

MessageQueue: internal structure is a single linked list created by Looper, the specific code is looper.prepare (); First in, first out (queue), insert queue according to message.when (queue is executed in chronological order)

ThreadLocal: The Looper responsible for storing and retrieving the local thread

Handler. sendMessage(message) sends the message to MessageQueue, which executes enqueueMessage() to join the queue. Which perform stars. The loop () method from the MessageQueue message, perform message. Target. DispatchMessage (message) method to send a message to the Handler, Get the callback in the handleMessage() method

Looper.loop() is an infinite loop on the main thread. Why is it not blocking the thread?

The true ANR is caused by waiting too long in the lifecycle callback, and more deeply, by looper.loop () not pulling out the message in time for distribution. Once there are no messages, Linux’s epoll mechanism wakes up and sleeps the main thread by pipe-writing file descriptors, and Android implementations that invoke the Linux layer sleep the main thread when appropriate.

MessageQueue contains JNI calls that notify EPoll to sleep when there is no message and start the thread when a message comes

Loop () in looper.loop().

 public static void loop(a) {...for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
Copy the code

In Queue.next, the main thread is piped to sleep by jNI calls, and Linux’s epoll mechanism writes file descriptors, and only when the application exits is an if statement executed to exit the loop.

Why can’t I update the UI on a child thread?

Because if you want to update the UI in a child thread, you have to consider thread-safety, locking mechanism, which is time-consuming, and without locking it is prone to errors that can be fatal, so only allow the UI thread to update the UI to avoid these errors.

Is it really impossible to update the UI on child threads?

Thread detection via checkThread() is performed in ViewRootImpl

public ViewRootImpl(Context context, Display display) {... mThread = Thread.currentThread(); . }...void checkThread(a) {
        if(mThread ! = Thread.currentThread()) {throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views."); }}Copy the code

It can be concluded that: ViewRootImpl is initialized in that thread, it updates the UI in that thread, and most of the time viewRootImpl is initialized in the UI thread, so you can only update the UI in the UI thread, In some cases the UI can be updated in child threads (e.g. Dialog initializes ViewRootImpl in addView)

The SurfaceView can be updated in child threads

When was ViewRootImpl created?

In Acitivty, ViewRootImpl is created in onResume, so child thread updates in onCreate can bypass checkThread() detection.

How many loopers can there be in a Thread? A few Handler

A Thread has only one Looper. There can be countless handlers, but MessageQueue is the same, that is, a Looper

Can I just new a Handler on a child thread? So what do you do?

thread= new Thread(){ @Override public void run() { super.run(); MessageQueue looper.prepare (); Handler =new Handler(); // Loop out the message and execute looper.loop (); } }.start();Copy the code

A Looper needs to be created, and the Looper creates a MessageQueue, from which the loop retrieves messages.

How can messages be created? Which works better and why?

The flyweight pattern

Data reuse

  1. Message msg = new Message();
  2. Message msg2 = Message.obtain();
  3. Message msg1 = handler1.obtainMessage();

2,3 returns a new Message instance from the entire Messge pool. ObtainMessage avoids duplicate message-created objects.

Therefore, it is recommended to use either the second or the third method to create Message objects.

Messge is a node, and its existence is a linked list, in which all reusable messages are stored in handleMessage and callback

The message.recycle() method is executed after information is reset and added to the head of the idle list. Each call to the obtain method removes the head node from the idle list. If the idle list is empty, a new message is created.

The Message cache pool size is 50

What happens to message queues when Hanlder’s postDelay() is used?

PostDelay () internal call sendMessageDelayed()

public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
Copy the code

Time: systemclock. uptimeMillis() + delayMillis

Systemclock. uptimeMills() is the time from startup to now. CurrentMills are not used because it is variable

  1. Handler.postDelayed(Runnable r, long delayMillis)
  2. Handler.sendMessageDelayed(getPostMessage(r), delayMillis)
  3. Handler.sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
  4. Handler.enqueueMessage(queue, msg, uptimeMillis)
  5. MessageQueue.enqueueMessage(msg, uptimeMillis)

When a message is queued, it will judge the time according to when and finally sort it according to the time size. The short time is at the head of the list and the long time is at the end of the list.

Examples are as follows:

  1. postDelay()A 10-second Runnable A, message into the queue, MessageQueue callnativePollOnce()Block, Looper block;
  2. thenpost()A Runnable B, the message queue, determines that A is blocking, inserts B into the head of the message queue (before A), and then callsnativeWake()Method to wake up the thread;
  3. MessageQueue.next()The method wakes up and starts reading the list again. The first message B is returned to Looper without delay.
  4. Looper is called again after processing the messagenext()MessageQueue continues to read the list of messages. The second message, A, does not run out of time and calculates the remaining time (if there are 9 seconds left) to continue the callnativePollOnce()Block;
  5. Until the block time expires or the next time a Message is queued;

What are synchronous, asynchronous, and synchronous barrier messages? What are the specific application scenarios?

Synchronous messages: The handler defaults to a no-argument construct of the form synchronous messages

Asynchronous message: Async is an asynchronous message if true is passed

Barrier message: msg.target == null, use postSyncBarrier() to open the synchronization barrier, so that the synchronization message is not executed, and the asynchronous message is preferentially executed. The synchronization barrier is closed when the synchronization message is completed.

Application scenario: In view update process, draw, requestLayout, invalidate all use this method, the system will process these asynchronous messages first, and wait for the completion of the synchronization message processing. This gives priority to the system messages we specify.

PostSyncBarrier () this method is private, so the API does not allow us to call it during development, so we just need to know how it works

Calling this method sends a barrier message directly to messageQueue, and the queue header is the barrier message

ThreadLocal, tell us what you understand

Similar to the HashMap functionality, why not just use HashMap? The reason:

  1. HashMap is too big and bloated. The key of a ThreadLocal can only be Thread and value looper, while the key of a HashMap can be string, int and other data types.
  2. Thread isolation: Our threads are unique to the system, and using ThreadLocal to manage these unique threads and their corresponding values is very convenient.
  3. ThreadLocal references HashMap, simplifying HashMap, and making it easier to use.
  4. The HashMap thread is not safe

The understanding of the ThreadLocal

Why can’t a child thread use a Handler when the UI thread can?

The UI thread is an ActivityThread. It creates a Looper and MessageQueue when it initializes, so it can use the Handler directly. The child thread does not create a Looper, so it can use it

The Handler constructor uses looper.mylooper () to get a Looper, but there is no Looper in the child thread

How does Handler cause memory leaks? How to solve it?

A non-static inner class or an anonymous inner class holds references to an external class by default. When an external class is reclaimed, the external class cannot be reclaimed because the inner class holds references to the external class, causing memory leaks.

  1. Clean up the message queue when the Activity is destroyed;
  2. Custom static Handler class + weak reference.

Messagequeue.next () blocks because it found a delayed message. So why aren’t subsequent non-delayed messages blocked?

First of all, the non-delayed message will queue up and insert the linked header. At this time, the thread will wake up and cycle out message. After the delayed message, if the event does not arrive, the blocking mechanism of next will be triggered

Is the Handler delay mechanism time-safe?

May also

 chatIflyHandler.post(new Runnable() {
            @Override
            public void run(a) {
                try {
                    Thread.sleep(3000);
                } catch(InterruptedException e) { e.printStackTrace(); }}}); chatIflyHandler.postDelayed(new Runnable() {
            @Override
            public void run(a) {
                Log.e("handler"."Execute delay operation for 1s"); }},1000);
Copy the code

First, a non-delayed message is entered into the queue, then a delayed message is entered into the queue, and the first non-delayed message is executed. After 3s, the delayed message is executed, and when is compared, and then directly executed. The test takes 3420ms in total

Handler enqueueing is thread-safe

messageQueue.equeue(){ synchronized(this){ ...... }}Copy the code

How to keep accurate time?

  • Using a timer (child thread processing TimerThread)

  • Error compensation algorithm (TextClock control method)

private final Runnable mTicker = new Runnable() {
        public void run(a) {
            onTimeChanged();

            long now = SystemClock.uptimeMillis();
            long next = now + (1000 - now % 1000); getHandler().postAtTime(mTicker, next); }};Copy the code

The whole second execution, when the last execution accumulated to 1200, in the next execution, through the calculation of next to ensure that the next execution time is not accumulated to 2200, but also in 2000

What is IdleHandler? For what?

MessageQueue has an addIdleHandler() method that adds the IdleHandler interface

  • If messageQueue is not empty when added, the method is called back when the thread sleeps (no messages, delayed messages)
  • If messageQueue is empty when it is added, the fallback will not be triggered at that time and will only be executed when the thread is woken up

When IdleHandler is enabled, if the thread is asleep, it will not take effect until the next sleep. If not, the next spin-down takes effect immediately.

After IdleHandler is enabled, the main thread will be notified of the next sleep

 Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle(a) {
               //do something
                return false; }});Copy the code

If return true, this IdleHandler can be used multiple times. If return false, this IdleHandler can only be used once

When does the main thread Looper exit? Can I log out manually?

Looper exits when app exits or terminates abnormally. During normal exit, the mH (Handler) in the ActivityThread main thread receives the callback message and calls the quit() method to force exit

//ActivityThread.java
case EXIT_APPLICATION:
    if(mInitialApplication ! =null) {
        mInitialApplication.onTerminate();
    }
    Looper.myLooper().quit();
    break;
Copy the code
  • Looper.quit(): terminates Looper after the call and no Message is processed. All attempts to put a Message into a Message queue will fail, such as handler.sendMessage (), which returns false but is unsafe. It is possible that a Message is still in the Message queue and terminates the Looper without being processed.

  • Looper.quitsafely (): This call terminates the Looper after all messages have been processed and all attempts to put a Message into a Message queue fail.

An error is reported when attempting to manually exit looper on the main thread:

Caused by: java.lang.IllegalStateException: Main thread not allowed to quit.
    at android.os.MessageQueue.quit(MessageQueue.java:428)
    at android.os.Looper.quit(Looper.java:354)
    at com.jackie.testdialog.Test2Activity.onCreate(Test2Activity.java:29)
    at android.app.Activity.performCreate(Activity.java:7802)
    at android.app.Activity.performCreate(Activity.java:7791)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) 
    at android.os.Handler.dispatchMessage(Handler.java:107) 
    at android.os.Looper.loop(Looper.java:214) 
    at android.app.ActivityThread.main(ActivityThread.java:7356) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
Copy the code

Since exiting the main thread means closing the app, this operation is not standardized and requires a formal exit operation

How to Exit app

  1. Log the Activity task stack and finish all
  2. System.exit(0); // Exit system.exit (1); // Exit abnormally
  3. android.os.Process.killProcess(android.os.Process.myPid()); Stop a process. If a process is not stopped, the system restarts it
  4. Directly to join in the Intent to identify the Intent FLAG_ACTIVITY_CLEAR_TOP, so that when you start the B, will clear all the Activity in the process of space.
  5. Use ActivityManager to close before version 2.2
ActivityManager am = (ActivityManager)getSystemService (Context.ACTIVITY_SERVICE);
am.restartPackage(getPackageName());
Copy the code

After version 2.2

ActivityManager am = (ActivityManager)getSystemService (Context.ACTIVITY_SERVICE);
am.killBackgroundProcesses(getPackageName());
System.exit(0);
Copy the code

This method is only a way to end the background process. It cannot end the current application and remove all activities. If you need to exit the application, you need to add the system.exit (0) method to use together, and limit the stack to only one Activity. If there are multiple activities, as mentioned in method 2 above, it will not work.

  1. Setting MainActivity to singleTask clears all activities when you return to MainActivity, so you can execute the Finish () method directly on the MainActivity

How to view sendMessageAtFrontOfQueue ()

public final boolean sendMessageAtFrontOfQueue(Message msg) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
            this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, 0);
}
Copy the code

The incoming delay time is 0, the header is inserted into the message queue, that is, the message queue executes immediately next time,

What do you think of CallBack methods in Handler constructs?
    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

public void dispatchMessage(Message msg) {
  // Callback is Runnable
  if(msg.callback ! =null) {
    handleCallback(msg);
  } else {
    // If callback processes the MSG and returns true, handleMessage is not called again
    if(mCallback ! =null) {
      if (mCallback.handleMessage(msg)) {
        return; } } handleMessage(msg); }}Copy the code

When the dispatch method is called, the Callback method will be called first. When the handleMessage method is called, the Callback method will be called

The Callback interface receives the message before handleMessage, and if true is returned, the handleMessage method is not called

We can use Callback to intercept Handler messages!

What is the difference between looper.prepareMain () and looper.perpare?

The difference is a Boolean value, the main thread looper never exits unless called

AsyncTask

How to understand AsyncTask?

  • Must be created on the main thread

AscncTask internally encapsulates a Handler+ thread pool

There are two thread pools, one for queuing and one for actual execution, with the Handler dropping the state back to the main thread

  • Number of core threads, minimum two, maximum four
  • Maximum number of threads = Number of CPU cores *2+1
  • Core threads have no timeout limit, and non-core threads have a timeout period of 1s when they are idle
  • The capacity of the task queue is 128

Execute method, join the queue thread pool queue, wait for the main thread to be notified by handler after the task is executed, call the state callback method, internal implementation because the queue thread pool is blocked, so the task is serial, that is, only one task will enter the thread pool for execution

ExecuteOnExecutor performs the call asynchronous operation

Why did Google drop AsyncTask

  1. Using multiple threads is more complex, making bugs harder to locate
  2. Too complicated
  3. Abuse inheritance, effic Java recommends “using composition rather than inheritance”, making classes too many and inefficient
  4. The default THREAD_POOL_EXECUTOR thread pool configuration is not appropriate

The thread pool

thread

Brief Description of thread pools

The main implementation of thread pools in Android is ThreadPoolExecutor

Parameters:

  • Number of core threads: If the allowCoreThreadTimeOut property of ThreadPoolExecutor is set to true, the core thread will be destroyed if it is inactive for more than a certain amount of time
  • Maximum number of threads: = Number of core threads + number of non-core threads
  • Timeout: Idle timeout of a non-core thread
  • Timeout unit: unit of idle timeout for non-core threads
  • Thread wait queue: When all core threads are working, new tasks are added to the queue to wait for processing. If the queue is full, a new non-core thread is created to execute the task
  • Thread creation factory: Denial policy for thread pools, error free and concern free

AllowCoreThreadTimeOut is set to true. The non-core thread timeout also applies to the core thread. If false, the core thread will never terminate

  1. SynchronousQueue: When a task is received on this queue, it is submitted directly to the thread instead of being retained. What if all threads are working? Create a new thread to handle the task! Therefore, maximumPoolSize is usually specified as integer. MAX_VALUE, or infinite, when using this type of queue to ensure that no new thread can be created when the number of threads reaches maximumPoolSize

  2. LinkedBlockingQueue (unlimited size) : When this queue receives a task, if the number of current threads is smaller than the number of core threads, a new thread (core thread) will process the task. If the number of current threads is equal to the number of core threads, the queue is queued. Since there is no maximum limit on this queue, any task that exceeds the number of core threads will be added to the queue, which invalidates maximumPoolSize because the total number of threads will never exceed corePoolSize

  3. ArrayBlockingQueue (size can be set) : If the queue is full, a new thread (non-core thread) will execute the task. If the queue is full, a new thread (non-core thread) will execute the task. If the total number of threads reaches maximumPoolSize, a new thread will execute the task. And the queue is full, an error occurs

  4. DelayQueue: The elements in the queue must implement the Delayed interface, which means that the task you sent in must implement the Delayed interface first. When the queue receives a task, it joins the queue first. The task will be executed only after the specified delay time is reached

Rules:

  1. If the number of core threads is not reached, create a new core thread
  2. Reaches or exceeds the number of core threads, and the task is inserted into the task queue for execution
  3. In Step 2, the queue cannot be inserted (the queue is full), the number of threads is less than the maximum thread pool, and a non-core thread is started to execute the task
  4. If the number of threads in Step 3 reaches the maximum value, this task is rejected

How many thread pools are there in Android?

Four kinds of

FixedThreadPool: Full of core threads, no timeout mechanism, and no size limit on the task queue

CachedThreadPool: all non-core threads, with a maximum value of integer. MAX_VALUE. Idle threads timeout 60 seconds (they can be reused within 60 seconds and reclaimed after 60 seconds)

ScheduledThreadPool: the core thread is fixed, and the non-core thread is interger. MAX_VALUE. The non-core thread has no timeout mechanism (it is reclaimed after execution)

SingleThreadExecutor: Only one core thread, no timeout mechanism, guaranteed to execute tasks in only one thread

Does a thread crash in a thread pool cause the pool to crash?

No, there are two ways to execute thread tasks in the thread pool: Submit and execute. When a thread crashes, execute will close the thread and open a new thread. Submit will return an exception but will not close the thread.

Submit:

  • Inherited from the ExecutorService
  • No stack heap exception is thrown, and the future.get method is used to get the exception information
  • Submit constructs a RunnableFuture and executes the execute method. RunnableFuture uses internal state management to judge the task execution status through an infinite loop and returns after execution or cancle.

The get() method is a blocking method that needs to be called with care

The execute:

  • Inherited from Executor
  • A stack exception message is thrown, the thread is closed and a new thread is created

How do you detect crashes in a thread pool?

The get() method of submit can get a crash, but it blocks and is not available, so we use another method

  1. The execute + ThreadFactory. UncaughtExceptionHandler UncaughtExceptionHandler failure under the submit, Because FutureTask catches the exception and saves it instead of putting it in UncaughtExceptionHandler
  2. Capture it yourself in the run method
  3. Rewrite ThreadLocalExecutor afterExecute method
  4. Submit + the get method