2025-05-25

在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、主要代碼
public class HandlerDemo extends Activity implements OnScrollListener {
 
    private ListView mListView;
    LinearLayout loadingLayout;
    private Thread mThread;
    private ListViewAdapter adapter;
 
    private int startIndex = 1;// 從第1條開始
    private int size = 10;// 每次下載十條數據
    private List<News> newsList;
    List<Map<String, String>> data ;
 
    /*
     * 設置佈局顯示屬性
     */
    private LayoutParams mLayoutParams = new LayoutParams(
            LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT);
 
    private LayoutParams ffLayoutParams = new LayoutParams(
            LinearLayout.LayoutParams.FILL_PARENT,
            LinearLayout.LayoutParams.FILL_PARENT);
 
    private ProgressBar progressBar;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.news_main);
        data=new ArrayList<Map<String, String>>();
        addView();
    }
 
    private void addView() {
        if (startIndex == 1) {
            newsList = new ArrayList<News>();
            newsList = getNewsList();
        }
        getdata(newsList);
        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.HORIZONTAL);
        progressBar = new ProgressBar(this);
        layout.addView(progressBar, mLayoutParams);
        TextView textView = new TextView(this);
        textView.setText("加載中…");
        textView.setGravity(Gravity.CENTER_VERTICAL);
        layout.addView(textView, ffLayoutParams);
        layout.setGravity(Gravity.CENTER);
        loadingLayout = new LinearLayout(this);
        loadingLayout.addView(layout, mLayoutParams);
        loadingLayout.setGravity(Gravity.CENTER);
 
        // 得到一個ListView用來顯示條目
        mListView = (ListView) findViewById(R.id.listView);
        mListView.addFooterView(loadingLayout);
        adapter = new ListViewAdapter();
        mListView.setAdapter(adapter);
        mListView.setOnScrollListener(this);
        mListView.setTextFilterEnabled(true);
    }
 
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        // TODO Auto-generated method stub
        if (firstVisibleItem + visibleItemCount == totalItemCount) {
            if (mThread == null || !mThread.isAlive()) {
                mThread = new Thread() {
 
                    @Override
                    public void run() {
                        newsList = new ArrayList<News>();
                        newsList = getNewsList();
                        getdata(newsList);
                        Message msg = new Message();
                        msg.what = 1;
                        handler.sendMessage(msg);
                    }
                };
                mThread.run();
            }
        }
    }
     
    Handler handler = new Handler() {
 
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            if (msg.what == 1) {
                startIndex = startIndex + size;
                Log.v("startindex", startIndex + "");
                mListView.removeFooterView(loadingLayout);
                mThread.stop();
                adapter.count += size;
                adapter.notifyDataSetChanged();
                return;
            }
        }
    };
 
    class ListViewAdapter extends BaseAdapter {
        int count = 10;
 
        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return count;
        }
 
        @Override
        public Object getItem(int position) {
            // TODO Auto-generated method stub
            return 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
            convertView = LayoutInflater.from(getApplicationContext()).inflate(
                    R.layout.news_item, null);
            TextView textView = (TextView) convertView
                    .findViewById(R.id.textNewsTitle);
            textView.setText((data.get(position)).get("title"));
            return convertView;
        }
    }
 
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // TODO Auto-generated method stub
 
    }
 
    private List<Map<String, String>> getdata(List<News> list) {
 
        if (list == null)
            return null;
        for (News news : list) {
            Map<String, String> map = new HashMap<String, String>();
            map.put("title", news.getTitle());
            data.add(map);
        }
        return data;
    }
 
    /*
     * 獲取網絡數據 註:我是訪問本機的一個新聞服務,使用asp.net技術來實現的,等一段時間我打算寫一個系列來總結次項目
     * 這個是項目是一個基於android的資訊播報軟件
     */
    private List<News> getNewsList() {
        String path = "http://10.0.2.2/getNewsList.aspx";
        String xmlStr = "<?xml version='1.0' encoding='utf-8'?><source><categoryIds>1,3,7</categoryIds><startIndex>"
                + startIndex
                + "</startIndex><detail>2</detail><count>"
                + size
                + "</count></source>";
        NewsConnector newsConnector = new NewsConnector();
        List<News> list = new ArrayList<News>();
        list = newsConnector.getNewsList(path, xmlStr);
        return list;
    }
}
  
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、主要代碼
 @Override
    public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
        // TODO Auto-generated method stub
        if(arg1+arg2==arg3)
        {
            if(!isloading)
            {
                new myAsyncTask().execute(null);
            }
            else
            {
                mListView.removeFooterView(loadingLayout);
            }
        }
    }
 
    @Override
    public void onScrollStateChanged(AbsListView arg0, int arg1) {
        // TODO Auto-generated method stub
         
    }
     
    private class myAsyncTask extends AsyncTask<Void, Void, Void>
    {
 
        @Override
        protected Void doInBackground(Void… params) {
            // TODO Auto-generated method stub
             
            newsList = new ArrayList<News>();
            newsList = getNewsList();
            getdata(newsList);
            return null;
             
        }
 
        @Override
        protected void onPostExecute(Void result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);
            adapter.count+=size;
            adapter.notifyDataSetChanged();
            startIndex+=size;
            isloading=false;
        }
 
        @Override
        protected void onPreExecute() {
            // TODO Auto-generated method stub
            super.onPreExecute();
            isloading=true;
        }
         
    }
註:以上僅是和使用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變得比較復雜。
 
附件上截圖

  

 

下載源碼:http://up.aiwalls.com/2012/0310/20120310091950280.zip

摘自 wangyan9110

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *