ListView動態加載數據分頁(使用Handler+線程和AsyncTask兩種方法)


     在android開發中,經常需要使用數據分頁,比如要實現一個新聞列表的顯示,或者博文列表的顯示,不可能第一次加載就展示出全部,這就需要使用分頁的方法來加載數據,在android中Handler經常用來在耗時的工作中,它接收子線程發送的數據,並使用數據配合更新UI,AsyncTask是在一個線程中執行耗時操作然后把結果傳給UI線程,不需要你親自去管理線程和句柄。

一、使用Handler+線程方法

1、基礎知識

Handler在android系統中,主要負責發送和接收消息,它的用途主要有以下兩種:

(1)按照計划來處理一個消息(sendMessage(Message)方法)或者執行某個runnable實例(post(Runnable)方法)

(2)把其他的線程對象放入消息隊列中,避免線程沖突。

     消息的發送通過post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int),sendMessage(Message), sendMessageAtTime(Message, long)和 sendMessageDelayed(Message, long) 方法完成。對於postXXX方法通過Runnable對象給消息隊列,並在消息隊列到達后被調用。對於sendMessageXXX方法,則傳遞一個包含message對象,該對象可以被Handler類的handlerMessage(Message)方法處理。

2、主要代碼

  1 public class HandlerDemo extends Activity implements OnScrollListener {
  2 
  3     private ListView mListView;
  4     LinearLayout loadingLayout;
  5     private Thread mThread;
  6     private ListViewAdapter adapter;
  7 
  8     private int startIndex = 1;// 從第1條開始
  9     private int size = 10;// 每次下載十條數據
 10     private List<News> newsList;
 11     List<Map<String, String>> data ;
 12 
 13     /*
 14      * 設置布局顯示屬性
 15      */
 16     private LayoutParams mLayoutParams = new LayoutParams(
 17             LinearLayout.LayoutParams.WRAP_CONTENT,
 18             LinearLayout.LayoutParams.WRAP_CONTENT);
 19 
 20     private LayoutParams ffLayoutParams = new LayoutParams(
 21             LinearLayout.LayoutParams.FILL_PARENT,
 22             LinearLayout.LayoutParams.FILL_PARENT);
 23 
 24     private ProgressBar progressBar;
 25 
 26     @Override
 27     protected void onCreate(Bundle savedInstanceState) {
 28         // TODO Auto-generated method stub
 29         super.onCreate(savedInstanceState);
 30         setContentView(R.layout.news_main);
 31         data=new ArrayList<Map<String, String>>();
 32         addView();
 33     }
 34 
 35     private void addView() {
 36         if (startIndex == 1) {
 37             newsList = new ArrayList<News>();
 38             newsList = getNewsList();
 39         }
 40         getdata(newsList);
 41         LinearLayout layout = new LinearLayout(this);
 42         layout.setOrientation(LinearLayout.HORIZONTAL);
 43         progressBar = new ProgressBar(this);
 44         layout.addView(progressBar, mLayoutParams);
 45         TextView textView = new TextView(this);
 46         textView.setText("加載中...");
 47         textView.setGravity(Gravity.CENTER_VERTICAL);
 48         layout.addView(textView, ffLayoutParams);
 49         layout.setGravity(Gravity.CENTER);
 50         loadingLayout = new LinearLayout(this);
 51         loadingLayout.addView(layout, mLayoutParams);
 52         loadingLayout.setGravity(Gravity.CENTER);
 53 
 54         // 得到一個ListView用來顯示條目
 55         mListView = (ListView) findViewById(R.id.listView);
 56         mListView.addFooterView(loadingLayout);
 57         adapter = new ListViewAdapter();
 58         mListView.setAdapter(adapter);
 59         mListView.setOnScrollListener(this);
 60         mListView.setTextFilterEnabled(true);
 61     }
 62 
 63     @Override
 64     public void onScroll(AbsListView view, int firstVisibleItem,
 65             int visibleItemCount, int totalItemCount) {
 66         // TODO Auto-generated method stub
 67         if (firstVisibleItem + visibleItemCount == totalItemCount) {
 68             if (mThread == null || !mThread.isAlive()) {
 69                 mThread = new Thread() {
 70 
 71                     @Override
 72                     public void run() {
 73                         newsList = new ArrayList<News>();
 74                         newsList = getNewsList();
 75                         getdata(newsList);
 76                         Message msg = new Message();
 77                         msg.what = 1;
 78                         handler.sendMessage(msg);
 79                     }
 80                 };
 81                 mThread.run();
 82             }
 83         }
 84     }
 85     
 86     Handler handler = new Handler() {
 87 
 88         @Override
 89         public void handleMessage(Message msg) {
 90             // TODO Auto-generated method stub
 91             if (msg.what == 1) {
 92                 startIndex = startIndex + size;
 93                 Log.v("startindex", startIndex + "");
 94                 mListView.removeFooterView(loadingLayout);
 95                 mThread.stop();
 96                 adapter.count += size;
 97                 adapter.notifyDataSetChanged();
 98                 return;
 99             }
100         }
101     };
102 
103     class ListViewAdapter extends BaseAdapter {
104         int count = 10;
105 
106         @Override
107         public int getCount() {
108             // TODO Auto-generated method stub
109             return count;
110         }
111 
112         @Override
113         public Object getItem(int position) {
114             // TODO Auto-generated method stub
115             return position;
116         }
117 
118         @Override
119         public long getItemId(int position) {
120             // TODO Auto-generated method stub
121             return position;
122         }
123         
124         @Override
125         public View getView(int position, View convertView, ViewGroup parent) {
126             // TODO Auto-generated method stub
127             convertView = LayoutInflater.from(getApplicationContext()).inflate(
128                     R.layout.news_item, null);
129             TextView textView = (TextView) convertView
130                     .findViewById(R.id.textNewsTitle);
131             textView.setText((data.get(position)).get("title"));
132             return convertView;
133         }
134     }
135 
136     @Override
137     public void onScrollStateChanged(AbsListView view, int scrollState) {
138         // TODO Auto-generated method stub
139 
140     }
141 
142     private List<Map<String, String>> getdata(List<News> list) {
143 
144         if (list == null)
145             return null;
146         for (News news : list) {
147             Map<String, String> map = new HashMap<String, String>();
148             map.put("title", news.getTitle());
149             data.add(map);
150         }
151         return data;
152     }
153 
154     /*
155      * 獲取網絡數據 注:我是訪問本機的一個新聞服務,使用asp.net技術來實現的
156      * 這個是項目是一個基於android的資訊播報軟件
157      */
158     private List<News> getNewsList() {
159         String path = "http://10.0.2.2/getNewsList.aspx";
160         String xmlStr = "<?xml version='1.0' encoding='utf-8'?><source><categoryIds>1,3,7</categoryIds><startIndex>"
161                 + startIndex
162                 + "</startIndex><detail>2</detail><count>"
163                 + size
164                 + "</count></source>";
165         NewsConnector newsConnector = new NewsConnector();
166         List<News> list = new ArrayList<News>();
167         list = newsConnector.getNewsList(path, xmlStr);
168         return list;
169     }
170 }

3、小結

ListView使用Handler+線程方式來動態加載數據的步驟如下:

1.先初始化頁面(如:加載第一頁數據)

2.在接收某個事件的消息之后(以上代碼是onScroll事件),啟動線程(線程完成下載數據,並發送消息給handler)

3.handler接收到消息后更新界面,顯示數據。

 

二、使用AsyncTask方法

1、基礎知識

AsyncTask也是android提供的一個為了不能阻塞主線程的一個類,AsyncTask定義了三種泛型類型Params、Progress和Result,Params啟動任務執行輸入參數,比如http請求的url和參數,Progress后台執行任務的百分比,后台執行最終返回的結果。

AsyncTask的執行分為四個步驟,每一步都對應都對應一個回調方法,開發者需要實現一個或者幾個方法,在任務的執行過程中,這些方法會自動調用。

onPreExecute(),在執行后台耗時操作前被調用,可以在執行此方法中做一些ui操作,比如顯示一個進度條等
doInBackground(Params...),這個方法在執行onPreExecute()后執行,這個方法完成耗時工作,比如下載等。
onProgressUpdate(Progress...),UI線程通過此方法獲取任務的完成的情況,比如完成的任務的百分比。
onPostExecute(Result),這個方法在耗時工作完成后被調用。UI線程調用此方法獲取結果。

注意:在使用AsyncTask類,有幾條准則需要遵守

(1)、Task的實例必須在UI線程中創建

(2)、execute方法必須在UI線程中調用

(3)、不要手動調用以上四個方法

(4)、這個任務只執行一次(如果執行第二次將會拋出異常)

2、主要代碼

 

 1 @Override
 2     public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
 3         // TODO Auto-generated method stub
 4         if(arg1+arg2==arg3)
 5         {
 6             if(!isloading)
 7             {
 8                 new myAsyncTask().execute(null);
 9             }
10             else
11             {
12                 mListView.removeFooterView(loadingLayout);
13             }
14         }
15     }
16 
17     @Override
18     public void onScrollStateChanged(AbsListView arg0, int arg1) {
19         // TODO Auto-generated method stub
20         
21     }
22     
23     private class myAsyncTask extends AsyncTask<Void, Void, Void>
24     {
25 
26         @Override
27         protected Void doInBackground(Void... params) {
28             // TODO Auto-generated method stub
29             
30             newsList = new ArrayList<News>();
31             newsList = getNewsList();
32             getdata(newsList);
33             return null;
34             
35         }
36 
37         @Override
38         protected void onPostExecute(Void result) {
39             // TODO Auto-generated method stub
40             super.onPostExecute(result);
41             adapter.count+=size;
42             adapter.notifyDataSetChanged();
43             startIndex+=size;
44             isloading=false;
45         }
46 
47         @Override
48         protected void onPreExecute() {
49             // TODO Auto-generated method stub
50             super.onPreExecute();
51             isloading=true;
52         }
53         
54     }

注:以上僅是和使用Handler+線程方法不同的代碼,建議下載源碼,了解詳細代碼

3、小結

ListView使用AsyncTask方法動態加載數據的方法如下:

1.和handler一樣初始化頁面(如:加載第一頁)

2.在接收某個事件的消息之后(以上代碼是onScroll事件),創建一個新的異步任務,並開始執行

3.耗時工作完成后,開始更新UI

 

三、總結

使用Handler+線程和使用AsyncTask方法進行ListView動態加載的比較

   Handler+線程方式:

在使用Handler方式時,它涉及Handler、Thread、Message、Looper四個對象,在執行的流程如下:主線程啟動一個Thread,這個Thread執行耗時操作,耗時操作完成后,生成一個Message,Looper讀取Message並傳遞給Hander,Handler接收Message並更新響應的UI。因為Looper在一個message處理完,才會讀下一條,如果發生多個Message就會形成一個消息隊列,所以它對多個后台操作比較清晰,明朗。但對於單個message來講顯得代碼比較多,過於復雜。

  AsyncTask方式:

AsyncTask繼承自Object,是android提供的輕量級的異步類。並提供了一個方法來獲取任務的執行進度(可以根據它來更新UI),最后會把結果返回在主線程。這個方式的比較簡單,而且可以清楚的看到耗時任務執行的進度。但是對於多個異步操作同時進行,並更新UI變得比較復雜。

 
附件上截圖

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM