熟悉Android的朋友們都知道,不管是微博客戶端還是新聞客戶端,都離不開列表組件,可以說列表組件是Android數據展現方面最重要的組件,我們今天就要講一講列表組件ListView加載數據的相關內容。通常來說,一個應用在展現大量數據時,不會將全部的可用數據都呈現給用戶,因爲這不管對於服務端還是客戶端來說都是不小的壓力,因此,很多應用都是採用分批次加載的形式來獲取用戶所需的數據。比如:微博客戶端可能會在用戶滑動至列表底端時自動加載下一頁數據,也可能在底部放置一個“加載更多”按鈕,用戶點擊後,加載下一頁數據。
我們今天就結合實例來演示一下使用ListView獲取數據的過程。
新建一個loadmore項目,我們來看一下結構圖和最終效果圖:
左圖中包含了三個佈局文件、一個Adapter和一個Activity,右圖是我們運行後的主界面。
其中,main.xml是主界面的佈局文件,它包含一個ListView組件,代碼如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:paddingLeft="3dp"
- android:paddingRight="3dp">
- <ListView
- android:id="@id/android:list"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"/>
- </LinearLayout>
然後就是list_item.xml,它是ListView中單個列表項的佈局文件,從效果圖中可以看到,這裏只使用到了一個TextView組件,list_item.xml代碼如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <TextView
- android:id="@+id/list_item_text"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:gravity="center"
- android:textSize="20sp"
- android:paddingTop="10dp"
- android:paddingBottom="10dp"/>
- </LinearLayout>
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <Button
- android:id="@+id/loadMoreButton"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="load more"
- android:onClick="loadMore"/>
- </LinearLayout>
- package com.scott.loadmore;
- 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> items) {
- this.items = items;
- inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- }
- @Override
- public int getCount() {
- return items.size();
- }
- @Override
- public Object getItem(int position) {
- return items.get(position);
- }
- @Override
- public long getItemId(int position) {
- return position;
- }
- @Override
- public View getView(int position, View view, ViewGroup parent) {
- if (view == null) {
- view = inflater.inflate(R.layout.list_item, null);
- }
- TextView text = (TextView) view.findViewById(R.id.list_item_text);
- text.setText(items.get(position));
- return view;
- }
- /**
- * 添加列表項
- * @param item
- */
- public void addItem(String item) {
- items.add(item);
- }
- }
最後我們來看一下MainActivity:
- package com.scott.loadmore;
- import java.util.ArrayList;
- import android.app.ListActivity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.util.Log;
- import android.view.View;
- import android.widget.AbsListView;
- import android.widget.AbsListView.OnScrollListener;
- import android.widget.Button;
- import android.widget.ListView;
- public class MainActivity extends ListActivity implements OnScrollListener {
- private ListView listView;
- private int visibleLastIndex = 0; //最後的可視項索引
- private int visibleItemCount; // 當前窗口可見項總數
- private ListViewAdapter adapter;
- private View loadMoreView;
- private Button loadMoreButton;
- private Handler handler = new Handler();
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- loadMoreView = getLayoutInflater().inflate(R.layout.load_more, null);
- loadMoreButton = (Button) loadMoreView.findViewById(R.id.loadMoreButton);
- listView = getListView(); //獲取id是list的ListView
- listView.addFooterView(loadMoreView); //設置列表底部視圖
- initAdapter();
- setListAdapter(adapter); //自動爲id是list的ListView設置適配器
- listView.setOnScrollListener(this); //添加滑動監聽
- }
- /**
- * 初始化適配器
- */
- private void initAdapter() {
- ArrayList<String> items = new ArrayList<String>();
- for (int i = 0; i < 10; i++) {
- items.add(String.valueOf(i + 1));
- }
- adapter = new ListViewAdapter(this, items);
- }
- /**
- * 滑動時被調用
- */
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
- this.visibleItemCount = visibleItemCount;
- visibleLastIndex = firstVisibleItem + visibleItemCount - 1;
- }
- /**
- * 滑動狀態改變時被調用
- */
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- int itemsLastIndex = adapter.getCount() - 1; //數據集最後一項的索引
- int lastIndex = itemsLastIndex + 1; //加上底部的loadMoreView項
- if (scrollState == OnScrollListener.SCROLL_STATE_IDLE && visibleLastIndex == lastIndex) {
- //如果是自動加載,可以在這裏放置異步加載數據的代碼
- Log.i("LOADMORE", "loading...");
- }
- }
- /**
- * 點擊按鈕事件
- * @param view
- */
- public void loadMore(View view) {
- loadMoreButton.setText("loading..."); //設置按鈕文字loading
- handler.postDelayed(new Runnable() {
- @Override
- public void run() {
- loadData();
- adapter.notifyDataSetChanged(); //數據集變化後,通知adapter
- listView.setSelection(visibleLastIndex - visibleItemCount + 1); //設置選中項
- loadMoreButton.setText("load more"); //恢復按鈕文字
- }
- }, 2000);
- }
- /**
- * 模擬加載數據
- */
- private void loadData() {
- int count = adapter.getCount();
- for (int i = count; i < count + 10; i++) {
- adapter.addItem(String.valueOf(i + 1));
- }
- }
- }
我們來演示一下這個加載過程:
如圖,當點擊完按鈕後,出現加載動作,加載完之後如右圖所示,新數據緊接在原數據之後。然後我們滑動到底部,加載按鈕仍可工作:
最後,我們測試一下滑動列表到底部,然後鬆開,控制檯打印如下:
我們看到onScrollStateChanged方法裏的if語句裏代碼執行了,所以如果我們希望自動加載的話,可以把加載代碼放於此處。
今天先講到這裏,謝謝大家。