tips:观察AndroidStudio的调用堆栈,对看源码分析问题很有帮助
业务场景
RecyclerView+LinearLayoutManager实现视频播放列表。当前视频播放完成后,自动向上滚动一个item,并且开始播放。
遇到问题
1.问题代码
//滑动一个item
recyclerView.scrollToPosition((msg.arg1 + 1));
View childAt = layoutManager.findViewByPosition((msg.arg1 + 1));
if (childAt!=null){
//视频开始播放
NiceVideoPlayer niceVideoPlayer=childAt.findViewById(R.id.nice_video_player);
niceVideoPlayer.start();
}
当前屏幕上有3个item,从第0个开始播放。第0个播放完成,播放第1个。第1个播放完成,播放第2个,layoutManager.findViewByPosition都可以获取到item。加载position为3的item时,layoutManager.findViewByPosition返回null。奇怪的事,position为3的item已经显示在屏幕上。
2.修改后的代码
//742是一个item的高度
recyclerView.scrollBy(0,742);
View childAt = layoutManager.findViewByPosition((msg.arg1 + 1));
if (childAt!=null){
//视频开始播放
NiceVideoPlayer niceVideoPlayer=childAt.findViewById(R.id.nice_video_player);
niceVideoPlayer.start();
}
原因分析
1.recyclerView.scrollToPosition((msg.arg1 + 1))为啥不行(未完待续)
RecyclerView
public void scrollToPosition(int position) {
if (mLayoutFrozen) {
return;
}
stopScroll();
if (mLayout == null) {
Log.e(TAG, "Cannot scroll to position a LayoutManager set. "
+ "Call setLayoutManager with a non-null argument.");
return;
}
mLayout.scrollToPosition(position);
awakenScrollBars();
}
LinearLayoutManager
@Override
public void scrollToPosition(int position) {
mPendingScrollPosition = position;
mPendingScrollPositionOffset = INVALID_OFFSET;
if (mPendingSavedState != null) {
mPendingSavedState.invalidateAnchor();
}
requestLayout();
}
LinearLayoutManager
public void requestLayout() {
if (mRecyclerView != null) {
mRecyclerView.requestLayout();
}
}
RecyclerView.scrollToPosition最终调用了RecyclerView的request()方法,RecyclerVeiw的onMeasure(),onLayout()都会被调用,onDraw()方法可能别调用,这没分析完,下次再写。
2.recyclerView.scrollBy(0,742)为啥可以
RecyclerView
@Override
public void scrollBy(int x, int y) {
if (mLayout == null) {
Log.e(TAG, "Cannot scroll without a LayoutManager set. "
+ "Call setLayoutManager with a non-null argument.");
return;
}
if (mLayoutFrozen) {
return;
}
final boolean canScrollHorizontal = mLayout.canScrollHorizontally();
final boolean canScrollVertical = mLayout.canScrollVertically();
if (canScrollHorizontal || canScrollVertical) {
scrollByInternal(canScrollHorizontal ? x : 0, canScrollVertical ? y : 0, null);
}
}
RecyclerView
boolean scrollByInternal(int x, int y, MotionEvent ev) {
int unconsumedX = 0, unconsumedY = 0;
int consumedX = 0, consumedY = 0;
consumePendingUpdateOperations();
if (mAdapter != null) {
eatRequestLayout();
onEnterLayoutOrScroll();
TraceCompat.beginSection(TRACE_SCROLL_TAG);
fillRemainingScrollValues(mState);
if (x != 0) {
consumedX = mLayout.scrollHorizontallyBy(x, mRecycler, mState);
unconsumedX = x - consumedX;
}
if (y != 0) {
consumedY = mLayout.scrollVerticallyBy(y, mRecycler, mState);
unconsumedY = y - consumedY;
}
TraceCompat.endSection();
repositionShadowingViews();
onExitLayoutOrScroll();
resumeRequestLayout(false);
}
if (!mItemDecorations.isEmpty()) {
invalidate();
}
if (dispatchNestedScroll(consumedX, consumedY, unconsumedX, unconsumedY, mScrollOffset,
TYPE_TOUCH)) {
// Update the last touch co-ords, taking any scroll offset into account
mLastTouchX -= mScrollOffset[0];
mLastTouchY -= mScrollOffset[1];
if (ev != null) {
ev.offsetLocation(mScrollOffset[0]