Guest User

Untitled

a guest
Jan 19th, 2018
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.03 KB | None | 0 0
  1. public final class AsyncLayoutInflater {
  2. private static final String TAG = "AsyncLayoutInflater";
  3.  
  4. LayoutInflater mInflater;
  5. Handler mHandler;
  6. InflateThread mInflateThread;
  7.  
  8. public AsyncLayoutInflater(@NonNull Context context) {
  9. mInflater = new BasicInflater(context);
  10. mHandler = new Handler(mHandlerCallback);
  11. mInflateThread = InflateThread.getInstance();
  12. }
  13.  
  14. @UiThread
  15. public void inflate(@LayoutRes int resid, @Nullable ViewGroup parent,
  16. @NonNull OnInflateFinishedListener callback) {
  17. if (callback == null) {
  18. throw new NullPointerException("callback argument may not be null!");
  19. }
  20. InflateRequest request = mInflateThread.obtainRequest();
  21. request.inflater = this;
  22. request.resid = resid;
  23. request.parent = parent;
  24. request.callback = callback;
  25. mInflateThread.enqueue(request);
  26. }
  27.  
  28. private Handler.Callback mHandlerCallback = new Handler.Callback() {
  29. @Override
  30. public boolean handleMessage(Message msg) {
  31. InflateRequest request = (InflateRequest) msg.obj;
  32. if (request.view == null) {
  33. request.view = mInflater.inflate(
  34. request.resid, request.parent, false);
  35. }
  36. request.callback.onInflateFinished(
  37. request.view, request.resid, request.parent);
  38. mInflateThread.releaseRequest(request);
  39. return true;
  40. }
  41. };
  42.  
  43. public interface OnInflateFinishedListener {
  44. void onInflateFinished(View view, int resid, ViewGroup parent);
  45. }
  46.  
  47. private static class InflateRequest {
  48. AsyncLayoutInflater inflater;
  49. ViewGroup parent;
  50. int resid;
  51. View view;
  52. OnInflateFinishedListener callback;
  53.  
  54. InflateRequest() {
  55. }
  56. }
  57.  
  58. private static class BasicInflater extends LayoutInflater {
  59. private static final String[] sClassPrefixList = {
  60. "android.widget.",
  61. "android.webkit.",
  62. "android.app."
  63. };
  64.  
  65. BasicInflater(Context context) {
  66. super(context);
  67. }
  68.  
  69. @Override
  70. public LayoutInflater cloneInContext(Context newContext) {
  71. return new BasicInflater(newContext);
  72. }
  73.  
  74. @Override
  75. protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
  76. for (String prefix : sClassPrefixList) {
  77. try {
  78. View view = createView(name, prefix, attrs);
  79. if (view != null) {
  80. return view;
  81. }
  82. } catch (ClassNotFoundException e) {
  83. // In this case we want to let the base class take a crack
  84. // at it.
  85. }
  86. }
  87.  
  88. return super.onCreateView(name, attrs);
  89. }
  90. }
  91.  
  92. private static class InflateThread extends Thread {
  93. private static final InflateThread sInstance;
  94. static {
  95. sInstance = new InflateThread();
  96. sInstance.start();
  97. }
  98.  
  99. public static InflateThread getInstance() {
  100. return sInstance;
  101. }
  102.  
  103. private ArrayBlockingQueue<InflateRequest> mQueue = new ArrayBlockingQueue<>(10);
  104. private Pools.SynchronizedPool<InflateRequest> mRequestPool = new Pools.SynchronizedPool<>(10);
  105.  
  106. // Extracted to its own method to ensure locals have a constrained liveness
  107. // scope by the GC. This is needed to avoid keeping previous request references
  108. // alive for an indeterminate amount of time, see b/33158143 for details
  109. public void runInner() {
  110. InflateRequest request;
  111. try {
  112. request = mQueue.take();
  113. } catch (InterruptedException ex) {
  114. // Odd, just continue
  115. Log.w(TAG, ex);
  116. return;
  117. }
  118.  
  119. try {
  120. request.view = request.inflater.mInflater.inflate(
  121. request.resid, request.parent, false);
  122. } catch (RuntimeException ex) {
  123. // Probably a Looper failure, retry on the UI thread
  124. Log.w(TAG, "Failed to inflate resource in the background! Retrying on the UI"
  125. + " thread", ex);
  126. }
  127. Message.obtain(request.inflater.mHandler, 0, request)
  128. .sendToTarget();
  129. }
  130.  
  131. @Override
  132. public void run() {
  133. ThreadLocal<Looper> sThreadLocal = null;
  134. try {
  135. Field field = Looper.class.getDeclaredField("sThreadLocal");
  136. field.setAccessible(true);
  137. Object object = field.get(Looper.getMainLooper());
  138. if (object instanceof ThreadLocal) {
  139. sThreadLocal = (ThreadLocal<Looper>) object;
  140. sThreadLocal.set(Looper.getMainLooper());
  141. }
  142. Log.i("AsyncLayoutInflater", "myLooper:" + Looper.myLooper());
  143. } catch (NoSuchFieldException e) {
  144. e.printStackTrace();
  145. } catch (IllegalAccessException e) {
  146. e.printStackTrace();
  147. }
  148. while (true) {
  149. runInner();
  150. }
  151. }
  152.  
  153. public InflateRequest obtainRequest() {
  154. InflateRequest obj = mRequestPool.acquire();
  155. if (obj == null) {
  156. obj = new InflateRequest();
  157. }
  158. return obj;
  159. }
  160.  
  161. public void releaseRequest(InflateRequest obj) {
  162. obj.callback = null;
  163. obj.inflater = null;
  164. obj.parent = null;
  165. obj.resid = 0;
  166. obj.view = null;
  167. mRequestPool.release(obj);
  168. }
  169.  
  170. public void enqueue(InflateRequest request) {
  171. try {
  172. mQueue.put(request);
  173. } catch (InterruptedException e) {
  174. throw new RuntimeException(
  175. "Failed to enqueue async inflate request", e);
  176. }
  177. }
  178. }
  179. }
Add Comment
Please, Sign In to add comment