如何快速實現(xiàn)app網(wǎng)絡(luò)加載中網(wǎng)絡(luò)異常、空數(shù)據(jù)等頁面?如何實現(xiàn)下拉刷新和加載更多等功能弦聂?

  • 在項目開發(fā)中如何快速處理網(wǎng)絡(luò)加載中錯誤頁面、空數(shù)據(jù)頁面捺檬、網(wǎng)絡(luò)異常等頁面蒿秦?
  • 在項目開發(fā)中如何快速實現(xiàn)“上拉刷新”與“加載更多”职车?
過去做法:
  • NetFragment 處理網(wǎng)絡(luò)加載的頁面
    • 采用“約定優(yōu)于配置原則”,直接規(guī)定好錯誤頁面、空數(shù)據(jù)頁面茫孔、網(wǎng)絡(luò)異常等頁面的Id
    • NetFragment負(fù)責(zé)加載數(shù)據(jù)、控制錯誤頁面锣咒、空數(shù)據(jù)頁面、網(wǎng)絡(luò)異常頁面顯示隱藏
  • ListNetFragment處理下拉刷新和加載更多的界面
    • 處理下拉刷新和加載更多的邏輯
    • 控制加載數(shù)據(jù)、控制錯誤頁面戏蔑、空數(shù)據(jù)頁面、網(wǎng)絡(luò)異常頁面顯示隱藏

存在的問題:
- 下拉刷新如果失敗候味,listview上面的headView需要保留(不能實現(xiàn))
- 下拉刷新加載過程中,上拉刷新出現(xiàn)崩潰Bug
- 控制邏輯C和頁面展示V 沒有真正分離,可擴展性差

現(xiàn)在做法:
  • 剝離網(wǎng)絡(luò)加載控制邏輯
  • 從NetFragment中抽取NetController粱玲,處理網(wǎng)絡(luò)加載控制邏輯
  • 從ListNetFragment中抽取ListNetController卵沉,處理下拉刷新和加載更多的邏輯

  • 重寫NetFragment史汗,實現(xiàn)NetController與各種頁面的綁定

  • 重寫ListNetFragment瓷蛙,實現(xiàn)ListNetController與各種頁面的綁定

資源下載:
使用教程
1. NetFragment
  • 繪制Xml eg:fragment_exam
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/net_refresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    //加載中   id為net_progress
    <LinearLayout
        android:id="@+id/net_progress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:orientation="vertical">

        <ProgressBar
            style="?android:attr/progressBarStyle"
            android:layout_width="200dip"
            android:layout_height="wrap_content"
            android:indeterminate="true"
            android:indeterminateOnly="true" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="數(shù)據(jù)正在加載中……"
            android:textColor="#000000" />
    </LinearLayout>
    
    //數(shù)據(jù)為空的界面  id為net_no_result
    <TextView
        android:id="@+id/net_no_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="數(shù)據(jù)為空"
        android:textColor="#000000" />

    //數(shù)據(jù)錯誤  id為net_error
    <TextView
        android:id="@+id/net_error"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="數(shù)據(jù)出錯"
        android:textColor="#000000" />
        
     //參數(shù)錯誤  id為net_fail
    <LinearLayout
        android:orientation="vertical"
        android:id="@+id/net_fail"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <include  layout="@layout/nonata_2"/>

    </LinearLayout>

    //網(wǎng)絡(luò)異常 id為net_cannot_access
    <LinearLayout
        android:orientation="vertical"
        android:id="@+id/net_cannot_access"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <include  layout="@layout/nonata_2"/>
    </LinearLayout>


     //有數(shù)據(jù)  id為net_result
    <LinearLayout
        android:orientation="vertical"
        android:id="@+id/net_result"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <include  layout="@layout/nonata_2"/>
    </LinearLayout>

</FrameLayout>
  • 網(wǎng)絡(luò)加載的Fragment繼承NetFragment eg: ExamFragment
public class ExamFragment extends NetFragment<GetSelfOfficialExamNameNetResultInfo> {
    private static final String TAG = ExamFragment.class.getSimpleName();
    @Bind(B.id.nav_go_back)
    ImageView navGoBack;
    @Bind(B.id.nav_tv_title)
    TextView navTvTitle;
    @Bind(B.id.nav_tv_right)
    TextView navTvRight;
    @Bind(B.id.tv_exam_choose_1)
    TextView tvExamChoose1;
    @Bind(B.id.tv_exam_choose_2)
    TextView tvExamChoose2;
    @Bind(B.id.ll_item_0)
    LinearLayout llItem0;
    @Bind(B.id.ll_item_1)
    LinearLayout llItem1;
    @Bind(B.id.tv_item_0_name)
    TextView tvItem0Name;
    @Bind(B.id.tv_item_1_name)
    TextView tvItem1Name;
    private GetSelfOfficialExamNameNetResultInfo resultInfo;//網(wǎng)絡(luò)請求的數(shù)據(jù)模型

     /**
     * 獲取布局Id
     */
    @Override
    public int getLayoutId() {
        return R.layout.fragment_exam;
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = super.onCreateView(inflater, container, savedInstanceState);
        navGoBack.setVisibility(View.INVISIBLE);
        navTvTitle.setText("考點兒");
        navTvRight.setText("考試管理");
        return rootView;
    }

    /**
     * 網(wǎng)絡(luò)請求
     */
    @Override
    public GetSelfOfficialExamNameNetResultInfo onDoInBackgroundSafely() {
        GetSelfOfficialExamNameNetResultInfo.Request params = new GetSelfOfficialExamNameNetResultInfo.Request();
        return RepositoryCollection.getSelfOfficialExamName(params);
    }

    /**
     *  請求成功時 
     */
    @Override
    protected void onDisplayResult(GetSelfOfficialExamNameNetResultInfo resultInfo) {
        this.resultInfo = resultInfo;
        tvItem0Name.setText(resultInfo.getSelfExamName());
        tvItem1Name.setText(resultInfo.getOfficialExamName());
    }

}

2 ListNetFragment 的使用
  • 繪制XML eg: fragment_teacher
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/net_result"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">

        <ListView
            android:id="@+id/net_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginLeft="@dimen/width_720_1280_20"
            android:layout_marginRight="@dimen/width_720_1280_20"
            android:background="@color/bg_window"
            android:clipToPadding="false"
            android:divider="@color/color_underline"
            android:dividerHeight="@dimen/hs1" />

    </android.support.v4.widget.SwipeRefreshLayout>

</FrameLayout>
  • 繪制異常界面的Xml 作為ListView的item eg:net_list_abnormal_layout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/net_no_result"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="@dimen/hs200">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:clickable="false"
            android:gravity="center"
            android:text="@string/net_no_result"
            android:textColor="#000000" />

    </LinearLayout>

    <LinearLayout
        android:id="@+id/net_error"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="@dimen/hs200">

        <include layout="@layout/nonata_2" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/net_fail"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        ndroid:orientation="vertical"
        android:paddingTop="@dimen/hs200">

        <include layout="@layout/nonata_2" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/net_cannot_access"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="@dimen/hs200">
        <include layout="@layout/nonata_2" />
    </LinearLayout>

</FrameLayout>

  • 繼承ListNetFragment
public class TeacherFragment extends ListNetFragment<AppArticleModel> {
    private static final String TAG = TeacherFragment.class.getSimpleName();
    @Bind(B.id.nav_go_back)
    ImageView navGoBack;
    @Bind(B.id.nav_tv_title)
    TextView navTvTitle;
    @Bind(B.id.iv_teacher_photo)
    ImageView ivTeacherPhoto;
    @Bind(B.id.tv_teacher_name_1)
    TextView tvTeacherName1;
    @Bind(B.id.tv_teacher_name_2)
    TextView tvTeacherName2;
    @Bind(B.id.tv_teacher_name_3)
    TextView tvTeacherName3;
    @Bind(B.id.ll_log_status)
    LinearLayout llLogStatus;
    private int teacherId;
    private DisplayImageOptions options;

    private AppTeacherModel teacherModel;

    @Override
    public int getLayoutId() {
        return R.layout.fragment_teacher;
    }
  // 獲取網(wǎng)絡(luò)異常 空數(shù)據(jù) 等界面布局
    @Override
    public int getAbnormalViewLayoutId() {
        return R.layout.net_list_abnormal_layout;
    }

  
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = super.onCreateView(inflater, container, savedInstanceState);

      //  mNetController.setPageSize(20);        //   設(shè)置每次加載個數(shù)  默認(rèn)為10
        mNetController.addHeadView(headView);  //  添加頭布局  沒有可以不寫
        mNetController.setListAdapter();       // 注: 在addHeadView(headView)之后箩兽,
      //  mNetController.setRefreshEnable(false); //能否下拉刷新  默認(rèn)為true
      //  mNetController.setLoadMoreEnable(false);//能否加載更多  默認(rèn)為true
        
        return rootView;
    }

    @Override
    protected ListNetResultInfo<AppArticleModel> onDoInBackgroundSafely(int i, int i1) {
        GetTeacherInfoNetResultInfo.Request params = new GetTeacherInfoNetResultInfo.Request();
        PageModel pageModel = new PageModel();
        pageModel.setStartIndex(i);
        pageModel.setPageSize(i1);
        params.setPage(pageModel);
        params.setTeacherId(teacherId);
        return RepositoryCollection.getTeacherInfo(params);
    }

  // list item任意一TextView的Id
  
    @Override
    public int getItemTextViewResourceId() {
        return R.id.tv_content;
    }

  //list item的布局
    @Override
    public int getItemLayoutId() {
        return R.layout.item_list_teacher;
    }

    //用于 處理list的item
    @Override
     public View bindView(int i, View view, ViewGroup viewGroup) {
         ViewHolder holder;
         if (view == null) {
             view = View.inflate(getContext(), R.layout.item_list_teacher, null);
         }
         holder = (ViewHolder) view.getTag();
         if (holder == null) {
             holder = new ViewHolder(view);
             view.setTag(holder);
         }
         final AppArticleModel model = getItem(i);
         
         holder.tvContent.setText(model.getTitle());
         String shareTime = TimeUtil.longToString(model.getCreateDate(), TimeUtil.FORMAT_DATE);
         holder.tvShareTime.setText(shareTime);
         holder.tvPreview.setText("" + model.getViewNum());
        
         return view;
     }
 
     class ViewHolder {
         @Bind(B.id.tv_title)
         TextView tvTitle;
         @Bind(B.id.tv_content)
         TextView tvContent;
         @Bind(B.id.tv_share_time)
         TextView tvShareTime;
         @Bind(B.id.tv_preview)
         TextView tvPreview;
         @Bind(B.id.tv_item_teacher_zambia)
         TextView tvItemTeacherZambia;
         @Bind(B.id.ll_item)
         LinearLayout ll_item;
 
         ViewHolder(View view) {
             ButterFork.bind(this, view);
         }
     }

}
解決SwipeRefreshLayout與ViewPager 的滑動沖突

通過重寫SwipeRefreshLayout的onInterceptTouchEvent方法

public class BannerSwipeRefreshLayout extends SwipeRefreshLayout {
    public BannerSwipeRefreshLayout(Context context) {
        super(context);
    }

    public BannerSwipeRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    float lastx = 0;
    float lasty = 0;
    boolean ismovepic = false;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            lastx = ev.getX();
            lasty = ev.getY();
            ismovepic = false;
            return super.onInterceptTouchEvent(ev);
        }

        final int action = MotionEventCompat.getActionMasked(ev);

        int x2 = (int) Math.abs(ev.getX() - lastx);
        int y2 = (int) Math.abs(ev.getY() - lasty);

        //滑動圖片最小距離檢查
        if (x2 > y2) {
            if (x2 >= 100) ismovepic = true;
            return false;
        }

        //是否移動圖片(下拉刷新不處理)
        if (ismovepic) {
            return false;
        }
        boolean isok = super.onInterceptTouchEvent(ev);

        return isok;
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嘹害,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖檀蹋,帶你破解...
    沈念sama閱讀 223,002評論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評論 3 400
  • 文/潘曉璐 我一進店門耀盗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舌厨,“玉大人躏哩,你說我怎么就攤上這事。” “怎么了姑曙?”我有些...
    開封第一講書人閱讀 169,787評論 0 365
  • 文/不壞的土叔 我叫張陵提完,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么鉴嗤? 我笑而不...
    開封第一講書人閱讀 60,237評論 1 300
  • 正文 為了忘掉前任垄琐,我火速辦了婚禮,結(jié)果婚禮上介杆,老公的妹妹穿的比我還像新娘。我一直安慰自己褒脯,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,237評論 6 398
  • 文/花漫 我一把揭開白布践啄。 她就那樣靜靜地躺著,像睡著了一般伐谈。 火紅的嫁衣襯著肌膚如雪窜护。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,821評論 1 314
  • 那天滨溉,我揣著相機與錄音栋操,去河邊找鬼和媳。 笑死,一個胖子當(dāng)著我的面吹牛哈街,可吹牛的內(nèi)容都是我干的留瞳。 我是一名探鬼主播,決...
    沈念sama閱讀 41,236評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼骚秦,長吁一口氣:“原來是場噩夢啊……” “哼她倘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起作箍,我...
    開封第一講書人閱讀 40,196評論 0 277
  • 序言:老撾萬榮一對情侶失蹤硬梁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后胞得,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荧止,經(jīng)...
    沈念sama閱讀 46,716評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,794評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了跃巡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片危号。...
    茶點故事閱讀 40,928評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖素邪,靈堂內(nèi)的尸體忽然破棺而出外莲,到底是詐尸還是另有隱情,我是刑警寧澤兔朦,帶...
    沈念sama閱讀 36,583評論 5 351
  • 正文 年R本政府宣布偷线,位于F島的核電站,受9級特大地震影響烘绽,放射性物質(zhì)發(fā)生泄漏淋昭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,264評論 3 336
  • 文/蒙蒙 一安接、第九天 我趴在偏房一處隱蔽的房頂上張望翔忽。 院中可真熱鬧,春花似錦盏檐、人聲如沸歇式。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽材失。三九已至,卻和暖如春硫豆,著一層夾襖步出監(jiān)牢的瞬間龙巨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評論 1 274
  • 我被黑心中介騙來泰國打工熊响, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留旨别,地道東北人。 一個月前我還...
    沈念sama閱讀 49,378評論 3 379
  • 正文 我出身青樓汗茄,卻偏偏與公主長得像秸弛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子洪碳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,937評論 2 361

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,341評論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫递览、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,126評論 4 61
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點贊按鈕進度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 46,795評論 22 665
  • 1瞳腌、網(wǎng)絡(luò)溝通6人 2绞铃、產(chǎn)品咨詢2人 個人體會 大家對微量元素里鋅有了解過嗎?今天給大家分享一下缺鋅給我?guī)淼?..
    葆嬰USANA廖瑜閱讀 59評論 0 0
  • ?— 01 — 我覺得這個世界上對姑娘們最不公平的一句話就是:干得好不如嫁得好嫂侍!雖然我也很認(rèn)同婚姻這件事情對一個姑...
    夕言細(xì)語閱讀 799評論 2 15