android - 为什么SwipeRefreshLayout的setRefreshing()方法,只有在Handle中才能起作用?
大家讲道理
大家讲道理 2017-04-17 17:15:46
0
3
644

比如我想用SwipeRefreshLayout在界面第一次加载进来时先自动刷新一次。

private SwipeRefreshLayout mRefreshLayout;
mRefreshLayout.setRefreshing(true);

这样不起作用,显示不出加载条。
但是交给handler就可以?

private SwipeRefreshLayout mRefreshLayout;
mHandler.post(new Runnable() {
    @Override
    public void run() {
        mRefreshLayout.setRefreshing(true);
    }
});
大家讲道理
大家讲道理

光阴似箭催人老,日月如移越少年。

reply all(3)
迷茫

First repost an answer from Zhihu, here explains why calling setRefreshing in onCreate is invalid:
Author: Xiaobo
Link: https://www.zhihu.com/question/35422150/answer/62784161
Source: Zhihu
Copyright All rights reserved to the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.


public void setRefreshing(boolean refreshing) {
if (refreshing && mRefreshing != refreshing) {
// scale and show
mRefreshing = refreshing;
int endTarget = 0;
if (!mUsingCustomStart) {
endTarget = (int) (mSpinnerFinalOffset + mOriginalOffsetTop);
} else {
endTarget = (int) mSpinnerFinalOffset;
}
setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop,
true /* requires update */);
mNotify = false;
startScaleUpAnimation(mRefreshListener);
} else {
setRefreshing(refreshing, false /* notify */);
}
} 
在onCreate里或onCreateView里调用setRefreshing,这个时候关键变量mOriginalOffsetTop并没有获取正确的值。下拉效果动画过程中没有显示到正确的坐标,我们看看这个值是什么时候获取的,上代码
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mTarget == null) {
ensureTarget();
}
if (mTarget == null) {
return;
}
mTarget.measure(MeasureSpec.makeMeasureSpec(
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));
mCircleView.measure(MeasureSpec.makeMeasureSpec(mCircleWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mCircleHeight, MeasureSpec.EXACTLY));
if (!mUsingCustomStart && !mOriginalOffsetCalculated) {
mOriginalOffsetCalculated = true;
mCurrentTargetOffsetTop = mOriginalOffsetTop = -mCircleView.getMeasuredHeight();
}

mCircleViewIndex = -1;
// Get the index of the circleview.
for (int index = 0; index < getChildCount(); index++) {
if (getChildAt(index) == mCircleView) {
mCircleViewIndex = index;
break;
}
}
} 
如代码所见,是在onMeasure里获取的,根据CircleView的高度来赋值的。

所以要解决的方法是让mOriginalOffsetTop能在setRefreshing前正确赋值。比较笨的方法是在onCreate里或onCreateView手动赋值,不推荐。
正确做法是在onMeasure触发后再调用setRefreshing。
代码如下:
root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
root.getViewTreeObserver().removeGlobalOnLayoutListener(this);
mRefreshLayout.setRefreshing(true);
loadData(true);
}
}); 

Since the initialization of the view has not been completed when we call setRefresh, the easiest way is to use post to join the queue, just write a demo, and the code is:

public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener{
    SwipeRefreshLayout refreshLayout;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh_layout);
        refreshLayout.setOnRefreshListener(this);
        refreshLayout.post(new Runnable() {
            @Override
            public void run() {
                refreshLayout.setRefreshing(true);
                onRefresh();
            }
        });
    }
    @Override
    public void onRefresh(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(3000);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        refreshLayout.setRefreshing(false);
                    }
                });
            }
        }).start();
    }
}

It should be noted that setRefreshing only displays animation. If you want to refresh automatically, you must manually call onRefresh; manually calling onRefresh must be in the runnable of the post, located after setRefreshing. Otherwise, if the task in onRefresh is executed too fast, the refresh animation cannot be canceled. situation.

小葫芦

It should be related to the life cycle of Activity. Placing it in the Handler can ensure that the page is refreshed correctly after initialization.

小葫芦

SwipeRefreshLayout refresh will not work before it is fully loaded. You can take a look at the source code.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template