【Andorid】提升性能:使用AsyncLayoutInflater异步加载布局

如果我们关注Log,有时候会看到这样的warn提示:

Activity: Slow Operation: Activity ***.***.**.***Activity onStart took 1239ms

一般项目中存在一个MainActivity,属于一个App的主页面,用户在这里停留时间最长,同时也承载了最多的功能。如果MainActivity里面包含着多个Fragment,每个Fragment的布局比较复杂,就回导致在启动MainActivity时,加载Fragment的布局耗时太多,系统给出上面的提示。

Google在SDK中给出了一个解决方案:AsyncLayoutInflater。

类如其名,AsyncLayoutInflater的作用是在主线程外加载布局,然后把加载结果返回给主线程,减少主线程的卡顿。

源码

实现相对简单,仅有不到200行代码。把线程池、LayoutInflater、Handler相关知识点集中在一起,熟悉以上知识的小伙伴,可以很轻松读懂。

public final class AsyncLayoutInflater {
    
    
    private static final String TAG = "AsyncLayoutInflater";

    LayoutInflater mInflater;
    Handler mHandler;
    InflateThread mInflateThread;

    public AsyncLayoutInflater(@NonNull Context context) {
    
    
        mInflater = new BasicInflater(context);
        mHandler = new Handler(mHandlerCallback);
        mInflateThread = InflateThread.getInstance();
    }

    @UiThread
    public void inflate(@LayoutRes int resid, @Nullable ViewGroup parent,
            @NonNull OnInflateFinishedListener callback) {
    
    
        InflateRequest request = mInflateThread.obtainRequest();
        request.inflater = this;
        request.resid = resid;
        request.parent = parent;
        request.callback = callback;
        mInflateThread.enqueue(request);
    }
}

异步的实现使用了Thread和Handler。

InflateThread继承自Thread,负责在run方法中加载布局。

private static class InflateThread extends Thread {
    
    
    private static final InflateThread sInstance;
    static {
    
    
        sInstance = new InflateThread();
        sInstance.start();
    }

    public static InflateThread getInstance() {
    
    
        return sInstance;
    }

    private ArrayBlockingQueue<InflateRequest> mQueue = new ArrayBlockingQueue<>(10);
    private SynchronizedPool<InflateRequest> mRequestPool = new SynchronizedPool<>(10);

    public void runInner() {
    
    
        InflateRequest request;
        
        request = mQueue.take();

        request.view = request.inflater.mInflater.inflate(
                request.resid, request.parent, false);

        Message.obtain(request.inflater.mHandler, 0, request)
                .sendToTarget();
    }

    @Override
    public void run() {
    
    
        while (true) {
    
    
            runInner();
        }
    }

    public InflateRequest obtainRequest() {
    
    
        InflateRequest obj = mRequestPool.acquire();
        if (obj == null) {
    
    
            obj = new InflateRequest();
        }
        return obj;
    }

    public void releaseRequest(InflateRequest obj) {
    
    
        obj.callback = null;
        obj.inflater = null;
        obj.parent = null;
        obj.resid = 0;
        obj.view = null;
        mRequestPool.release(obj);
    }

    public void enqueue(InflateRequest request) {
    
    
        mQueue.put(request);}
}

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;
    }
};

InflateRequest封装了异步加载的各种属性,如:layout资源、回调接口、加载完成的view等。

private static class InflateRequest {
    
    
    AsyncLayoutInflater inflater;
    ViewGroup parent;
    int resid;
    View view;
    OnInflateFinishedListener callback;

    InflateRequest() {
    
    
    }
}
public interface OnInflateFinishedListener {
    
    
    void onInflateFinished(@NonNull View view, @LayoutRes int resid,
            @Nullable ViewGroup parent);
}

BasicInflater继承自LayoutInflater,负责加载布局:

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){
    
    
        for (String prefix : sClassPrefixList) {
    
    
            View view = createView(name, prefix, attrs);
            if (view != null) {
    
    
                return view;
            }
        }

        return super.onCreateView(name, attrs);
    }
}

优化

AsyncLayoutInflater在性能方面做了一些优化:

对象池缓存对象:

#InflateThread
private SynchronizedPool<InflateRequest> mRequestPool = new SynchronizedPool<>(10);

对象池:Pool的使用

猜你喜欢

转载自blog.csdn.net/qq_23049111/article/details/127010288