• Android Scrollview嵌套下listView动态加载数据,解决onScrollChanged执行多次数据重复问题


    这一篇博客和上一篇讲的都是listView的动态加载,但有所不同的是,本篇的listView是嵌套在ScrollView下的,有时候在一个Activity中可能分为好几个模块,由于展示的需要(手机屏幕大小有限),我们需要在这些模块的外层嵌套ScrollView,这时候我们就不能根据listView的状态来监听是否需要加载数据啦,但是转念一想,我们可以监听scrollview,但scrollview滑动到最底部时,那listview肯定也滑动到底部啦。思路确定啦,但是在开发的过程中发现了一个bug,listView有时候会加载重复的数据,搞的莫名其妙,后来经过查资料得知在ScrollView滑动中,onScrollChanged总是在不停被调用,导致多次向服务器端请求同样的数据,这时候就需要我们自己做并发控制

    ZdyListView

     1 package com.example.listview;
     2 
     3 import android.content.Context;
     4 import android.util.AttributeSet;
     5 import android.view.LayoutInflater;
     6 import android.view.View;
     7 import android.widget.ListView;
     8 import android.widget.ProgressBar;
     9 import android.widget.TextView;
    10 
    11 /**
    12  * Created by keranbin on 2015/10/25.
    13  */
    14 public class ZdyListView extends ListView {
    15     private Context context;
    16     private View footer;
    17     private ProgressBar progressBar; 
    18     private TextView tv;
    19 
    20     public ZdyListView(Context context) {
    21         super(context);
    22         init(context);
    23     }
    24     public ZdyListView(Context context, AttributeSet attrs) {
    25         super(context, attrs);
    26         init(context);
    27     }
    28     public ZdyListView(Context context, AttributeSet attrs, int defStyle) {
    29         super(context, attrs, defStyle);
    30         init(context);
    31     }
    32     private void init(Context context) {
    33         this.context=context;
    34         footer=LayoutInflater.from(context).inflate(R.layout.activity_footer, null);
    35         this.addFooterView(footer);
    36         progressBar=(ProgressBar) footer.findViewById(R.id.progressBar);
    37         tv=(TextView) footer.findViewById(R.id.tv);
    38         tv.setText("上拉加载更多");
    39     }
    40 
    41     //正在加载数据,将listview底部提示文字置为"正在加载中。。。。"
    42     public void onLoading(){
    43         progressBar.setVisibility(VISIBLE);
    44         tv.setText("正在加载中。。。。");
    45     }
    46 
    47     //加载完毕,将listView底部提示文字改为"上拉加载更多"
    48     public void LoadingComplete(){
    49         progressBar.setVisibility(GONE);
    50         tv.setText("上拉加载更多");
    51     }
    52 
    53     
    54     //重写onMeasure,解决scrollview与listview冲突
    55     @Override
    56     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    57         int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
    58                 MeasureSpec.AT_MOST);
    59         super.onMeasure(widthMeasureSpec, expandSpec);
    60     }
    61 
    62 
    63 
    64 }

    ZdyScrollView

     1 package com.example.listview;
     2 
     3 import android.content.Context;
     4 import android.util.AttributeSet;
     5 import android.view.View;
     6 import android.widget.ScrollView;
     7 
     8 public class ZdyScrollView extends ScrollView{
     9     private int flag=0;    //并发控制标志位
    10 
    11     private OnZdyScrollViewListener onZdyScrollViewListener;
    12 
    13     public ZdyScrollView(Context context) {
    14         super(context);
    15     }
    16 
    17     public ZdyScrollView(Context context, AttributeSet attrs) {
    18         super(context, attrs);
    19     }
    20 
    21     public ZdyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
    22         super(context, attrs, defStyleAttr);
    23     }
    24 
    25     //listview加载完毕,将并发控制符置为0
    26     public void loadingComponent(){
    27         flag=0;
    28     }
    29 
    30     @Override
    31     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    32         super.onScrollChanged(l, t, oldl, oldt);
    33         View view=this.getChildAt(0);
    34         //如果scrollview滑动到底部并且并发控制符为0,回调接口向服务器端请求数据
    35         if (this.getHeight() + this.getScrollY() == view.getHeight() && flag == 0) {
    36             flag = 1;//一进来就将并发控制符置为1,虽然onScrollChanged执行多次,但是由于并发控制符的值为1,不满足条件就不会执行到这
    37             onZdyScrollViewListener.ZdyScrollViewListener();
    38         }
    39     }
    40 
    41     public void setOnZdyScrollViewListener(OnZdyScrollViewListener onZdyScrollViewListener){
    42         this.onZdyScrollViewListener=onZdyScrollViewListener;
    43     }
    44 
    45     public interface OnZdyScrollViewListener{
    46         public void ZdyScrollViewListener();
    47     }
    48 
    49 }

    MainActivity

      1 package com.example.listview;
      2 
      3 import java.util.ArrayList;
      4 
      5 import com.example.listview.ZdyScrollView.OnZdyScrollViewListener;
      6 
      7 import android.app.Activity;
      8 import android.os.Bundle;
      9 import android.os.Handler;
     10 import android.os.Message;
     11 
     12 
     13 public class MainActivity extends Activity {
     14 
     15     private ZdyScrollView scrollView;
     16     private ZdyListView listView;
     17     private ListViewAdapter adapter;
     18     
     19     //一次从服务器端请求十条数据
     20     private int current=1;  
     21     private int number=9;
     22     
     23     ArrayList<String> listDatas;
     24 
     25     private Handler handler=new Handler(){
     26         public void handleMessage(Message msg) {
     27             setListView((ArrayList<String>)msg.obj);
     28         }
     29     };
     30 
     31 
     32     @Override
     33     protected void onCreate(Bundle savedInstanceState) {
     34         super.onCreate(savedInstanceState);
     35         setContentView(R.layout.activity_main);
     36         initView();
     37         initListener();
     38     }
     39 
     40     
     41     @Override
     42     protected void onStart() {
     43         super.onStart();
     44         //第一次请求数据
     45         getDataThread(current,number);
     46     }
     47     
     48     
     49 
     50     private void initView() {
     51         listView=(ZdyListView) this.findViewById(R.id.listView);
     52         scrollView=(ZdyScrollView) this.findViewById(R.id.scrollView);
     53 
     54     }
     55 
     56     private void initListener() {
     57         scrollView.setOnZdyScrollViewListener(new OnZdyScrollViewListener() {
     58             @Override
     59             public void ZdyScrollViewListener() {
     60                 //上拉加载更多数据
     61                 getDataThread(current,number);
     62             }
     63         });
     64 
     65     }
     66 
     67     
     68     private void setListView(ArrayList<String> datas) {
     69         if(listDatas==null){//第一次加载数据,为listview设置适配器
     70             listDatas=new ArrayList<String>();
     71             listDatas.addAll(datas);
     72             adapter=new ListViewAdapter(MainActivity.this,listDatas);
     73             listView.setAdapter(adapter);
     74             current=adapter.getCount()+1; //记录当前listview中的最后一个数据的下标
     75             listView.LoadingComplete();   //告诉listview已经加载完毕,重置提示文字
     76             scrollView.loadingComponent();//告示scrollview已经加载完毕,重置并发控制符的值
     77         }else{//下拉加载更多数据,只需要告诉adapter刷新就行
     78             listDatas.addAll(datas);
     79             adapter.notifyDataSetChanged();
     80             current=adapter.getCount()+1;
     81             listView.LoadingComplete();
     82             scrollView.loadingComponent();
     83         }
     84         
     85     };
     86     
     87     private void getDataThread(final int current, final int number){
     88         final Message msg=new Message();
     89         listView.onLoading();
     90         new Thread(){
     91             public void run() {
     92                 try {//模拟向服务器请求数据耗时
     93                     sleep(10000);
     94                 } catch (InterruptedException e) {
     95                     e.printStackTrace();
     96                 }
     97                 ArrayList<String> datas=ListViewDatas.returnNum(current, current+number);
     98                 if(datas!=null&&datas.size()>0){
     99                     msg.obj=datas;
    100                     handler.sendMessage(msg);
    101                 }
    102             };
    103         }.start();
    104     }
    105 
    106 }

    模拟服务器端发回数据ListViewDatas

     1 package com.example.listview;
     2 
     3 import java.util.ArrayList;
     4 
     5 public class ListViewDatas {
     6     //模拟服务器端数据库中的数据,假设现在只有3条数据
     7     public static int NUM=53;
     8     public static ArrayList<String> returnNum(int startNum,int endNum){
     9         ArrayList<String> list=new ArrayList<String>();
    10         if(endNum<=NUM){//客户端请求的数据在数据库数据范围之内
    11             for(int i=startNum;i<=endNum;i++){
    12                 list.add(String.valueOf(i));
    13             }
    14             return list;
    15         }else if(endNum>=NUM&&startNum<=NUM){//客户端请求的数据不全在数据库数据范围之内
    16             for(int i=startNum;i<=NUM;i++){
    17                 list.add(String.valueOf(i));
    18             }
    19             return list;            
    20         }else if(startNum>NUM){//客户端请求的数据超出数据库数据范围之内
    21             return null;
    22         }
    23         return null;
    24     }
    25 }

    页面布局activity_main.xml

     1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     android:layout_width="fill_parent"
     3     android:layout_height="fill_parent"
     4     android:orientation="vertical" >
     5 
     6     <com.example.listview.ZdyScrollView
     7         android:id="@+id/scrollView"
     8         android:layout_width="match_parent"
     9         android:layout_height="match_parent" >
    10 
    11         <com.example.listview.ZdyListView
    12             android:id="@+id/listView"
    13             android:layout_width="match_parent"
    14             android:layout_height="match_parent" >
    15         </com.example.listview.ZdyListView>
    16     </com.example.listview.ZdyScrollView>
    17 
    18 </LinearLayout>

    listView的footView  activity_footer.xml

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:orientation="vertical" >
     6 
     7     <LinearLayout
     8         android:id="@+id/load_layout"
     9         android:layout_width="match_parent"
    10         android:layout_height="wrap_content"
    11         android:gravity="center"
    12         android:orientation="horizontal"
    13         android:paddingBottom="10dip"
    14         android:paddingTop="10dip" >
    15 
    16         <ProgressBar
    17             style="?android:attr/progressBarStyleSmall"
    18             android:layout_width="wrap_content"
    19             android:layout_height="wrap_content"
    20             android:id="@+id/progressBar" 
    21             android:visibility="gone"/>
    22 
    23         <TextView
    24             android:layout_width="wrap_content"
    25             android:layout_height="wrap_content"
    26             android:text="正在加载..." 
    27             android:id="@+id/tv"/>
    28 
    29     </LinearLayout>
    30 
    31 </LinearLayout>
  • 相关阅读:
    数组作为函数参数传递时
    Tree 笨方法实现
    双向链表
    带头节点的循环链表及两个循环链表的合并
    josephus问题->不带头节点的循环链表
    数组形式链表
    检测qq是否在线
    Python-requests模块
    Python面向对象练习——基于面向对象设计一个对战游戏
    Python-面向对象
  • 原文地址:https://www.cnblogs.com/bdsdkrb/p/5070891.html
Copyright © 2020-2023  润新知