ListView的分页加载问题

ListView的优化一直是Android中比较常见的问题,那么一些比较基本的ListView的优化还是应该要掌握的,其中就涉及到ListView的分页加载问题,主要是将数据一页一页的加载出来,提高流畅度,一般是一次加载10项,下面看看具体的代码。

xml的代码比较简单,就是在activity_main中显示一个listview

<?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" >

    <ListView
        android:id="@id/android:list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

 


显示ListView中item的内容list_item

<?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" >

    <TextView
        android:id="@+id/list_item_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:paddingBottom="10dp"
        android:paddingTop="10dp"
        android:textSize="20sp" />

</LinearLayout>

定义一个分页加载的Button load_more

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <Button
        android:id="@+id/loadMoreButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:onClick="loadMore"
        android:text="加载更多" />

</LinearLayout>


 


定义一个ListViewAdpater适配器继承BaseAdapter,需要重写里面的getCount(),getItem(),getItem(),getView()方法。此适配器需要一个Context对象来获取LayoutInflater实例和一个集合对象来充当适配器的数据集。

package com.example.mikasa_list;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class ListViewAdapter extends BaseAdapter{
	
	private List<String> items;
	private LayoutInflater inflater;
	
	public ListViewAdapter(Context context, List<String> list){
		items = list;
		inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return items.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return items.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		ViewHolder viewholder = null;
		if(convertView == null){
			convertView = inflater.inflate(R.layout.list_item, null);
			viewholder = new ViewHolder();
			viewholder.text = (TextView)convertView.findViewById(R.id.list_item_text);
			convertView.setTag(viewholder);
		}else{
			viewholder = (ViewHolder)convertView.getTag();
		}
		viewholder.text.setText(items.get(position));
		return convertView;
	}
	
	class ViewHolder{
		private TextView text;
	}

	public void additem(String item){
		items.add(item);
	}
}


可以看到在getView()方法中使用了对ListView的基本优化,如果convertView为空,则使用LayoutInflater的inflate方法去加载布局,如果不为空,则直接重用。同时增加了一个ViewHolder的内部类来对空间进行缓存,这样就不用每次都重新加载空间的实例,提高了ListView的运行效率。

主MainActivity也比较简单

package com.example.mikasa_list;

import java.util.ArrayList;
import java.util.List;

import android.app.ListActivity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ListActivity implements OnScrollListener {

	private ListView lv;
	private Button btn;
	private View loadMoreView; 
	private int visibleLastIndex = 0;
	private int visibleItemCount;
	private ListViewAdapter adapter;
	private Handler mhandler = new Handler();
    private Boolean islast = false;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		loadMoreView = getLayoutInflater().inflate(R.layout.load_more, null);
		btn = (Button)loadMoreView.findViewById(R.id.loadMoreButton);
		lv = getListView();
		lv.addFooterView(loadMoreView);
		intiadater();
		setListAdapter(adapter);
		lv.setOnScrollListener(this);
	}
	private void intiadater() {
		ArrayList<String> list = new ArrayList<String>();
		for(int i = 0; i < 10; i++){
			list.add(String.valueOf(i + 1));
		}
		adapter = new ListViewAdapter(this, list);
	}
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {

		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
	@Override
	public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount){
		//public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
		// TODO Auto-generated method stub	
		visibleLastIndex = firstVisibleItem;
		if(firstVisibleItem + visibleItemCount == totalItemCount){
			islast = true;
		}
	}
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		//public void onScrollStateChanged(AbsListView arg0, int arg1) {
		// TODO Auto-generated method stub
		int itemsLastIndex = adapter.getCount();
		int lastIndex = itemsLastIndex + 1 ;
		
		if(scrollState == OnScrollListener.SCROLL_STATE_IDLE && islast){
			Log.i("TAG", "loading...");
			loadData();
			Toast.makeText(this, "正在加载中...", Toast.LENGTH_SHORT).show();
			islast = false;
		}
	}

	public void loadMore(View view) {  
		btn.setText("加载中...");
		loadData();
	}
	private void loadData() {
		mhandler.postDelayed(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				int count = adapter.getCount();
				for(int i = count; i < count + 10; i++){
					adapter.additem(String.valueOf(i + 1));
				}
				adapter.notifyDataSetChanged();
				lv.setSelection(visibleLastIndex);
				btn.setText("加载更多...");
			}
		}, 2000);
		
	}
}

 

主要是设置ListView的监听事件ListView.setOnScrollListener(this);并重写onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)和onScrollStateChanged(AbsListView view, int scrollState)方法,注意到这里的几个参数。

firstVisibleItem表示当前能看到的第一个列表项id(从0开始,不完整的也算)

visibleItemCount表示当前页面能看到的列表总数(不完整的也算),即整个页面能显示多少个item

totalItemCount表示ListView的列表总数

scrollState表示正在滚动的回调次数,为0的时候表示没有滑动,为1的时候表示正在滑动,为2的时候表示手指离开屏幕

islast是判断是否在最后一行,初始值为false,注意加载的数据一般在异步完成。

 

还有几个问题是在滑动过程中,向上滑动有时也会自动加载,应该是要加判断是向上还是向下,还有一个是会连续加载两次,有时会因为firstVisibleItem和visibleItemCount的数值问题导致不能自动加载,猜想应该是因为在底部加了一个Button的原因,有待考证。希望能一起讨论

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值