这一篇博客和上一篇讲的都是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. 201871020225-牟星源《面向对象程序设计(java)》第十周学习总结

    201871020225-牟星源<面向对象程序设计(java)>第十周学习总结 博文正文开头: 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu- ...

  2. Zookeeper注册中心搭建-单机版(三)

    Zookeeper是一个分布式协调组件,本质是一个软件. Zookeeper常用的功能有: 发布订阅功能,把 zookeeper 当作注册中心的原因. 分布式/集群管理功能 Zookeeper是Jav ...

  3. flutter环境配置window10

    第一步,配置git环境,这个作为前端的都是会的,如果你不会,去问度娘去 第二步,配置java的开发环境,这里建议下载jdk为1.8版本的,我最初使用的是如下图的jdk版本,后面和flutter版本不一 ...

  4. b站滑动验证码图片的获取-python

    本文仅是获取验证码图片,python+selenium实现 图片的处理,算出偏移位置网上都有现成的:而由于b站的更新,图片的获取则与之前完全不同,不能直接从html中拿到 过程比较曲折所以记录一下,可 ...

  5. requests--重定向,序列化

    重定向 默认情况下,除了 HEAD, Requests 会自动处理所有重定向.可以使用响应对象的 history 方法来追踪重定向. Response.history 是一个 Response 对象的 ...

  6. java 随笔

    Spring的scope="prototype"属性 - 多例 spring 默认scope 是单例模式(singleton),这样只会创建一个Action对象,每次访问都是同一个 ...

  7. Web协议详解与抓包实战:HTTP1协议-内容协商是怎样进行的(8)

    一.内容协商的两种方式 每个 URI 指向的资源可以是任何事物,可以有多种不同的表述,例如一份文档可以有不同语言的翻译.不同的媒体格式.可以针对不同的浏览器提供不同的压缩编码等 二.Proactive ...

  8. markdown格式接口文档模板

    源文件 https://files.cnblogs.com/files/bincoding/%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A3.zip 目录 测试接口 查询指定项 ...

  9. vue学习面向对象,在项目中怎么用呢?

    面向对象感觉很牛逼,可是在项目中怎么用呢? 我至今见到的用法,写了一个用户对象. 效果:只要执行了new User(userInfo)就会在cookie,localStorage存放数据. 所以最简单 ...

  10. Ubuntu16 安装 wireshark

    添加源 sudo apt-add-repository ppa:wireshark-dev/stable 更新 sudo apt-get update 安装 sudo apt-get install ...