diff --git a/README-ch.md b/README-ch.md index c34404b0..0425c1f2 100644 --- a/README-ch.md +++ b/README-ch.md @@ -169,9 +169,3 @@ recycler.setAdapter(myAdapter); # 开源许可证 vlayout遵循MIT开源许可证协议。 - -# 微信群 - -![](https://img.alicdn.com/tfs/TB11_2_kbSYBuNjSspiXXXNzpXa-167-167.png) - -搜索 `tangram_` 或者扫描以上二维码添加 Tangram 为好友,以便我们邀请你入群。 diff --git a/README.md b/README.md index 772b8b01..76b41b7f 100644 --- a/README.md +++ b/README.md @@ -168,9 +168,3 @@ Before you open an issue or create a pull request, please read [Contributing Gui # LICENSE Vlayout is available under the MIT license. - -# WeChatGroup - -![](https://img.alicdn.com/tfs/TB11_2_kbSYBuNjSspiXXXNzpXa-167-167.png) - -Search `tangram_` or scan the QR code above to be invited in WeChat. diff --git a/examples/src/main/java/com/alibaba/android/vlayout/example/VLayoutActivity.java b/examples/src/main/java/com/alibaba/android/vlayout/example/VLayoutActivity.java index cc19dc5e..318f3195 100644 --- a/examples/src/main/java/com/alibaba/android/vlayout/example/VLayoutActivity.java +++ b/examples/src/main/java/com/alibaba/android/vlayout/example/VLayoutActivity.java @@ -29,6 +29,7 @@ import com.alibaba.android.vlayout.RecyclablePagerAdapter; import com.alibaba.android.vlayout.VirtualLayoutManager; import com.alibaba.android.vlayout.VirtualLayoutManager.LayoutParams; +import com.alibaba.android.vlayout.extend.PerformanceMonitor; import com.alibaba.android.vlayout.extend.ViewLifeCycleListener; import com.alibaba.android.vlayout.layout.ColumnLayoutHelper; import com.alibaba.android.vlayout.layout.FixLayoutHelper; @@ -120,7 +121,22 @@ protected void onCreate(Bundle savedInstanceState) { final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.main_view); final VirtualLayoutManager layoutManager = new VirtualLayoutManager(this); + layoutManager.setPerformanceMonitor(new PerformanceMonitor() { + long start; + long end; + + @Override + public void recordStart(String phase, View view) { + start = System.currentTimeMillis(); + } + + @Override + public void recordEnd(String phase, View view) { + end = System.currentTimeMillis(); + Log.d("VLayoutActivity", view.getClass().getName() + " " + (end - start)); + } + }); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int scrollState) { diff --git a/gradle.properties b/gradle.properties index 021f2cc5..994ff7ac 100644 --- a/gradle.properties +++ b/gradle.properties @@ -44,7 +44,7 @@ GROUP=com.alibaba.android ARTIFACT=vlayout VERSION=1 -VERSION_NAME=1.2.13 +VERSION_NAME=1.2.17 PACKAGING_TYPE=aar useNewSupportLibrary=true systemProp.compileSdkVersion=25 diff --git a/vlayout/src/main/java/com/alibaba/android/vlayout/Cantor.java b/vlayout/src/main/java/com/alibaba/android/vlayout/Cantor.java index 73b2d7e8..1729b0b4 100644 --- a/vlayout/src/main/java/com/alibaba/android/vlayout/Cantor.java +++ b/vlayout/src/main/java/com/alibaba/android/vlayout/Cantor.java @@ -28,11 +28,11 @@ public static void reverseCantor(long cantor, long[] result) { result = new long[2]; } // reverse Cantor Function - int w = (int) (Math.floor(Math.sqrt(8 * cantor + 1) - 1) / 2); - int t = (w * w + w) / 2; + long w = (long) (Math.floor(Math.sqrt(8 * cantor + 1) - 1) / 2); + long t = (w * w + w) / 2; - int k2 = (int)(cantor - t); - int k1 = w - k2; + long k2 = cantor - t; + long k1 = w - k2; result[0] = k1; result[1] = k2; } diff --git a/vlayout/src/main/java/com/alibaba/android/vlayout/RangeLayoutHelperFinder.java b/vlayout/src/main/java/com/alibaba/android/vlayout/RangeLayoutHelperFinder.java index cde8451e..3201b7f1 100644 --- a/vlayout/src/main/java/com/alibaba/android/vlayout/RangeLayoutHelperFinder.java +++ b/vlayout/src/main/java/com/alibaba/android/vlayout/RangeLayoutHelperFinder.java @@ -27,10 +27,13 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.ListIterator; /** * An implement of {@link LayoutHelperFinder} which finds layoutHelpers by position @@ -46,6 +49,8 @@ public class RangeLayoutHelperFinder extends LayoutHelperFinder { @NonNull private List mReverseLayoutHelpers =new LinkedList<>(); + private LayoutHelperItem[] mSortedLayoutHelpers = null; + @NonNull private Comparator mLayoutHelperItemComparator = new Comparator() { @Override @@ -68,16 +73,21 @@ public void setLayouts(@Nullable List layouts) { mReverseLayoutHelpers.clear(); mLayoutHelperItems.clear(); if (layouts != null) { - for (int i = 0, size = layouts.size(); i < size; i++) { - LayoutHelper helper = layouts.get(i); + ListIterator iterator = layouts.listIterator(); + LayoutHelper helper = null; + while (iterator.hasNext()) { + helper = iterator.next(); mLayoutHelpers.add(helper); mLayoutHelperItems.add(new LayoutHelperItem(helper)); } - for (int i = layouts.size() - 1; i >= 0; i--) { - mReverseLayoutHelpers.add(layouts.get(i)); + + while (iterator.hasPrevious()) { + mReverseLayoutHelpers.add(iterator.previous()); } - Collections.sort(mLayoutHelperItems, mLayoutHelperItemComparator); + // Collections.sort(mLayoutHelperItems, mLayoutHelperItemComparator); + mSortedLayoutHelpers = mLayoutHelperItems.toArray(new LayoutHelperItem[mLayoutHelperItems.size()]); + Arrays.sort(mSortedLayoutHelpers, mLayoutHelperItemComparator); } } @@ -90,18 +100,17 @@ protected List getLayoutHelpers() { @Nullable @Override public LayoutHelper getLayoutHelper(int position) { - final int count = mLayoutHelperItems.size(); - if (count == 0) { + if (mSortedLayoutHelpers == null || mSortedLayoutHelpers.length == 0) { return null; } + final int count = mSortedLayoutHelpers.length; int s = 0, e = count - 1, m; LayoutHelperItem rs = null; - // binary search range while (s <= e) { m = (s + e) / 2; - rs = mLayoutHelperItems.get(m); + rs = mSortedLayoutHelpers[m]; if (rs.getStartPosition() > position) { e = m - 1; } else if (rs.getEndPosition() < position) { diff --git a/vlayout/src/main/java/com/alibaba/android/vlayout/VirtualLayoutManager.java b/vlayout/src/main/java/com/alibaba/android/vlayout/VirtualLayoutManager.java index 355cf969..7653b3e7 100644 --- a/vlayout/src/main/java/com/alibaba/android/vlayout/VirtualLayoutManager.java +++ b/vlayout/src/main/java/com/alibaba/android/vlayout/VirtualLayoutManager.java @@ -24,14 +24,7 @@ package com.alibaba.android.vlayout; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - +import com.alibaba.android.vlayout.extend.PerformanceMonitor; import com.alibaba.android.vlayout.extend.ViewLifeCycleHelper; import com.alibaba.android.vlayout.extend.ViewLifeCycleListener; import com.alibaba.android.vlayout.layout.BaseLayoutHelper; @@ -54,6 +47,16 @@ import android.view.ViewGroup; import android.view.ViewParent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + /** * A {@link android.support.v7.widget.RecyclerView.LayoutManager} implementation which provides @@ -69,6 +72,8 @@ public class VirtualLayoutManager extends ExposeLinearLayoutManagerEx implements LayoutManagerHelper { protected static final String TAG = "VirtualLayoutManager"; + private static final String PHASE_MEASURE = "measure"; + private static final String PHASE_LAYOUT = "layout"; private static final String TRACE_LAYOUT = "VLM onLayoutChildren"; private static final String TRACE_SCROLL = "VLM scroll"; @@ -92,12 +97,32 @@ public static void enableDebugging(boolean isDebug) { private boolean mNestedScrolling = false; + private boolean mCanScrollHorizontally; + + private boolean mCanScrollVertically; + private boolean mEnableMarginOverlapping = false; private int mMaxMeasureSize = -1; + private PerformanceMonitor mPerformanceMonitor; + private ViewLifeCycleHelper mViewLifeCycleHelper; + private Comparator, Integer>> mRangeComparator = new Comparator, Integer>>() { + @Override + public int compare(Pair, Integer> a, Pair, Integer> b) { + if (a == null && b == null) return 0; + if (a == null) return -1; + if (b == null) return 1; + + Range lr = a.first; + Range rr = b.first; + + return lr.getLower() - rr.getLower(); + } + }; + public VirtualLayoutManager(@NonNull final Context context) { this(context, VERTICAL); } @@ -121,9 +146,14 @@ public VirtualLayoutManager(@NonNull final Context context, int orientation, boo super(context, orientation, reverseLayout); this.mOrientationHelper = OrientationHelperEx.createOrientationHelper(this, orientation); this.mSecondaryOrientationHelper = OrientationHelperEx.createOrientationHelper(this, orientation == VERTICAL ? HORIZONTAL : VERTICAL); + this.mCanScrollVertically = super.canScrollVertically(); + this.mCanScrollHorizontally = super.canScrollHorizontally(); setHelperFinder(new RangeLayoutHelperFinder()); } + public void setPerformanceMonitor(PerformanceMonitor performanceMonitor) { + mPerformanceMonitor = performanceMonitor; + } public void setNoScrolling(boolean noScrolling) { this.mNoScrolling = noScrolling; @@ -132,6 +162,14 @@ public void setNoScrolling(boolean noScrolling) { mSpaceMeasuring = false; } + public void setCanScrollVertically(boolean canScrollVertically) { + this.mCanScrollVertically = canScrollVertically; + } + + public void setCanScrollHorizontally(boolean canScrollHorizontally) { + this.mCanScrollHorizontally = canScrollHorizontally; + } + public void setNestedScrolling(boolean nestedScrolling) { setNestedScrolling(nestedScrolling, -1); } @@ -153,9 +191,12 @@ public void setHelperFinder(@NonNull final LayoutHelperFinder finder) { List helpers = new LinkedList<>(); if (this.mHelperFinder != null) { List layoutHelpers = mHelperFinder.getLayoutHelpers(); - for (int i = 0, size = layoutHelpers.size(); i < size; i++) { - LayoutHelper helper = layoutHelpers.get(i); - helpers.add(helper); + Iterator iterator = layoutHelpers.iterator(); + LayoutHelper layoutHelper = null; + while (iterator.hasNext()) { + layoutHelper = iterator.next(); + helpers.add(layoutHelper); + } } @@ -189,17 +230,18 @@ public void setFixOffset(int left, int top, int right, int bottom) { */ public void setLayoutHelpers(@Nullable List helpers) { List layoutHelpers = mHelperFinder.getLayoutHelpers(); - for (int i = 0, size = layoutHelpers.size(); i < size; i++) { - LayoutHelper helper = layoutHelpers.get(i); + Iterator it0 = layoutHelpers.iterator(); + while (it0.hasNext()) { + LayoutHelper helper = it0.next(); oldHelpersSet.put(System.identityHashCode(helper), helper); } // set ranges if (helpers != null) { int start = 0; - for (int i = 0; i < helpers.size(); i++) { - LayoutHelper helper = helpers.get(i); - + Iterator it1 = helpers.iterator(); + while (it1.hasNext()) { + LayoutHelper helper = it1.next(); if (helper instanceof FixAreaLayoutHelper) { ((FixAreaLayoutHelper) helper).setAdjuster(mFixAreaAdjustor); } @@ -222,12 +264,12 @@ public void setLayoutHelpers(@Nullable List helpers) { this.mHelperFinder.setLayouts(helpers); layoutHelpers = mHelperFinder.getLayoutHelpers(); - for (int i = 0, size = layoutHelpers.size(); i < size; i++) { - LayoutHelper helper = layoutHelpers.get(i); - newHelpersSet.put(System.identityHashCode(helper), helper); + Iterator iterator = layoutHelpers.iterator(); + while (iterator.hasNext()) { + LayoutHelper layoutHelper = iterator.next(); + newHelpersSet.put(System.identityHashCode(layoutHelper), layoutHelper); } - for (Iterator> it = oldHelpersSet.entrySet().iterator(); it.hasNext(); ) { Map.Entry entry = it.next(); Integer key = entry.getKey(); @@ -342,8 +384,10 @@ public void onAnchorReady(RecyclerView.State state, ExposeLinearLayoutManagerEx. mTempAnchorInfoWrapper.position = anchorInfo.mPosition; mTempAnchorInfoWrapper.coordinate = anchorInfo.mCoordinate; List layoutHelpers = mHelperFinder.getLayoutHelpers(); - for (int i = 0, size = layoutHelpers.size(); i < size; i++) { - LayoutHelper layoutHelper = layoutHelpers.get(i); + Iterator iterator = layoutHelpers.iterator(); + LayoutHelper layoutHelper = null; + while (iterator.hasNext()) { + layoutHelper = iterator.next(); layoutHelper.onRefreshLayout(state, mTempAnchorInfoWrapper, this); } } @@ -412,8 +456,10 @@ private void runPreLayout(RecyclerView.Recycler recycler, RecyclerView.State sta if (mNested == 0) { List reverseLayoutHelpers = mHelperFinder.reverse(); - for (int i = 0, size = reverseLayoutHelpers.size(); i < size; i++) { - LayoutHelper layoutHelper = reverseLayoutHelpers.get(i); + Iterator iterator = reverseLayoutHelpers.iterator(); + LayoutHelper layoutHelper = null; + while (iterator.hasNext()) { + layoutHelper = iterator.next(); layoutHelper.beforeLayout(recycler, state, this); } } @@ -428,8 +474,10 @@ private void runPostLayout(RecyclerView.Recycler recycler, RecyclerView.State st final int startPosition = findFirstVisibleItemPosition(); final int endPosition = findLastVisibleItemPosition(); List layoutHelpers = mHelperFinder.getLayoutHelpers(); - for (int i = 0, size = layoutHelpers.size(); i < size; i++) { - LayoutHelper layoutHelper = layoutHelpers.get(i); + Iterator iterator = layoutHelpers.iterator(); + LayoutHelper layoutHelper = null; + while (iterator.hasNext()) { + layoutHelper = iterator.next(); try { layoutHelper.afterLayout(recycler, state, startPosition, endPosition, scrolled, this); } catch (Exception e) { @@ -586,8 +634,10 @@ public void onScrollStateChanged(int state) { int startPosition = findFirstVisibleItemPosition(); int endPosition = findLastVisibleItemPosition(); List layoutHelpers = mHelperFinder.getLayoutHelpers(); - for (int i = 0, size = layoutHelpers.size(); i < size; i++) { - LayoutHelper layoutHelper = layoutHelpers.get(i); + Iterator iterator = layoutHelpers.iterator(); + LayoutHelper layoutHelper = null; + while (iterator.hasNext()) { + layoutHelper = iterator.next(); layoutHelper.onScrollStateChanged(state, startPosition, endPosition, this); } } @@ -597,9 +647,12 @@ public void offsetChildrenHorizontal(int dx) { super.offsetChildrenHorizontal(dx); List layoutHelpers = mHelperFinder.getLayoutHelpers(); - for (int i = 0, size = layoutHelpers.size(); i < size; i++) { - LayoutHelper layoutHelper = layoutHelpers.get(i); + Iterator iterator = layoutHelpers.iterator(); + LayoutHelper layoutHelper = null; + while (iterator.hasNext()) { + layoutHelper = iterator.next(); layoutHelper.onOffsetChildrenHorizontal(dx, this); + } } @@ -607,8 +660,10 @@ public void offsetChildrenHorizontal(int dx) { public void offsetChildrenVertical(int dy) { super.offsetChildrenVertical(dy); List layoutHelpers = mHelperFinder.getLayoutHelpers(); - for (int i = 0, size = layoutHelpers.size(); i < size; i++) { - LayoutHelper layoutHelper = layoutHelpers.get(i); + Iterator iterator = layoutHelpers.iterator(); + LayoutHelper layoutHelper = null; + while (iterator.hasNext()) { + layoutHelper = iterator.next(); layoutHelper.onOffsetChildrenVertical(dy, this); } @@ -635,7 +690,7 @@ public int getVirtualLayoutDirection() { private LayoutStateWrapper mTempLayoutStateWrapper = new LayoutStateWrapper(); - private List, Integer>> mRangeLengths = new LinkedList<>(); + private List, Integer>> mRangeLengths = new ArrayList<>(); @Nullable private int findRangeLength(@NonNull final Range range) { @@ -710,19 +765,7 @@ protected void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State st } mRangeLengths.add(Pair.create(range, consumed)); - Collections.sort(mRangeLengths, new Comparator, Integer>>() { - @Override - public int compare(Pair, Integer> a, Pair, Integer> b) { - if (a == null && b == null) return 0; - if (a == null) return -1; - if (b == null) return 1; - - Range lr = a.first; - Range rr = b.first; - - return lr.getLower() - rr.getLower(); - } - }); + Collections.sort(mRangeLengths, mRangeComparator); } } @@ -830,8 +873,10 @@ public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCo @Override public void onItemsChanged(RecyclerView recyclerView) { List layoutHelpers = mHelperFinder.getLayoutHelpers(); - for (int i = 0, size = layoutHelpers.size(); i < size; i++) { - LayoutHelper layoutHelper = layoutHelpers.get(i); + Iterator iterator = layoutHelpers.iterator(); + LayoutHelper layoutHelper = null; + while (iterator.hasNext()) { + layoutHelper = iterator.next(); layoutHelper.onItemsChanged(this); } @@ -885,8 +930,10 @@ public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycl super.onDetachedFromWindow(view, recycler); List layoutHelpers = mHelperFinder.getLayoutHelpers(); - for (int i = 0, size = layoutHelpers.size(); i < size; i++) { - LayoutHelper layoutHelper = layoutHelpers.get(i); + Iterator iterator = layoutHelpers.iterator(); + LayoutHelper layoutHelper = null; + while (iterator.hasNext()) { + layoutHelper = iterator.next(); layoutHelper.clear(this); } @@ -1119,8 +1166,10 @@ public List getFixedViews() { // TODO: support zIndex? List views = new LinkedList<>(); List layoutHelpers = mHelperFinder.getLayoutHelpers(); - for (int i = 0, size = layoutHelpers.size(); i < size; i++) { - LayoutHelper layoutHelper = layoutHelpers.get(i); + Iterator iterator = layoutHelpers.iterator(); + LayoutHelper layoutHelper = null; + while (iterator.hasNext()) { + layoutHelper = iterator.next(); View fixedView = layoutHelper.getFixedView(); if (fixedView != null) { views.add(fixedView); @@ -1281,25 +1330,37 @@ public int getChildMeasureSpec(int parentSize, int size, boolean canScroll) { @Override public boolean canScrollHorizontally() { - return super.canScrollHorizontally() && !mNoScrolling; + return mCanScrollHorizontally && !mNoScrolling; } @Override public boolean canScrollVertically() { - return super.canScrollVertically() && !mNoScrolling; + return mCanScrollVertically && !mNoScrolling; } @Override public void layoutChildWithMargins(View child, int left, int top, int right, int bottom) { final ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) child.getLayoutParams(); + if (mPerformanceMonitor != null) { + mPerformanceMonitor.recordStart(PHASE_LAYOUT, child); + } layoutDecorated(child, left + lp.leftMargin, top + lp.topMargin, right - lp.rightMargin, bottom - lp.bottomMargin); + if (mPerformanceMonitor != null) { + mPerformanceMonitor.recordEnd(PHASE_LAYOUT, child); + } } @Override public void layoutChild(View child, int left, int top, int right, int bottom) { + if (mPerformanceMonitor != null) { + mPerformanceMonitor.recordStart(PHASE_LAYOUT, child); + } layoutDecorated(child, left, top, right, bottom); + if (mPerformanceMonitor != null) { + mPerformanceMonitor.recordEnd(PHASE_LAYOUT, child); + } } @Override @@ -1417,7 +1478,13 @@ private void measureChildWithDecorations(View child, int widthSpec, int heightSp calculateItemDecorationsForChild(child, mDecorInsets); widthSpec = updateSpecWithExtra(widthSpec, mDecorInsets.left, mDecorInsets.right); heightSpec = updateSpecWithExtra(heightSpec, mDecorInsets.top, mDecorInsets.bottom); + if (mPerformanceMonitor != null) { + mPerformanceMonitor.recordStart(PHASE_MEASURE, child); + } child.measure(widthSpec, heightSpec); + if (mPerformanceMonitor != null) { + mPerformanceMonitor.recordEnd(PHASE_MEASURE, child); + } } private void measureChildWithDecorationsAndMargin(View child, int widthSpec, int heightSpec) { @@ -1432,7 +1499,13 @@ private void measureChildWithDecorationsAndMargin(View child, int widthSpec, int heightSpec = updateSpecWithExtra(heightSpec, mDecorInsets.top, mDecorInsets.bottom); } + if (mPerformanceMonitor != null) { + mPerformanceMonitor.recordStart(PHASE_MEASURE, child); + } child.measure(widthSpec, heightSpec); + if (mPerformanceMonitor != null) { + mPerformanceMonitor.recordEnd(PHASE_MEASURE, child); + } } /** diff --git a/vlayout/src/main/java/com/alibaba/android/vlayout/extend/PerformanceMonitor.java b/vlayout/src/main/java/com/alibaba/android/vlayout/extend/PerformanceMonitor.java new file mode 100644 index 00000000..7c4ec661 --- /dev/null +++ b/vlayout/src/main/java/com/alibaba/android/vlayout/extend/PerformanceMonitor.java @@ -0,0 +1,57 @@ +package com.alibaba.android.vlayout.extend; + +import android.support.annotation.Keep; +import android.view.View; + +/** + * Add callback during measure and layout, help you to monitor your view's performance.
+ * Designed as Class instead of Interface is able to extend api in future.
+ * + * Created by longerian on 2018/5/16. + * + * @author longerian + * @date 2018/05/16 + */ +public class PerformanceMonitor { + + /** + * Record the start time + * @param phase + * @param viewType + */ + @Keep + public void recordStart(String phase, String viewType) { + + } + + /** + * Record the end time + * @param phase + * @param viewType + */ + @Keep + public void recordEnd(String phase, String viewType) { + + } + + /** + * Record the start time + * @param phase + * @param view + */ + @Keep + public void recordStart(String phase, View view) { + + } + + /** + * Record the end time + * @param phase + * @param view + */ + @Keep + public void recordEnd(String phase, View view) { + + } + +}