【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的使用

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个错误信息表示您正在尝试使用未激活的应用程序进行Android Facebook登录。为了解决这个问题,您可以按照以下步骤操作: 1. 检查应用程序状态:确保您的应用程序已经在Facebook开发者平台上激活。您需要在开发者帐户上登录,并确保设置了正确的应用程序ID和密钥。 2. 检查应用程序权限:检查您的应用程序是否已被授予所需的权限,在Facebook开发者平台上进行设置。确保您已正确设置了登录权限,以便用户可以使用它们的Facebook凭据进行登录。 3. 检查应用程序密钥散列值:应用程序的密钥散列值是Android应用程序与Facebook应用程序之间的安全连接。确保您已正确生成和配置应用程序密钥散列值。您可以从Facebook开发者平台上的应用程序设置中获取这个值。 4. 检查应用程序包名签名:检查您的应用程序包名和签名是否与在Facebook开发者平台上注册的应用程序设置相匹配。如果它们不匹配,您将无法使用该应用程序进行登录。 5. 清除缓存和数据:如果您之前尝试过登录,但遇到问题,可以尝试清除应用程序的缓存和数据。您可以在Android设置中的应用程序管理器中找到该应用程序,并选择清除缓存和数据选项。 通过检查和调整上述步骤,您应该能够解决Android Facebook登录时出现的"app not active"错误。如果问题仍然存在,您可以尝试重新安装应用程序或联系Facebook开发者支持寻求进一步的帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值