android的MessageQueue.IdleHandler

There is an IdleHandler interface inside MessageQueue, which is specifically defined as follows:

   /**
     * Callback interface for discovering when a thread is going to block
     * waiting for more messages.
     */
    public static interface IdleHandler {        
       /**
         * Called when the message queue has run out of messages and will now
         * wait for more.  Return true to keep your idle handler active, false
         * to have it removed.  This may be called if there are still messages
         * pending in the queue, but they are all scheduled to be dispatched
         * after the current time.
         */
        boolean queueIdle();
    }

In short, the message in the looper is temporarily processed. At this time, the interface will be called back, and if false is returned, it will be removed. If it is returned true, the callback will continue when the message is processed next time.

Let's first use an example to visually see the execution timing of IdleHandler.

public class IdleHandleActivity extends Activity {

    public static final String TAG = "IdleHandleActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        setContentView(R.layout.activity_idle_handler);

        Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
                Log.d(TAG, "IdleHandler post");
                return false;
            }
        });

        new Handler().post(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "Handler post1");
            }
        });
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "Handler post2");
            }
        });
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "Handler delay post");
            }
        }, 500);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume");
    }
}
public class MyView extends TextView {

    ......

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        Log.d(IdleHandleActivity.TAG, getText() + " onFinishInflate");
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        Log.d(IdleHandleActivity.TAG, getText() + " onMeasure");
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        Log.d(IdleHandleActivity.TAG, getText() + " onLayout");
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.d(IdleHandleActivity.TAG, getText() + " onDraw");
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.outman.example.androidtest.MainActivity">

    <com.outman.example.androidtest.MyView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="MyView!"/>

</LinearLayout>

Results of the:

04-08 17:30:33.994 16452-16452/ D/IdleHandleActivity: onCreate
04-08 17:30:34.038 16452-16452/ D/IdleHandleActivity: MyView! onFinishInflate
04-08 17:30:34.068 16452-16452/ D/IdleHandleActivity: onStart
04-08 17:30:34.073 16452-16452/ D/IdleHandleActivity: onResume
04-08 17:30:34.089 16452-16452/ D/IdleHandleActivity: Handler post1
04-08 17:30:34.089 16452-16452/ D/IdleHandleActivity: Handler post2
04-08 17:30:34.097 16452-16452/ D/IdleHandleActivity: MyView! onMeasure
04-08 17:30:34.106 16452-16452/ D/IdleHandleActivity: MyView! onMeasure
04-08 17:30:34.107 16452-16452/ D/IdleHandleActivity: MyView! onLayout
04-08 17:30:34.125 16452-16452/ D/IdleHandleActivity: MyView! onDraw
04-08 17:30:34.136 16452-16452/ D/IdleHandleActivity: IdleHandler post
04-08 17:30:34.569 16452-16452/ D/IdleHandleActivity: Handler delay post

You can see from the execution result

1. The callback of IdleHandler is in, all Handlers execute the content in the MessageQueue, and then execute

2.  The callback of the IdleHandler is in, the Activity executes the onResume method, and then executes

3. The callback of the IdleHandler is executed after the View is initialized, that is, after the onDraw is executed.

IdleHandler is used in both Glide and LeakCanary

Glide

// Responsible for cleaning up the active resource map by remove weak references that have been cleared.
    private static class RefQueueIdleHandler implements MessageQueue.IdleHandler {
        private final Map<Key, WeakReference<EngineResource<?>>> activeResources;
        private final ReferenceQueue<EngineResource<?>> queue;

        public RefQueueIdleHandler(Map<Key, WeakReference<EngineResource<?>>> activeResources,
                ReferenceQueue<EngineResource<?>> queue) {
            this.activeResources = activeResources;
            this.queue = queue;
        }

        @Override
        public boolean queueIdle() {
            ResourceWeakReference ref = (ResourceWeakReference) queue.poll();
            if (ref != null) {
                activeResources.remove(ref.key);
            }

            return true;
        }
    }

LeakCanary中

private void showToast(final FutureResult<Toast> waitingForToast) {
    mainHandler.post(new Runnable() {
      @Override public void run() {
        final Toast toast = new Toast(context);
        toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
        toast.setDuration(Toast.LENGTH_LONG);
        LayoutInflater inflater = LayoutInflater.from(context);
        toast.setView(inflater.inflate(R.layout.leak_canary_heap_dump_toast, null));
        toast.show();
        // Waiting for Idle to make sure Toast gets rendered.
        Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
          @Override public boolean queueIdle() {
            waitingForToast.set(toast);
            return false;
          }
        });
      }
    });
  }

 

Refer to https://mp.weixin.qq.com/s/KpeBqIEYeOzt_frANoGuSg

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324417703&siteId=291194637