/* * Copyright (C) 2016 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.test.uibench; import android.content.Context; import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.InsetDrawable; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.view.View; import android.view.ViewGroup; import com.android.test.uibench.recyclerview.RvCompatListActivity; import java.util.ArrayList; import java.util.concurrent.TimeUnit; public class SlowNestedRecyclerViewActivity extends RvCompatListActivity { private static final int OUTER_ITEM_COUNT = 100; private static final int INNER_ITEM_COUNT = 20; private static final long INNER_ITEM_CREATE_NS = TimeUnit.MILLISECONDS.toNanos(6); private static final long INNER_ITEM_BIND_NS = TimeUnit.MILLISECONDS.toNanos(1); private static final long INNER_ITEM_ATTACH_NS = TimeUnit.MILLISECONDS.toNanos(1); private static final long OUTER_ITEM_CREATE_NS = TimeUnit.MILLISECONDS.toNanos(3); private static final long OUTER_ITEM_BIND_NS = TimeUnit.MILLISECONDS.toNanos(1); private static final long OUTER_ITEM_ATTACH_NS = TimeUnit.MILLISECONDS.toNanos(1); private SizeData mSizeData; private static class SizeData { final int innerItemWidth; final int innerItemHeight; final int headerHeight; SizeData(Resources resources) { innerItemWidth = (int) (resources.getDisplayMetrics().widthPixels / 3.3f); innerItemHeight = (int) (innerItemWidth * 1.6f); headerHeight = (int) (resources.getDisplayMetrics().heightPixels * 0.5f); } } private SizeData getSizeData(Resources resources) { if (mSizeData == null) { mSizeData = new SizeData(resources); } return mSizeData; } @Override protected RecyclerView.LayoutManager createLayoutManager(Context context) { return new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); } @Override protected RecyclerView.Adapter createAdapter() { return new OuterAdapter(); } private class InnerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { final long start = System.nanoTime(); final float density = parent.getResources().getDisplayMetrics().density; View view = new View(parent.getContext()) { @Override protected void onAttachedToWindow() { final long start = System.nanoTime(); super.onAttachedToWindow(); while (System.nanoTime() - start < INNER_ITEM_ATTACH_NS); } }; SizeData sizeData = getSizeData(parent.getResources()); view.setMinimumWidth(sizeData.innerItemWidth); view.setMinimumHeight(sizeData.innerItemHeight); GradientDrawable bg = new GradientDrawable(); bg.setCornerRadius(10 * density); bg.setColor(Color.BLACK); final int pad = (int)(10 * density); view.setPadding(pad, pad, pad, pad); view.setBackgroundDrawable(new InsetDrawable(bg, pad)); RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(view) {}; while (System.nanoTime() - start < INNER_ITEM_CREATE_NS); return holder; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { final long start = System.nanoTime(); while (System.nanoTime() - start < INNER_ITEM_BIND_NS); } @Override public int getItemCount() { return INNER_ITEM_COUNT; } } private class OuterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { static final int TYPE_HEADER = 0; static final int TYPE_RECYCLER = 1; ArrayList<InnerAdapter> mAdapters = new ArrayList<>(); RecyclerView.RecycledViewPool mSharedPool = new RecyclerView.RecycledViewPool(); OuterAdapter() { for (int i = 0; i < OUTER_ITEM_COUNT; i++) { mAdapters.add(new InnerAdapter()); } } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { SizeData sizeData = getSizeData(parent.getResources()); if (viewType == TYPE_HEADER) { View view = new View(parent.getContext()); view.setMinimumHeight(sizeData.headerHeight); return new RecyclerView.ViewHolder(view) {}; } else { final long start = System.nanoTime(); RecyclerView rv = new RecyclerView(parent.getContext()) { @Override protected void onAttachedToWindow() { final long start = System.nanoTime(); super.onAttachedToWindow(); while (System.nanoTime() - start < OUTER_ITEM_ATTACH_NS); } }; rv.setLayoutParams(new RecyclerView.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, sizeData.innerItemHeight)); rv.setLayoutManager(new LinearLayoutManager(parent.getContext(), LinearLayoutManager.HORIZONTAL, false)); rv.setRecycledViewPool(mSharedPool); RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(rv) {}; while (System.nanoTime() - start < OUTER_ITEM_CREATE_NS); return holder; } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (getItemViewType(position) == TYPE_RECYCLER) { final long start = System.nanoTime(); ((RecyclerView)holder.itemView).setAdapter(mAdapters.get(position)); while (System.nanoTime() - start < OUTER_ITEM_BIND_NS); } } @Override public int getItemViewType(int position) { return position == 0 ? TYPE_HEADER : TYPE_RECYCLER; } @Override public int getItemCount() { return mAdapters.size(); } } }