AsyncLayoutInflater顾名思义异步加载xml,如果布局比较复杂,且耗时较多情况下,可以使用此方式异步加载布局,使用方法很简单;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "asyncLayoutInflater";
private LinearLayout content;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
content = findViewById(R.id.content);
new AsyncLayoutInflater(this).inflate(R.layout.activity_include, content,
new AsyncLayoutInflater.OnInflateFinishedListener() {
@Override
public void onInflateFinished(@NonNull View view, int i, @Nullable ViewGroup viewGroup) {
viewGroup.addView(view);
}
});
}
}
这样activity_include布局就加载到id为content的View中了;
来分析其源码:
LayoutInflater mInflater;
Handler mHandler;
InflateThread mInflateThread;
public AsyncLayoutInflater(@NonNull Context context) {
mInflater = new BasicInflater(context);
mHandler = new Handler(mHandlerCallback);
mInflateThread = InflateThread.getInstance();
}
看到这,初步猜测就是LayoutInflater+Handler+Thread实现了;
BasicInflater是继承LayoutInflater类,重写了onCreateView方法,无特别之处;
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);
}
}
InflateThread,一个线程池,单例模式,类加载后就会初始化并且运行线程,并且线程是不会退出的,一直while(true)在执行;
private static class InflateThread extends Thread {
private static final InflateThread sInstance;
static {
sInstance = new InflateThread();
sInstance.start();
}
public static InflateThread getInstance() {
return sInstance;
}
//阻塞队列,10个最多;
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) {
// 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消息回调Handler的callBack
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) {
try {
mQueue.put(request);
} catch (InterruptedException e) {
throw new RuntimeException(
"Failed to enqueue async inflate request", e);
}
}
}
}
布局加载,往生产者消费者模型中添加加载布局任务;
@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);
}
因为new Handler(mHandlerCallback),Handler创建方式是有CallBack的,因此会执行回调过程代码:
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);
}
//回调onInflateFinished
request.callback.onInflateFinished(
request.view, request.resid, request.parent);
mInflateThread.releaseRequest(request);
return true;
}
};
整个过程比较清晰,流程简单,涉及单例模式,生产者-消费者模型,对象池缓存,Handler的CallBack回调,Handler有3种回调方式,依次顺序为Message回调,Handler构造方法CallBakc回调,最后是重写HandlerMessage方法回调;
缺点:
1.生产者-消费者模型最大10个,超过线程需等待;
2.单个线程,执行效率较低,不退出执行,虽然有生产者-消费者阻塞,但是线程一直开着,未退出;
3.不支持LayoutInflater.Factory 或者 LayoutInflater.Factory2;
4.在加载完后需要手动addView到parent中,即调用viewGroup.addView(view);
5.添加inflater任务到生产者消费者模型后,等待时机触发未有cancel取消方式;
改造下使用线程池方式:
public class MyAsyncLayoutInflater {
private static final String TAG = "MyAsyncLayoutInflater";
LayoutInflater mInflater;
Handler mHandler;
InflateThread mInflateThread;
public MyAsyncLayoutInflater(@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 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;
}
};
public interface OnInflateFinishedListener {
void onInflateFinished(View view, int resid, ViewGroup parent);
}
private static class InflateRequest{
MyAsyncLayoutInflater 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 InflateRequestRunnable implements Runnable{
private InflateRequest request;
public InflateRequestRunnable(InflateRequest request) {
this.request = request;
}
@Override
public void run() {
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();
}
}
private static class InflateThread{
private static final InflateThread sInstance;
//这里线程池写法都是参考AsyncTask里面的
public static final Executor THREAD_POOL_EXECUTOR;
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final long KEEP_ALIVE_SECONDS = 30;
//无限制队列
private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<>();
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "MyAsyncLayoutInflater #" + mCount.getAndIncrement());
}
};
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
sInstance = new InflateThread();
}
public static InflateThread getInstance() {
return sInstance;
}
private SynchronizedPool<InflateRequest> mRequestPool = new SynchronizedPool<>(10);
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) {
THREAD_POOL_EXECUTOR.execute(new InflateRequestRunnable(request));
}
}
//取消inflater过程
public void cancelInflater(){
mHandler.removeCallbacksAndMessages(null);
}
}
使用方式:
AsyncLayoutInflater asyncLayoutInflater = new AsyncLayoutInflater(this);
for(int i =0;i<100000;i++){
asyncLayoutInflater.inflate(R.layout.activity_include, content,
new AsyncLayoutInflater.OnInflateFinishedListener() {
@Override
public void onInflateFinished(@NonNull View view, int i, @Nullable ViewGroup viewGroup) {
viewGroup.addView(view);
}
});
}
// MyAsyncLayoutInflater asyncLayoutInflater = new MyAsyncLayoutInflater(this);
// for(int i =0;i<100000;i++){
// asyncLayoutInflater.inflate(R.layout.activity_include, content,
// new MyAsyncLayoutInflater.OnInflateFinishedListener() {
// @Override
// public void onInflateFinished(@NonNull View view, int i, @Nullable ViewGroup viewGroup) {
// viewGroup.addView(view);
// }
// });
// }
最后对比两种方式加载时间,线程池优势还是很大的,当然一切还是根据实际需求为主,此处主要学习Android源码以及其设计模式;