首页 > 代码库 > Android UI组件----自定义ListView实现动态刷新

Android UI组件----自定义ListView实现动态刷新

【声明】

欢迎转载,但请保留文章原始出处→_→

生命壹号:http://www.cnblogs.com/smyhvae/

文章来源:http://www.cnblogs.com/smyhvae/p/3910541.html

联系方式:smyhvae@163.com 

 

【正文】

一、具体步骤:

(1)在activiy_main.xml中加一个ListView控件;再添加一个item的模板activity_main_item.xml,加一个底部加载的视图activity_main_load.xml;

(2)初始化item中的数据;

(3)自定义适配器BaseAdapter;

(4)ListiView绑定监听器OnScrollListener,并实现该监听器的两个方法:

    • public void onScrollStateChanged(AbsListView view, int scrollState)
    • public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount)

      注:如果屏幕滑到最下面了,并且scrollState的状态为:滚动完毕之后ListView处于停止状态(手离开屏幕),此时可以加载新数据了

(5)通过额外的线程,来模拟加载新数据;

(6)新数据加载完成后,通过handle通知主线程,将这个新数据显示在UI界面上(因为涉及到线程安全问题),此时要调用notifyDataSetChanged()方法来刷新。

       注:handler为线程之间通信的桥梁

 

二、代码实现: 

完整版代码如下:

activiy_main.xml代码如下:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2     xmlns:tools="http://schemas.android.com/tools" 3     android:layout_width="match_parent" 4     android:layout_height="match_parent" 5     tools:context=".MainActivity" > 6     <ListView 7         android:id="@+id/listView1" 8         android:layout_width="match_parent" 9         android:layout_height="match_parent" >10     </ListView>11 </LinearLayout>

注:为优化起见,第9行的代码一定要写成"match_parent",而不是“wrap_content”(解释略)

 

activity_main_item.xml代码如下:(作为一个item的模板)

 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     <TextView 7     android:id="@+id/textView1_title" 8     android:layout_width="match_parent" 9     android:layout_height="wrap_content"10     android:text="Large Text"11     android:textAppearance="?android:attr/textAppearanceLarge" />12     <TextView13         android:id="@+id/textView2_content"14         android:layout_width="match_parent"15         android:layout_height="wrap_content"16         android:text="TextView" />17 </LinearLayout>

 

activity_main_load.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="wrap_content" 5     android:orientation="horizontal" 6     android:gravity="center" > 7  8     <ProgressBar 9         android:id="@+id/progressBar1"10         android:layout_width="25dp"11         android:layout_height="25dp" />12 13     <TextView14         android:id="@+id/textView1"15         android:layout_width="wrap_content"16         android:layout_height="wrap_content"17         android:text="正在加载···" />18 19 </LinearLayout>

 

MainActivity.java代码如下:

  1 package com.smyhvae.smyh005listview5;  2   3 import java.util.Vector;  4   5 import android.app.Activity;  6 import android.os.Bundle;  7 import android.os.Handler;  8 import android.os.Message;  9 import android.view.Menu; 10 import android.view.View; 11 import android.view.ViewGroup; 12 import android.widget.AbsListView; 13 import android.widget.AbsListView.OnScrollListener; 14 import android.widget.BaseAdapter; 15 import android.widget.ListView; 16 import android.widget.TextView; 17  18 public class MainActivity extends Activity { 19  20     private ListView listView; 21     Vector<News> news = new Vector<News>(); 22     //private ArrayList<News> news = new ArrayList<News>();上面一行与这一行,二选一 23     MyAdapter myAdapter; 24      25     @Override 26     protected void onCreate(Bundle savedInstanceState) { 27         super.onCreate(savedInstanceState); 28         setContentView(R.layout.activity_main); 29         listView = (ListView)findViewById(R.id.listView1); 30          31         listView.setOnScrollListener(new ListViewListener());  //绑定监听器 32          33         //设置底部视图 34         View footer = getLayoutInflater().inflate(R.layout.activity_main_load, null); 35         listView.addFooterView(footer);         36          37 //        initData(); 38         new LoadDataThread().start();//加载数据的工作线程 39              40         myAdapter = new MyAdapter(); 41         listView.setAdapter(myAdapter); 42     } 43  44    //定义一个数据的类 45     class News { 46         String title; 47         String content; 48     } 49      50     int index = 1;//数据的记数器(索引) 51     //初始化数据 52     void initData(){         53         System.out.println("initData"); 54         for (int i = 0; i < 15; i++) { 55             News n = new News();  //这句话一定要放在循环的里面,否则每个item显示的内容都是一样的 56             n.title = "title-"+index; 57             n.content = "content"+index; 58             index++; 59             news.add(n);  //这一步很关键,我就是少了这一步,导致运行时,界面为空 60         } 61     } 62      63      64      65     //自定义适配器 66     class MyAdapter extends BaseAdapter{ 67  68         @Override 69         public int getCount() { 70             // TODO Auto-generated method stub 71             return news.size(); 72         } 73         public Object getItem(int position) { 74             return news.get(position); 75         } 76  77         @Override 78         public long getItemId(int position) { 79             return position; 80         } 81  82         @Override 83         public View getView(int position, View convertView, ViewGroup parent) { 84             ViewHolder viewHolder = new ViewHolder(); 85             //通过下面的条件判断语句,来循环利用。如果convertView = null ,表示屏幕上没有可以被重复利用的对象。 86             if(convertView==null){ 87                 //创建View 88                 convertView = getLayoutInflater().inflate(R.layout.activity_main_item, null); 89                 viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.textView1_title); 90                 viewHolder.tvContent = (TextView) convertView.findViewById(R.id.textView2_content); 91                 convertView.setTag(viewHolder); 92             }else{ 93                 viewHolder = (ViewHolder)convertView.getTag(); 94             } 95             //从Vector中取出数据填充到ListView列表项中 96             News n = news.get(position); 97             viewHolder.tvTitle.setText(n.title); 98             viewHolder.tvContent.setText(n.content); 99             return convertView;100         }101         102     }103 104     static class ViewHolder{105         TextView tvTitle;106         TextView tvContent;107     }    108 109     110 111     112     //实现ListView的监听器的接口113     int visibleLastIndex = 0; //最后一个显示的索引    114     public class ListViewListener implements OnScrollListener{        115         @Override116         public void onScrollStateChanged(AbsListView view, int scrollState) {117             //如果屏幕滑到最下面了,并且scrollState的状态为:滚动完毕之后ListView处于停止状态(手离开屏幕),118             if(visibleLastIndex==myAdapter.getCount() && scrollState==OnScrollListener.SCROLL_STATE_IDLE){119                 new LoadDataThread().start();//如果满足上面的条件,此时,可以加载新数据了120             }121         }122 123         @Override124         public void onScroll(AbsListView view, int firstVisibleItem,125             int visibleItemCount, int totalItemCount) {126             visibleLastIndex = firstVisibleItem+visibleItemCount-1;127             128         }129         130     }131     132     //额外开启一个线程,模拟加载数据133     class LoadDataThread extends Thread{134         @Override135         public void run() {136             initData();137             try {138                 Thread.sleep(2000);//休眠两秒139             } catch (InterruptedException e) {140                 // TODO Auto-generated catch block141                 e.printStackTrace();142             }143             144             //新数据加载完成后,通过handle通知主线程,将这个新数据显示在UI界面上(因为涉及到线程安全问题)145             handler.sendEmptyMessage(1);146         }147     }      148     149     //handler为线程之间通信的桥梁    150     private Handler handler = new Handler(){151         public void handleMessage(Message msg) {152             switch(msg.what){153             case 1:  //根据上面的提示,当Message为1,表示数据处理完了,可以通知主线程了154                  myAdapter.notifyDataSetChanged();        //这个方法一旦调用,UI界面就刷新了155                 break;156                 157             default :158                 break;159             }160         }161         162     };163     164     165     @Override166     public boolean onCreateOptionsMenu(Menu menu) {167         // Inflate the menu; this adds items to the action bar if it is present.168         getMenuInflater().inflate(R.menu.main, menu);169         return true;170     }171 172 173     174 }
  • 运行后,显示结果如下:

下图依次为:刚运行时、滑动到底部时、刷新之后的效果

 

三、总结:

监听事件处理的接口:OnScrollListener

实现接口的方法

listView注册滚动监听

Adapter中添加增加数据的函数

获得第2页以后的数据后,调用AdapterAdapter的刷新方法notifyDataSetChanged(),实现刷新。

具体的步骤如下:

(1)在activiy_main.xml中加一个ListView控件;再添加一个item的模板activity_main_item.xml,加一个底部加载的视图activity_main_load.xml

(2)初始化数据

(3)自定义适配器BaseAdapter

(4)ListiView绑定监听器OnScrollListener,并实现该监听器的两个方法:

  • public void onScrollStateChanged(AbsListView view, int scrollState)
  • public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount)

注:如果屏幕滑到最下面了,并且scrollState的状态为:如果屏幕滑到最下面了,并且scrollState的状态为:滚动完毕之后ListView处于停止状态(手离开屏幕),此时可以加载新数据了

(5)此时,通过额外的线程,来模拟加载新数据

(6)新数据加载完成后,通过handle通知主线程,将这个新数据显示在UI界面上(因为涉及到线程安全问题)。handler为线程之间通信的桥梁

【工程文件】

链接:http://pan.baidu.com/s/1kTwYcRX

密码:u691