blob: 8af048d9d13b2969c820d71b6af03ee7155fcad0 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.util;
import android.content.Context;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.launcher3.util.ViewPool.Reusable;
import androidx.annotation.AnyThread;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
/**
* Utility class to maintain a pool of reusable views.
* During initialization, views are inflated on the background thread.
*/
public class ViewPool<T extends View & Reusable> {
private final Object[] mPool;
private final LayoutInflater mInflater;
private final ViewGroup mParent;
private final int mLayoutId;
private int mCurrentSize = 0;
public ViewPool(Context context, @Nullable ViewGroup parent,
int layoutId, int maxSize, int initialSize) {
mLayoutId = layoutId;
mParent = parent;
mInflater = LayoutInflater.from(context);
mPool = new Object[maxSize];
if (initialSize > 0) {
initPool(initialSize);
}
}
@UiThread
private void initPool(int initialSize) {
Preconditions.assertUIThread();
Handler handler = new Handler();
// Inflate views on a non looper thread. This allows us to catch errors like calling
// "new Handler()" in constructor easily.
new Thread(() -> {
for (int i = 0; i < initialSize; i++) {
T view = inflateNewView();
handler.post(() -> addToPool(view));
}
}).start();
}
@UiThread
public void recycle(T view) {
Preconditions.assertUIThread();
view.onRecycle();
addToPool(view);
}
@UiThread
private void addToPool(T view) {
Preconditions.assertUIThread();
if (mCurrentSize >= mPool.length) {
// pool is full
return;
}
mPool[mCurrentSize] = view;
mCurrentSize++;
}
@UiThread
public T getView() {
Preconditions.assertUIThread();
if (mCurrentSize > 0) {
mCurrentSize--;
return (T) mPool[mCurrentSize];
}
return inflateNewView();
}
@AnyThread
private T inflateNewView() {
return (T) mInflater.inflate(mLayoutId, mParent, false);
}
/**
* Interface to indicate that a view is reusable
*/
public interface Reusable {
/**
* Called when a view is recycled / added back to the pool
*/
void onRecycle();
}
}