Android學習筆記二十四之ListView列表視圖二

來源:互聯網
上載者:User

標籤:

Android學習筆記二十四之ListView列表視圖二

  前面一篇我們介紹了常用的幾種適配器的簡單實現和ListView的簡單使用,這一篇中,我們介紹一下ListView的最佳化和一些其它的問題。

ListView最佳化方法一

  在ListView中,我們最常用的就是自訂Adapter,在我們自訂Adapter中,需要實現兩個比較重要的方法getCount()和getView(),前者是負責計算ListView的總Item數,後者是產生Item,有多少個Item就會調用getView()方法多少次。getView()方法每次調用的時候都會重新inflate一個View出來返回去,但是對於ListView,只需要保留能夠顯示的最大的View的數目即可,而新的View可以複用消失的View。ListView給我們提供了可複用的View對象,在getView()方法裡面,有一個參數View,這個就是可以複用的View對象。當參數View為null的時候,我們需要inflate一個View,當它不為null的時候,我們可以直接將他返回。例如:

 @Overridepublic View getView(int i, View view, ViewGroup viewGroup) {    ViewHolder viewHolder;    //view為空白的時候,inflate一個新的view    if (view == null) {        view = LayoutInflater.from(context).inflate(R.layout.item_base_adapter, null);        viewHolder = new ViewHolder();        viewHolder.tv_base_adapter = (TextView) view.findViewById(R.id.tv_base_adapter);        view.setTag(viewHolder);    } else {        viewHolder = (ViewHolder) view.getTag();    }    viewHolder.tv_base_adapter.setText(datas[i]);    //不為空白,複用view    return view;}
ListView最佳化方法二

  上面介紹的是對View複用的最佳化,這樣我們可以不必每一item都inflate一個新的view,可以通過複用,減小記憶體開銷。下面我們介紹一個每一個AndroidAPP中都必不可少的操作,擷取控制項控制代碼,簡單的說就是拿到id。在ListView中,我們inflate一個View,裡面也有需要擷取到組件id的,我們可以用ViewHolder來實現最佳化:

  具體的思路就是,我們在ViewHolder中存放我們需要的控制項,在View為null的時候,需要inflate一個新的view,同時我們還new一個ViewHolder類的對象,並將findviewById的結果賦值給ViewHolder中對應的成員變數,我們可以調用View中setTag()方法,將ViewHolder和View綁定起來。當view不為null的時候,通過getTag()方法取出ViewHolder對象,這樣就可以獲得ViewHolder中的成員變數,也不再需要調用findViewById方法了。例如:

@Overridepublic View getView(int i, View view, ViewGroup viewGroup) {    ViewHolder viewHolder;    if (view == null) {        view = LayoutInflater.from(context).inflate(R.layout.item_base_adapter, null);        //view為空白,new一個ViewHolder對象        viewHolder = new ViewHolder();        //擷取到ViewHolder對象中成員變數的id        viewHolder.tv_base_adapter = (TextView) view.findViewById(R.id.tv_base_adapter);        //調用setTag方法,將ViewHolder綁定到中        view.setTag(viewHolder);    } else {        //view不為空白,調用getTag方法,取出儲存的ViewHolder對象        viewHolder = (ViewHolder) view.getTag();    }    viewHolder.tv_base_adapter.setText(datas[i]);    return view;}static class ViewHolder {    TextView tv_base_adapter;}
ListView最佳化方法三

  上面介紹了兩種ListView的最佳化方法,第二種最佳化效率根據google官方文檔的解析,可以最佳化5%左右的效率。下面介紹一下第三種最佳化方法。

  在我們實際開發中,ListView顯示的資料都是在網路中載入,假如網路比較好,能一次將所有的資料載入出來,這樣使用者體驗還好,如果網路不好,那麼載入資料需要時間比較久,使用者體驗就不好。另外,我們知道,虛擬機器為每一個進程分配的記憶體是有限的,如果一下載入太多的資料就會出現記憶體溢出的情況。為瞭解決這兩個問題,我們可以用分批載入的方法,但是分批載入還是不能完全解決問題。假如我有10萬條資料需要載入,分批載入任然可能會出現OOM問題,這時,我們需要將資料分頁載入,先分頁載入,然後在分批載入,這樣使用者體驗會好一些。

ListView出現的一些問題和解決ListView焦點問題

  在一些情況中,我們需要在ListView的Item中添加Button、EditText、CheckBox等控制項,這就涉及到了焦點擷取的問題。我們在ListView的Item中添加了Button按鈕,點擊發現,我們不能觸發onItemClick和onItemLongClick方法,這就是ListView的焦點被攔截了。解決辦法也很簡單:

  給攔截ListView焦點的控制項設定android:focusable=”false”屬性或者代碼調用setFocusable(false) 防範即可。還有一種方法就是在Item布局的根節點設定android:descendantFocusability=”blocksDescendants” 屬性,這個屬性有三個可選值

  • beforeDescendants:viewgroup會優先其子類控制項而擷取到焦點
  • afterDescendants:viewgroup只有當其子類控制項不需要擷取焦點時才擷取焦點
  • blocksDescendants:viewgroup會覆蓋子類控制項而直接獲得焦點

這是ListView焦點問題的解決方案。

ListView資料更新問題

首先實現一個簡單的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"><LinearLayout    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_marginLeft="10dp"    android:layout_marginTop="10dp"    android:orientation="horizontal">    <Button        android:id="@+id/btn_add_one"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="插入一條資料" />    <Button        android:id="@+id/btn_add_on_position"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="在特定位置插入一條資料" /></LinearLayout><LinearLayout    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_marginBottom="10dp"    android:layout_marginLeft="10dp"    android:orientation="horizontal">    <Button        android:id="@+id/btn_delete_one"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="根據對象刪除" />    <Button        android:id="@+id/btn_delete_on_position"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="根據位置刪除" />    <Button        android:id="@+id/btn_delete_all"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="刪除所有資料" /></LinearLayout><ListView    android:id="@+id/lv_data"    android:layout_width="match_parent"    android:layout_height="match_parent" /></LinearLayout>

Item布局代碼:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="10dp"android:gravity="center_vertical"android:orientation="horizontal"><ImageView    android:id="@+id/iv_icon"    android:layout_width="40dp"    android:layout_height="40dp"    android:src="@drawable/icon" /><TextView    android:id="@+id/tv_data_text"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_centerVertical="true"    android:layout_marginLeft="5dp"    android:layout_toRightOf="@id/iv_icon"    android:text="載入出來的資料"    android:textSize="18sp" /></RelativeLayout>

這裡的Item比較簡單,就直接是一張圖片和一個文字

Activity代碼:

package com.example.listviewdemo.activity;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.ListView;import com.example.listviewdemo.MYData;import com.example.listviewdemo.R;import com.example.listviewdemo.adapter.DataAdapter;import java.util.ArrayList;import java.util.List;/** * Created by Devin on 2016/7/11. */public class DataUpActivity extends AppCompatActivity {private Button btn_add_one;private Button btn_add_on_position;private Button btn_delete_one;private Button btn_delete_on_position;private Button btn_delete_all;private ListView lv_data;private DataAdapter adapter;private List<MYData> datas;private int flag = 1;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_data);    btn_add_one = (Button) findViewById(R.id.btn_add_one);    btn_add_on_position = (Button) findViewById(R.id.btn_add_on_position);    btn_delete_one = (Button) findViewById(R.id.btn_delete_one);    btn_delete_on_position = (Button) findViewById(R.id.btn_delete_on_position);    btn_delete_all = (Button) findViewById(R.id.btn_delete_all);    lv_data = (ListView) findViewById(R.id.lv_data);    datas = new ArrayList<>();    adapter = new DataAdapter(this, datas);    lv_data.setAdapter(adapter);  }}

自訂配接器代碼:

package com.example.listviewdemo.adapter;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;import com.example.listviewdemo.MYData;import com.example.listviewdemo.R;import java.util.ArrayList;import java.util.List;/** * Created by Devin on 2016/7/11. */public class DataAdapter extends BaseAdapter {private List<MYData> datas;private Context mContext;public DataAdapter(Context mContext, List<MYData> datas) {    this.mContext = mContext;    this.datas = datas;}@Overridepublic int getCount() {    return datas.size();}@Overridepublic Object getItem(int i) {    return i;}@Overridepublic long getItemId(int i) {    return i;}@Overridepublic View getView(int i, View view, ViewGroup viewGroup) {    ViewHolder viewHolder;    if (view == null) {        view = LayoutInflater.from(mContext).inflate(R.layout.item_data, null);        viewHolder = new ViewHolder();        viewHolder.tv_data_text = (TextView) view.findViewById(R.id.tv_data_text);        viewHolder.iv_icon = (ImageView) view.findViewById(R.id.iv_icon);        view.setTag(viewHolder);    } else {        viewHolder = (ViewHolder) view.getTag();    }    viewHolder.iv_icon.setImageResource(datas.get(i).getIconId());    viewHolder.tv_data_text.setText(datas.get(i).getContent());    return view;}private static class ViewHolder {    TextView tv_data_text;    ImageView iv_icon;}}

還有就是一個普通的bean

package com.example.listviewdemo;/** * Created by Devin on 2016/7/11. */public class MYData {private int iconId;private String content;public MYData() {}public MYData(int iconId, String content) {    this.iconId = iconId;    this.content = content;}public int getIconId() {    return iconId;}public void setIconId(int iconId) {    this.iconId = iconId;}public String getContent() {    return content;}public void setContent(String content) {    this.content = content;}@Overridepublic String toString() {    return "Data{" +            "iconId=" + iconId +            ", content=‘" + content + ‘\‘‘ +            ‘}‘;}}

這樣,我們啟動並執行效果是:

沒有顯示有Item,因為我們在適配器中添加的是一個空的list,接下來我們實現按鈕的事件和具體更新ListView

插入一條資料

在適配器中添加這個方法:

/** * 添加資料 * * @param myData */public void addData(MYData myData) {    if (datas == null) {        datas = new ArrayList<>();    }    datas.add(myData);    notifyDataSetChanged();}

在activity中實現點擊事件:

btn_add_one.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View view) {            MYData data = new MYData(R.drawable.icon, "這是添加的資料~~~~~~X" + flag);            adapter.addData(data);            flag++;        }    });

就可以實現在ListView中添加一條資料,具體的會在後面統一附上

在指定位置插入一條資料

在適配器中添加如下方法:

/** * 在指定位置添加資料 * * @param position * @param myData */public void addData(int position, MYData myData) {    if (datas == null) {        datas = new ArrayList<>();    }    datas.add(position, myData);    notifyDataSetChanged();}

實現按鈕的點擊事件:

btn_add_on_position.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View view) {            MYData data = new MYData(R.drawable.icon, "這是添加的資料~~~~~~X" + flag);            adapter.addData(3, data);        }    });

就可以完成在指定位置添加一條資料,這裡只是簡單的實現,如果list中沒有那麼多資料,會出現數組下標越界的錯誤

根據對象刪除資料

在適配器中添加如下方法:

/** * 根據對象刪除資料 * * @param myData */public void removeData(MYData myData) {    if (datas != null) {        datas.remove(myData);    }    notifyDataSetChanged();}

實現按鈕的點擊事件:

btn_delete_one.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View view) {            MYData data = datas.get(2);            adapter.removeData(data);        }    });

這裡只是簡單的刪除下標為3的資料,如果listview的長度小於3,會出現數組下標越界的錯誤

根據位置刪除資料

在適配器中添加如下方法:

/** * 根據位置刪除資料 * * @param position */public void removeData(int position) {    if (datas != null && position <= datas.size()) {        datas.remove(position);    }    notifyDataSetChanged();}

實現按鈕的點擊事件:

btn_delete_on_position.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View view) {            adapter.removeData(3);        }    });

刪除指定位置的資料,需要判定是否存在不然會出現錯誤

刪除所有的資料

在適配器中添加如下方法:

/** * 清除所有的資料 */public void removeAll() {    if (datas != null) {        datas.clear();    }    notifyDataSetChanged();}

實現按鈕的點擊事件:

btn_delete_all.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View view) {            adapter.removeAll();        }    });

最後附上:

這裡實現ListView的資料更新問題,但是任然存在一些小問題,比如,沒有資料的時候顯示一片空白,使用者體驗不是很好。可以重寫,根據伺服器返回的資料更新介面。這裡就不做實現了。下一節我們介紹一下ListView多布局的實現,類似QQ等的聊天介面。

Android學習筆記二十四之ListView列表視圖二

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.