如何快速实现app网络加载中网络异常、空数据等页面?如何实现下拉刷新和加载更多等功能?

  • 在项目开发中如何快速处理网络加载中错误页面、空数据页面、网络异常等页面?
  • 在项目开发中如何快速实现“上拉刷新”与“加载更多”?
过去做法:
  • NetFragment 处理网络加载的页面
    • 采用“约定优于配置原则”,直接规定好错误页面、空数据页面、网络异常等页面的Id
    • NetFragment负责加载数据、控制错误页面、空数据页面、网络异常页面显示隐藏
  • ListNetFragment处理下拉刷新和加载更多的界面
    • 处理下拉刷新和加载更多的逻辑
    • 控制加载数据、控制错误页面、空数据页面、网络异常页面显示隐藏

存在的问题:
- 下拉刷新如果失败,listview上面的headView需要保留(不能实现)
- 下拉刷新加载过程中,上拉刷新出现崩溃Bug
- 控制逻辑C和页面展示V 没有真正分离,可扩展性差

现在做法:
  • 剥离网络加载控制逻辑
  • 从NetFragment中抽取NetController,处理网络加载控制逻辑
  • 从ListNetFragment中抽取ListNetController,处理下拉刷新和加载更多的逻辑

  • 重写NetFragment,实现NetController与各种页面的绑定

  • 重写ListNetFragment,实现ListNetController与各种页面的绑定

资源下载:
  • PandaAndroidLibs库
    https://github.com/tianci/panda.android
使用教程
1. NetFragment
  • 绘制Xml eg:fragment_exam


    //加载中   id为net_progress
    

        

        
    
    
    //数据为空的界面  id为net_no_result
    

    //数据错误  id为net_error
    
        
     //参数错误  id为net_fail
    
        

    

    //网络异常 id为net_cannot_access
    
        
    


     //有数据  id为net_result
    
        
    


  • 网络加载的Fragment继承NetFragment eg: ExamFragment
public class ExamFragment extends NetFragment {
    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;//网络请求的数据模型

     /**
     * 获取布局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;
    }

    /**
     * 网络请求
     */
    @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


    

        

    


  • 绘制异常界面的Xml 作为ListView的item eg:net_list_abnormal_layout



    

        

    

    

        
    

    

        
    

    
        
    



  • 继承ListNetFragment
public class TeacherFragment extends ListNetFragment {
    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;
    }
  // 获取网络异常 空数据 等界面布局
    @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);        //   设置每次加载个数  默认为10
        mNetController.addHeadView(headView);  //  添加头布局  没有可以不写
        mNetController.setListAdapter();       // 注: 在addHeadView(headView)之后,
      //  mNetController.setRefreshEnable(false); //能否下拉刷新  默认为true
      //  mNetController.setLoadMoreEnable(false);//能否加载更多  默认为true
        
        return rootView;
    }

    @Override
    protected ListNetResultInfo 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;
    }
}

你可能感兴趣的:(如何快速实现app网络加载中网络异常、空数据等页面?如何实现下拉刷新和加载更多等功能?)