美文网首页
AsyncLayoutInflater 源码详解

AsyncLayoutInflater 源码详解

作者: 房房1524 | 来源:发表于2020-01-06 11:41 被阅读0次

    1、简介(此间代码基于Android API 28)

    官方解释
    Helper class for inflating layouts asynchronously. To use, construct
    an instance of {@link AsyncLayoutInflater} on the UI thread and call
    {@link #inflate(int, ViewGroup, OnInflateFinishedListener)}. The
    {@link OnInflateFinishedListener} will be invoked on the UI thread
    when the inflate request has completed.

    翻译一下
    一个异步加载布局的帮助类,使用的话在UI线程中构造(ps:构造的时候直接new的handler,要使用这个handler切换到主线程,所以需要在UI线程中new),调用inflate方法。当加载完成后会回调OnInflateFinishedListener中的方法(纯手工翻译,英语好的别喷)

    2、类的结构&源码详解

    2.1内部类

    2.1.1 InflateRequest

    private static class InflateRequest {
            AsyncLayoutInflater inflater;
            ViewGroup parent;
            int resid;
            View view;
            OnInflateFinishedListener callback;
        }
    
    • OO思想 封装了一个request对象;
    • 将 inflate(int resid, ViewGroup parent,OnInflateFinishedListener callback)中参数 封装
    • 然后 enqueue【入队列[阻塞队列——具体看下面inflate方法分析]】

    2.1.2 InflateThread

    private static class InflateThread extends Thread {
            private static final InflateThread sInstance;
            // 直接构造,直接start 这个thread
            static {
                sInstance = new InflateThread();
                // 类加载的时候就直接跑起来
                sInstance.start();
            }
    
            public static InflateThread getInstance() {
                return sInstance;
            }
            // 阻塞队列(保存封装过得request)
            private ArrayBlockingQueue<InflateRequest> mQueue = new ArrayBlockingQueue<>(10);
            private SynchronizedPool<InflateRequest> mRequestPool = new SynchronizedPool<>(10);
    
        
            public void runInner() {
                InflateRequest request;
                try {
                    request = mQueue.take();
                } catch (InterruptedException ex) {
                    return;
                }
                request.view = request.inflater.mInflater.inflate(
                           request.resid, request.parent, false);
                }
                Message.obtain(request.inflater.mHandler, 0, request)
                        .sendToTarget();
            }
    
            @Override
            public void run() {
                // 异步加载布局并使用handler进行,具体原因 看下文方法分析
                while (true) {
                    runInner();
                }
            }
    
            public void enqueue(InflateRequest request) {
                try {
                    mQueue.put(request);
                } catch (InterruptedException e) {
                    throw new RuntimeException(
                            "Failed to enqueue async inflate request", e);
                }
            }
    
            public void runInner() {
                InflateRequest request;
                try {
                    // take()如果队列为空 会阻塞
                    request = mQueue.take();
                } catch (InterruptedException ex) {
                    return;
                }
    
                try {
                    request.view = request.inflater.mInflater.inflate(
                            request.resid, request.parent, false);
                } catch (RuntimeException ex) {
                    // Probably a Looper failure, retry on the UI thread
                    Log.w(TAG, "Failed to inflate resource in the background! Retrying on the UI"
                            + " thread", ex);
                }
                Message.obtain(request.inflater.mHandler, 0, request)
                        .sendToTarget();
            }
        }
    
    
    
    • 就是一个Thread,并且在类加载的时候就调用了start方法。
    • 阻塞队列(保存封装过得request),调用AsyncLayoutInflate.inflate()方法时候入队列(InflateThread #enqueue方法)
    runInner方法详解
       //异步加载
      request.view = request.inflater.mInflater.inflate(
                            request.resid, request.parent, false);
      //这个handler是AsyncLayoutInflate构造时候new出来的,注释中要求在UI(主线程)中构造,所以这个handler为主线程handler,实现线程切换        
      Message.obtain(request.inflater.mHandler, 0, request)
                        .sendToTarget();
      // handler处理方式
      private Callback mHandlerCallback = new Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                InflateRequest request = (InflateRequest) msg.obj;
                if (request.view == null) {
                    request.view = mInflater.inflate(
                            request.resid, request.parent, false);
                }
                //回调
                request.callback.onInflateFinished(
                        request.view, request.resid, request.parent);
                //释放资源
                mInflateThread.releaseRequest(request);
                return true;
            }
        };
    

    2.1.3 BasicInflater

    private static class BasicInflater extends LayoutInflater {
            private static final String[] sClassPrefixList = {
                "android.widget.",
                "android.webkit.",
                "android.app."
            };
    
            BasicInflater(Context context) {
                super(context);
            }
    
            @Override
            public LayoutInflater cloneInContext(Context newContext) {
                return new BasicInflater(newContext);
            }
    
            @Override
            protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
                for (String prefix : sClassPrefixList) {
                    try {
                        View view = createView(name, prefix, attrs);
                        if (view != null) {
                            return view;
                        }
                    } catch (ClassNotFoundException e) {
                        // In this case we want to let the base class take a crack
                        // at it.
                    }
                }
    
                return super.onCreateView(name, attrs);
            }
        }
    
    • 优先加载 sClassPrefixList中包名下的UI

    3、源码解析

    3.1重要方法

    上面都分析过了

    3.2设计思路(本人拙见)

    看的比较简单就先不写了

    4.总结

    除了这个方法优化布局加载,其实Google也推出了类似SwiftUI的一种声明式UI-Compose、还有Facebook的 Litho,另外还可以利用APT的方式将xml在编译的时候直接转换为java代码(X2C框架),省去运行时候xml的读取和反射构造VIew,后续也会有关于Compose和其他布局加载优化的文章

    相关文章

      网友评论

          本文标题:AsyncLayoutInflater 源码详解

          本文链接:https://www.haomeiwen.com/subject/zgvnoctx.html