搜尋

首頁  >  問答  >  主體

android - 为什么SwipeRefreshLayout的setRefreshing()方法,只有在Handle中才能起作用?

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

private SwipeRefreshLayout mRefreshLayout;
mRefreshLayout.setRefreshing(true);

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

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

全部回覆(3)我來回復

  • 迷茫

    迷茫2017-04-17 17:17:46

    先轉載知乎一個答案,這裡解釋了為什麼在onCreate中調用setRefreshing無效:
    作者:小波
    連結:https://www.zhihu.com/question/35422150/answer/62784161
    來源:知乎歸作者所有。商業轉載請聯絡作者授權,非商業轉載請註明出處。

    
    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);
    }
    }); 
    

    既然是因為在我們呼叫setRefresh時view的初始化還未執行完畢,那麼最簡單的辦法就是用post加入隊列,隨便寫了個demo,上代碼:

    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();
        }
    }

    要注意的是,setRefreshing只是展示動畫,想要自動刷新必須手動調用onRefresh;手動調用onRefresh必須在post的runnable中,位於setRefreshing之後,否則若onRefresh中任務執行過快,就會出現無法取消refresh動畫的情況。

    回覆
    0
  • 高洛峰

    高洛峰2017-04-17 17:17:46

    應該和Activity的生命週期有關。放在Handler裡可以保證頁面初始化完了以後正確刷新。

    回覆
    0
  • 高洛峰

    高洛峰2017-04-17 17:17:46

    SwipeRefreshLayout在沒有完全載入之前,refresh是不起作用的,可以看一下原始碼。

    回覆
    0
  • 取消回覆