Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 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) {
- if (callback == null) {
- throw new NullPointerException("callback argument may not be null!");
- }
- InflateRequest request = mInflateThread.obtainRequest();
- request.inflater = this;
- request.resid = resid;
- request.parent = parent;
- request.callback = callback;
- mInflateThread.enqueue(request);
- }
- private Handler.Callback mHandlerCallback = new Handler.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;
- }
- };
- public interface OnInflateFinishedListener {
- void onInflateFinished(View view, int resid, ViewGroup parent);
- }
- private static class InflateRequest {
- AsyncLayoutInflater inflater;
- ViewGroup parent;
- int resid;
- View view;
- OnInflateFinishedListener callback;
- InflateRequest() {
- }
- }
- 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);
- }
- }
- 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 Pools.SynchronizedPool<InflateRequest> mRequestPool = new Pools.SynchronizedPool<>(10);
- // Extracted to its own method to ensure locals have a constrained liveness
- // scope by the GC. This is needed to avoid keeping previous request references
- // alive for an indeterminate amount of time, see b/33158143 for details
- public void runInner() {
- InflateRequest request;
- try {
- request = mQueue.take();
- } catch (InterruptedException ex) {
- // Odd, just continue
- Log.w(TAG, 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();
- }
- @Override
- public void run() {
- ThreadLocal<Looper> sThreadLocal = null;
- try {
- Field field = Looper.class.getDeclaredField("sThreadLocal");
- field.setAccessible(true);
- Object object = field.get(Looper.getMainLooper());
- if (object instanceof ThreadLocal) {
- sThreadLocal = (ThreadLocal<Looper>) object;
- sThreadLocal.set(Looper.getMainLooper());
- }
- Log.i("AsyncLayoutInflater", "myLooper:" + Looper.myLooper());
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- 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) {
- try {
- mQueue.put(request);
- } catch (InterruptedException e) {
- throw new RuntimeException(
- "Failed to enqueue async inflate request", e);
- }
- }
- }
- }
Add Comment
Please, Sign In to add comment