Android Scrollview嵌套下listView动态加载数据,解决onScrollChanged执行多次数据重复问题
这一篇博客和上一篇讲的都是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执行多次数据重复问题的更多相关文章
- 携程Android App插件化和动态加载实践
携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实 ...
- AppCan学习笔记----关闭页面listview动态加载数据
AppCan页面关闭 AppCan 的页面是由两个HTML组成,如果要完全关闭的话需要在主HTML eg.index.html中关闭,关闭方法:appcan.window.close(-1); 管道 ...
- ie6,7下js动态加载图片不显示错误
ie6,7下js动态加载图片不显示错误 先描述一下出现这种匪夷所思bug的背景: 我在页面加载的时候加载一堆小缩略图,<a href="javascript:void(0);" ...
- 分享个刚写好的 android 的 ListView 动态加载类,功能全而代码少。
(转载声明出处:http://www.cnblogs.com/linguanh/) 简介: 该ListView 实现动态加载数据,为了方便用户充分地自定义自己的数据源.点击事件,等核心操作, ...
- Android中ListView动态加载数据
1. 引言: 为了提高ListView的效率和应用程序的性能,在Android应用程序中不应该一次性加载ListView所要显示的全部信息,而是采取分批加载策略,随着用户的滑动,动态的从后台加载所需的 ...
- Android中插件开发篇之----动态加载Activity(免安装运行程序)
一.前言 又到周末了,时间过的很快,今天我们来看一下Android中插件开发篇的最后一篇文章的内容:动态加载Activity(免安装运行程序),在上一篇文章中说道了,如何动态加载资源(应用换肤原理解析 ...
- android sax解析xml 文件 动态加载标题
要解决一个问题 : 问题描述为 把标题动态的加载到 listView子布局中 我们首先通过 java程序写一个把标题写到xml文件的程序.这个程序会在以后讲解. 现在截图 已经写好的xm文件格式如下 ...
- Android 插件化方案(动态加载)总结
1.作用 大多数Android开发人员开始接触这个问题是因为 App 爆棚了,方法数超过了一个 Dex 最大方法数 65535 的上限,因而便有了插件化的概念,将一个 App 划分为多个插件(Apk ...
- Android应用安全之外部动态加载DEX文件风险
1. 外部动态加载DEX文件风险描述 Android 系统提供了一种类加载器DexClassLoader,其可以在运行时动态加载并解释执行包含在JAR或APK文件内的DEX文件.外部动态加载DEX文件 ...
随机推荐
- 青春正盛,未来可期。马上2020了,低成本投资自己:vip测试提升圈
应部分群友再三强烈建议要求,组建了一个测试提升小分队,相约vip测试提升圈, 这里汇集了一群热爱学习.渴望提升的测试小伙伴,大家都朝着自己的梦想拼命努力: 此圈将助你在接口自动化和性能方向全面提升,提 ...
- djang项目中的疑问及解决办法(ValueError: Invalid model reference 'apps.user.User'. String model references must be of the form 'app_label.ModelName'.)
这个问题其实就是apps.user.User这种用法是不对的,就在下面的模型中,我本来是绑定apps.user.User,但是试了一下,由于order和user是在同一个apps中,所以直接用user ...
- 使用Python获取图片的物理尺寸(KB)
如何获取图片的物理尺寸,而非(width, height)? #! -*- coding: utf-8 -*- import requests import io url = "https: ...
- Cookie 技术
Cookie 学习: 问题: HTTP 协议是没有记忆功能的,一次请求结束后,相关数据会被销毁.如果第二次的请求需要使用相同的请求数据怎么办呢?难道是让用户再次请求书写吗? 解决:使用 Cookie ...
- Spring Batch 跑批框架
SpringBatch的框架包括启动批处理作业的组件和存储Job执行产生的元数据. 如果作为一个批处理应用程序的开发人员,你暂时没有必要跟这些组件打交道, 因为它们主要为我们提供组件支持的角色,但是您 ...
- map、set 使用方法 | 1022 图书馆信息查询
看了答案才知道了这题的各种骚操作,然后敲了一顿骚键盘,然后wa.调了很久,才发现要规格化打印……mdzz…… 注:加粗代码为傻逼规格化打印代码: #include <stdio.h> #i ...
- CF1187D Subarray Sorting(神奇思路,线段树)
说实话,$2200$ 的题做不出来也有点丢脸了…… 当然要先判所有数出现次数相同. 首先区间排序就相当于交换相邻两个数,前面的数要大于后面的数才能交换. 然后就不会了…… 我们考虑 $b_1$ 到 $ ...
- 使用go-mysql-elasticsearch同步mysql数据库信息到ElasticSearch
本文介绍如何使用go-mysql-elasticsearch同步mysql数据库信息到ElasticSearch. 1.go-mysql-elasticsearch简介 go-mysql-elasti ...
- 解密httpclient,dbcp,jedis,c3p0,druid,okhttp都在使用的连接池技术
最近在连接池上面栽了个跟头(参见这里),引起我对池技术的强烈关注,这几天总结了一下很多场景都会使用的池技术: 池概念 pool,中文翻译为水池,但是在英文中,还有一种解释是 an organizati ...
- RabbitMQ操作代码封装
1.Message.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; u ...