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

ZdyListView

 package com.example.listview;

 import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView; /**
* Created by keranbin on 2015/10/25.
*/
public class ZdyListView extends ListView {
private Context context;
private View footer;
private ProgressBar progressBar;
private TextView tv; public ZdyListView(Context context) {
super(context);
init(context);
}
public ZdyListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ZdyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
this.context=context;
footer=LayoutInflater.from(context).inflate(R.layout.activity_footer, null);
this.addFooterView(footer);
progressBar=(ProgressBar) footer.findViewById(R.id.progressBar);
tv=(TextView) footer.findViewById(R.id.tv);
tv.setText("上拉加载更多");
} //正在加载数据,将listview底部提示文字置为"正在加载中。。。。"
public void onLoading(){
progressBar.setVisibility(VISIBLE);
tv.setText("正在加载中。。。。");
} //加载完毕,将listView底部提示文字改为"上拉加载更多"
public void LoadingComplete(){
progressBar.setVisibility(GONE);
tv.setText("上拉加载更多");
} //重写onMeasure,解决scrollview与listview冲突
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
} }

ZdyScrollView

 package com.example.listview;

 import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ScrollView; public class ZdyScrollView extends ScrollView{
private int flag=0; //并发控制标志位 private OnZdyScrollViewListener onZdyScrollViewListener; public ZdyScrollView(Context context) {
super(context);
} public ZdyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
} public ZdyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} //listview加载完毕,将并发控制符置为0
public void loadingComponent(){
flag=0;
} @Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
View view=this.getChildAt(0);
//如果scrollview滑动到底部并且并发控制符为0,回调接口向服务器端请求数据
if (this.getHeight() + this.getScrollY() == view.getHeight() && flag == 0) {
flag = 1;//一进来就将并发控制符置为1,虽然onScrollChanged执行多次,但是由于并发控制符的值为1,不满足条件就不会执行到这
onZdyScrollViewListener.ZdyScrollViewListener();
}
} public void setOnZdyScrollViewListener(OnZdyScrollViewListener onZdyScrollViewListener){
this.onZdyScrollViewListener=onZdyScrollViewListener;
} public interface OnZdyScrollViewListener{
public void ZdyScrollViewListener();
} }

MainActivity

 package com.example.listview;

 import java.util.ArrayList;

 import com.example.listview.ZdyScrollView.OnZdyScrollViewListener;

 import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message; public class MainActivity extends Activity { private ZdyScrollView scrollView;
private ZdyListView listView;
private ListViewAdapter adapter; //一次从服务器端请求十条数据
private int current=1;
private int number=9; ArrayList<String> listDatas; private Handler handler=new Handler(){
public void handleMessage(Message msg) {
setListView((ArrayList<String>)msg.obj);
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
} @Override
protected void onStart() {
super.onStart();
//第一次请求数据
getDataThread(current,number);
} private void initView() {
listView=(ZdyListView) this.findViewById(R.id.listView);
scrollView=(ZdyScrollView) this.findViewById(R.id.scrollView); } private void initListener() {
scrollView.setOnZdyScrollViewListener(new OnZdyScrollViewListener() {
@Override
public void ZdyScrollViewListener() {
//上拉加载更多数据
getDataThread(current,number);
}
}); } private void setListView(ArrayList<String> datas) {
if(listDatas==null){//第一次加载数据,为listview设置适配器
listDatas=new ArrayList<String>();
listDatas.addAll(datas);
adapter=new ListViewAdapter(MainActivity.this,listDatas);
listView.setAdapter(adapter);
current=adapter.getCount()+1; //记录当前listview中的最后一个数据的下标
listView.LoadingComplete(); //告诉listview已经加载完毕,重置提示文字
scrollView.loadingComponent();//告示scrollview已经加载完毕,重置并发控制符的值
}else{//下拉加载更多数据,只需要告诉adapter刷新就行
listDatas.addAll(datas);
adapter.notifyDataSetChanged();
current=adapter.getCount()+1;
listView.LoadingComplete();
scrollView.loadingComponent();
} }; private void getDataThread(final int current, final int number){
final Message msg=new Message();
listView.onLoading();
new Thread(){
public void run() {
try {//模拟向服务器请求数据耗时
sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ArrayList<String> datas=ListViewDatas.returnNum(current, current+number);
if(datas!=null&&datas.size()>0){
msg.obj=datas;
handler.sendMessage(msg);
}
};
}.start();
} }

模拟服务器端发回数据ListViewDatas

 package com.example.listview;

 import java.util.ArrayList;

 public class ListViewDatas {
//模拟服务器端数据库中的数据,假设现在只有3条数据
public static int NUM=53;
public static ArrayList<String> returnNum(int startNum,int endNum){
ArrayList<String> list=new ArrayList<String>();
if(endNum<=NUM){//客户端请求的数据在数据库数据范围之内
for(int i=startNum;i<=endNum;i++){
list.add(String.valueOf(i));
}
return list;
}else if(endNum>=NUM&&startNum<=NUM){//客户端请求的数据不全在数据库数据范围之内
for(int i=startNum;i<=NUM;i++){
list.add(String.valueOf(i));
}
return list;
}else if(startNum>NUM){//客户端请求的数据超出数据库数据范围之内
return null;
}
return null;
}
}

页面布局activity_main.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" > <com.example.listview.ZdyScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent" > <com.example.listview.ZdyListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</com.example.listview.ZdyListView>
</com.example.listview.ZdyScrollView> </LinearLayout>

listView的footView  activity_footer.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <LinearLayout
android:id="@+id/load_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:paddingBottom="10dip"
android:paddingTop="10dip" > <ProgressBar
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressBar"
android:visibility="gone"/> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在加载..."
android:id="@+id/tv"/> </LinearLayout> </LinearLayout>

Android Scrollview嵌套下listView动态加载数据,解决onScrollChanged执行多次数据重复问题的更多相关文章

  1. 携程Android App插件化和动态加载实践

    携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实 ...

  2. AppCan学习笔记----关闭页面listview动态加载数据

    AppCan页面关闭 AppCan 的页面是由两个HTML组成,如果要完全关闭的话需要在主HTML eg.index.html中关闭,关闭方法:appcan.window.close(-1); 管道 ...

  3. ie6,7下js动态加载图片不显示错误

    ie6,7下js动态加载图片不显示错误 先描述一下出现这种匪夷所思bug的背景: 我在页面加载的时候加载一堆小缩略图,<a href="javascript:void(0);" ...

  4. 分享个刚写好的 android 的 ListView 动态加载类,功能全而代码少。

    (转载声明出处:http://www.cnblogs.com/linguanh/) 简介:      该ListView 实现动态加载数据,为了方便用户充分地自定义自己的数据源.点击事件,等核心操作, ...

  5. Android中ListView动态加载数据

    1. 引言: 为了提高ListView的效率和应用程序的性能,在Android应用程序中不应该一次性加载ListView所要显示的全部信息,而是采取分批加载策略,随着用户的滑动,动态的从后台加载所需的 ...

  6. Android中插件开发篇之----动态加载Activity(免安装运行程序)

    一.前言 又到周末了,时间过的很快,今天我们来看一下Android中插件开发篇的最后一篇文章的内容:动态加载Activity(免安装运行程序),在上一篇文章中说道了,如何动态加载资源(应用换肤原理解析 ...

  7. android sax解析xml 文件 动态加载标题

    要解决一个问题 : 问题描述为 把标题动态的加载到 listView子布局中 我们首先通过 java程序写一个把标题写到xml文件的程序.这个程序会在以后讲解. 现在截图 已经写好的xm文件格式如下 ...

  8. Android 插件化方案(动态加载)总结

    1.作用 大多数Android开发人员开始接触这个问题是因为 App 爆棚了,方法数超过了一个 Dex 最大方法数 65535 的上限,因而便有了插件化的概念,将一个 App 划分为多个插件(Apk ...

  9. Android应用安全之外部动态加载DEX文件风险

    1. 外部动态加载DEX文件风险描述 Android 系统提供了一种类加载器DexClassLoader,其可以在运行时动态加载并解释执行包含在JAR或APK文件内的DEX文件.外部动态加载DEX文件 ...

随机推荐

  1. shell的使用技巧

    推荐使用的远程连接软件以及vi编辑器的基本使用 简介:远程连接软件 与 vi命令的基本使用 (1)软件: CRT 已经下载好的压缩包 直接双击 点击新建会话  点击下一步  输入主机名  下一步    ...

  2. TYVJ1071 LCIS 线性DP+决策集优化

    问题描述 TYVJ1071 题解 暴力\(\mathrm{DP}\) 首先,一个\(O(n^3)\)的解法: 设\(opt_{i,j}\)代表\(a\)的前\(i\)个和\(b\)的前\(j\)个的\ ...

  3. 判断所有的input框不能为空

    // 判断input框(除了类名为min1和max7)是否为空 function isEmpty(){ var flag=true; $("input[type='text']") ...

  4. [NOI2014]动物园(KMP,字符串)

    半年前看这题还感觉很神仙,做不动(没看题解). 现在过来看发现……这tm就是一个sb题…… 首先题面已经提示我们用 KMP 了.那 KMP 究竟能干啥呢? 看 $num$ 的定义.发现对于前缀 $i$ ...

  5. [LeetCode] 2. Add Two Numbers 两个数字相加

    You are given two non-empty linked lists representing two non-negative integers. The digits are stor ...

  6. 如何为python 2.7安装tensorflow?

    “TensorFlow在Windows上支持Python 3.5.x和3.6.x.” 因此,您无法在Windows上使用Python 2.7的tensorflow 如果您被迫使用Python 2.7, ...

  7. Failed to start LSB: Bring up/down networking 另外一个偏方

    之前网卡启动不了,会是配置不对,或者是移动了虚拟机导致hwaddr发生了变化. 但是今天没改动什么,突然用不了,一直报错Failed to start LSB: Bring up/down .... ...

  8. vs2019 更新之后无法用ctrl+d再设置回来..

    工具-选项-环境-键盘

  9. 基于JRebel开发的MybatisPlus热加载插件

    前言 前天项目中使用了mybatis-plus,但是搭配Jrebel开发项目时,发现修改mapper的xml,或者mapper方法中的注解,Jrebel并没有能够reload mapper.于是就有了 ...

  10. Postman界面了解

    Postman界面了解 2019年3月21日去面试了一家软件测试,本以为自己对简历上写的技能都熟悉,跳个槽,涨点工资,想象很美好,现实太残忍.当问到做接口测试postman和swagger工具的时候, ...