實驗五 ListView 水果列表
一、實驗目的
(1)掌握ListView控制元件的使用
(2)掌握如何自定義Adapter的使用二、實驗內容
(1)定義一個實體類Fruit,作為ListView介面卡的適配型別。
(2)為ListView的子項指定一個我們自定義的佈局fruit_item.xml。
(3)建立一個自定義的介面卡FruitAdapter,這個介面卡繼承自ArrayAdapter。重寫構造方法和getView方法。
(4) 分析上述程式碼存在的問題並改進。
三、實驗結果圖
四、實驗程式碼
Fruit類:
package com.test5.listview; public class Fruit { private String name; private int id; public Fruit(String name,int id) { // TODO Auto-generated constructor stub this.id = id; this.name = name; } public int getId() { return id; } public String getName() { return name; } }
FruitAdapter:
package com.test5.listview; import java.util.List; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; public class FruitAdapter extends ArrayAdapter<Fruit> { private int resouceID; public FruitAdapter(Context context, int id, List<Fruit> objects) { super(context, id, objects); // TODO Auto-generated constructor stub resouceID = id; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub Fruit fruit = getItem(position); View view; ViewHolder viewHolder; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate(resouceID, null); viewHolder = new ViewHolder(); viewHolder.fruit_image = (ImageView) view.findViewById (R.id.fruit_image); viewHolder.fruit_item = (TextView) view.findViewById (R.id.fruit_item); view.setTag(viewHolder); // 將ViewHolder儲存在View中 } else { view = convertView; viewHolder = (ViewHolder) view.getTag(); // 重新獲取ViewHolder } viewHolder.fruit_image.setImageResource((fruit).getId()); viewHolder.fruit_item.setText(fruit.getName()); return view; } } class ViewHolder{ ImageView fruit_image; TextView fruit_item; }
MainActivity:
package com.test5.listview; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; import android.widget.Toast; public class MainActivity extends Activity { private List<Fruit> fruitlist = new ArrayList<Fruit>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initFruit(); FruitAdapter adapter = new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitlist); ListView listview = (ListView) findViewById(R.id.lv); listview.setAdapter(adapter); listview.setOnItemClickListener(new OnItemClickListener(){ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub Fruit fruit = fruitlist.get(position); Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show(); } }); } @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; } public void initFruit(){ Fruit apple = new Fruit("Apple",R.drawable.apple_pic); fruitlist.add(apple); Fruit banana = new Fruit("Banana",R.drawable.banana_pic); fruitlist.add(banana); Fruit cherry = new Fruit("Cherry",R.drawable.cherry_pic); fruitlist.add(cherry); Fruit grape = new Fruit("Grape",R.drawable.grape_pic); fruitlist.add(grape); Fruit mango = new Fruit("Mango",R.drawable.mango_pic); fruitlist.add(mango); Fruit orange = new Fruit("Orange",R.drawable.orange_pic); fruitlist.add(orange); Fruit pear = new Fruit("Pear",R.drawable.pear_pic); fruitlist.add(pear); Fruit pineapple = new Fruit("Pineapple",R.drawable.pineapple_pic); fruitlist.add(pineapple); Fruit strawberry = new Fruit("Strawberry",R.drawable.strawberry_pic); fruitlist.add(strawberry); Fruit watermelon = new Fruit("Watermelon",R.drawable.watermelon_pic); fruitlist.add(watermelon); } }
activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
</ListView>
</RelativeLayout>
fruit_item.xml:
<?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" >
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/fruit_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp"/>
</LinearLayout>
五、存在的問題
先回答實驗內容中的第四條:按照圖片的程式碼寫的ListView的執行效率是很低的,因為在FruitAdapter的getView()方法中每次都將佈局重新載入了一遍,當ListView快速滾動的時候這就會成為效能的瓶頸。所以我們需要做一點修改,在getView()方法中進行了判斷,如果convertView為空,則使用LayoutInflater去載入佈局,如果不為空則直接對convertView進行重用。新增了一個內部類ViewHolder,用於對控制元件的例項進行快取。當convertView為空的時候,建立一個ViewHolder物件,並將控制元件的例項都存放在ViewHolder裡,然後呼叫View的setTag()方法,將ViewHolder物件儲存在View中。當convertView不為空的時候則呼叫View的getTag()方法,把ViewHolder重新取出。這樣所有控制元件的例項都快取在了ViewHolder裡,就沒有必要每次都通過findViewById()方法來獲取控制元件例項了。
然後就是,上面都是參考書上的解釋,大家能看明白最好,參考輸上的MainActivity用的是線性佈局,我這裡用的的相對佈局,顯示不太有影響。
PS:前段時間忙著比賽沒有時間更新,最近會一點點補上,實驗課的內容在自學筆記中都會有講解。