1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.test.uibench; 17 18 import android.content.Context; 19 import android.content.res.Resources; 20 import android.graphics.Color; 21 import android.graphics.drawable.GradientDrawable; 22 import android.graphics.drawable.InsetDrawable; 23 import androidx.recyclerview.widget.LinearLayoutManager; 24 import androidx.recyclerview.widget.RecyclerView; 25 import android.view.View; 26 import android.view.ViewGroup; 27 28 import com.android.test.uibench.recyclerview.RvCompatListActivity; 29 30 import java.util.ArrayList; 31 import java.util.concurrent.TimeUnit; 32 33 public class SlowNestedRecyclerViewActivity extends RvCompatListActivity { 34 private static final int OUTER_ITEM_COUNT = 100; 35 private static final int INNER_ITEM_COUNT = 20; 36 37 private static final long INNER_ITEM_CREATE_NS = TimeUnit.MILLISECONDS.toNanos(6); 38 private static final long INNER_ITEM_BIND_NS = TimeUnit.MILLISECONDS.toNanos(1); 39 private static final long INNER_ITEM_ATTACH_NS = TimeUnit.MILLISECONDS.toNanos(1); 40 41 private static final long OUTER_ITEM_CREATE_NS = TimeUnit.MILLISECONDS.toNanos(3); 42 private static final long OUTER_ITEM_BIND_NS = TimeUnit.MILLISECONDS.toNanos(1); 43 private static final long OUTER_ITEM_ATTACH_NS = TimeUnit.MILLISECONDS.toNanos(1); 44 45 private SizeData mSizeData; 46 47 private static class SizeData { 48 final int innerItemWidth; 49 final int innerItemHeight; 50 final int headerHeight; 51 SizeData(Resources resources)52 SizeData(Resources resources) { 53 innerItemWidth = (int) (resources.getDisplayMetrics().widthPixels / 3.3f); 54 innerItemHeight = (int) (innerItemWidth * 1.6f); 55 headerHeight = (int) (resources.getDisplayMetrics().heightPixels * 0.5f); 56 } 57 } 58 getSizeData(Resources resources)59 private SizeData getSizeData(Resources resources) { 60 if (mSizeData == null) { 61 mSizeData = new SizeData(resources); 62 } 63 return mSizeData; 64 } 65 66 @Override createLayoutManager(Context context)67 protected RecyclerView.LayoutManager createLayoutManager(Context context) { 68 return new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); 69 } 70 71 @Override createAdapter()72 protected RecyclerView.Adapter createAdapter() { 73 return new OuterAdapter(); 74 } 75 76 private class InnerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { 77 @Override onCreateViewHolder(ViewGroup parent, int viewType)78 public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 79 final long start = System.nanoTime(); 80 81 final float density = parent.getResources().getDisplayMetrics().density; 82 View view = new View(parent.getContext()) { 83 @Override 84 protected void onAttachedToWindow() { 85 final long start = System.nanoTime(); 86 super.onAttachedToWindow(); 87 while (System.nanoTime() - start < INNER_ITEM_ATTACH_NS); 88 } 89 }; 90 91 SizeData sizeData = getSizeData(parent.getResources()); 92 view.setMinimumWidth(sizeData.innerItemWidth); 93 view.setMinimumHeight(sizeData.innerItemHeight); 94 95 GradientDrawable bg = new GradientDrawable(); 96 bg.setCornerRadius(10 * density); 97 bg.setColor(Color.BLACK); 98 final int pad = (int)(10 * density); 99 view.setPadding(pad, pad, pad, pad); 100 view.setBackgroundDrawable(new InsetDrawable(bg, pad)); 101 RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(view) {}; 102 103 while (System.nanoTime() - start < INNER_ITEM_CREATE_NS); 104 return holder; 105 } 106 107 @Override onBindViewHolder(RecyclerView.ViewHolder holder, int position)108 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 109 final long start = System.nanoTime(); 110 while (System.nanoTime() - start < INNER_ITEM_BIND_NS); 111 } 112 113 @Override getItemCount()114 public int getItemCount() { return INNER_ITEM_COUNT; } 115 } 116 117 private class OuterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { 118 static final int TYPE_HEADER = 0; 119 static final int TYPE_RECYCLER = 1; 120 121 ArrayList<InnerAdapter> mAdapters = new ArrayList<>(); 122 RecyclerView.RecycledViewPool mSharedPool = new RecyclerView.RecycledViewPool(); 123 OuterAdapter()124 OuterAdapter() { 125 for (int i = 0; i < OUTER_ITEM_COUNT; i++) { 126 mAdapters.add(new InnerAdapter()); 127 } 128 } 129 130 @Override onCreateViewHolder(ViewGroup parent, int viewType)131 public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 132 SizeData sizeData = getSizeData(parent.getResources()); 133 if (viewType == TYPE_HEADER) { 134 View view = new View(parent.getContext()); 135 view.setMinimumHeight(sizeData.headerHeight); 136 return new RecyclerView.ViewHolder(view) {}; 137 } else { 138 final long start = System.nanoTime(); 139 140 RecyclerView rv = new RecyclerView(parent.getContext()) { 141 @Override 142 protected void onAttachedToWindow() { 143 final long start = System.nanoTime(); 144 super.onAttachedToWindow(); 145 while (System.nanoTime() - start < OUTER_ITEM_ATTACH_NS); 146 147 } 148 }; 149 150 rv.setLayoutParams(new RecyclerView.LayoutParams( 151 ViewGroup.LayoutParams.MATCH_PARENT, sizeData.innerItemHeight)); 152 rv.setLayoutManager(new LinearLayoutManager(parent.getContext(), 153 LinearLayoutManager.HORIZONTAL, false)); 154 rv.setRecycledViewPool(mSharedPool); 155 RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(rv) {}; 156 157 while (System.nanoTime() - start < OUTER_ITEM_CREATE_NS); 158 return holder; 159 } 160 } 161 162 @Override onBindViewHolder(RecyclerView.ViewHolder holder, int position)163 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 164 if (getItemViewType(position) == TYPE_RECYCLER) { 165 final long start = System.nanoTime(); 166 ((RecyclerView)holder.itemView).setAdapter(mAdapters.get(position)); 167 while (System.nanoTime() - start < OUTER_ITEM_BIND_NS); 168 } 169 } 170 171 @Override getItemViewType(int position)172 public int getItemViewType(int position) { 173 return position == 0 ? TYPE_HEADER : TYPE_RECYCLER; 174 } 175 176 @Override getItemCount()177 public int getItemCount() { 178 return mAdapters.size(); 179 } 180 } 181 } 182