After developing and using various Adapters, the one I feel most comfortable using is BaseAdapter. Although it is a little more troublesome to use than other adapters, you can use it to achieve many of your favorite list layouts, such as ListView, GridView, Gallery, Spinner, etc. . It is directly inherited from the interface class Adapter. When using BaseAdapter, you need to rewrite many methods, the most important of which is getView, because this will involve issues such as ListView optimization. For other methods, please refer to the linked article
BaseAdapter and Others Adapter is a little different. Other Adapters can set data directly in their construction methods, such as
SimpleAdapter adapter = new SimpleAdapter(this, getData(), R.layout.list_item, new String[]{"img","title","info",newint[]{R.id.img, R.id.title, R.id.info}});
. But in BaseAdapter, you need to implement a class inherited from BaseAdapter and rewrite many methods in it, such as
class MyAdapter extends BaseAdapter { private Context context; public MyAdapter(Context context) { this.context = context; } @Override publicint getCount() { // How many items are in the data set represented by this Adapter.(在此适配器中所代表的数据集中的条目数) return0; } @Override public Object getItem(int position) { // Get the data item associated with the specified position in the data set.(获取数据集中与指定索引对应的数据项) returnnull; } @Override publiclong getItemId(int position) { // Get the row id associated with the specified position in the list.(取在列表中与指定索引对应的行id) return0; } @Override public View getView(int position, View convertView, ViewGroup parent) { // Get a View that displays the data at the specified position in the data set. returnnull; } }
this There is nothing difficult in it, but this getView method must be handled carefully, which is also the most troublesome. The first type: there is no processing, and it is not recommended to write like this. If the amount of data is small, it will be fine, but if the amount of data in the list item is large, the View will be re-created every time and the resources will be set, seriously affecting the performance, so don’t use this method from the beginning
@Override public View getView(int position, View convertView, ViewGroup parent) { View item = mInflater.inflate(R.layout.list_item, null); ImageView img = (ImageView)item.findViewById(R.id.img) TextView title = (TextView)item.findViewById(R.id.title); TextView info = (TextView)item.findViewById(R.id.info); img.setImageResource(R.drawable.ic_launcher); title.setText("Hello"); info.setText("world"); return item; }
The second method ListView optimization: By caching convertView, this method of using cached contentView can determine if the View does not exist in the cache before creating the View. If it already exists, you can use the View in the cache to improve performance
public View getView(int position, View convertView, ViewGroup parent) { if(convertView == null) { convertView = mInflater.inflate(R.layout.list_item, null); } ImageView img = (ImageView)convertView.findViewById(R.id.img) TextView title = (TextView)convertView.findViewById(R.id.title); TextView info = (TextView)ConvertView.findViewById(R.id.info); img.setImageResource(R.drawable.ic_launcher); title.setText("Hello"); info.setText("world"); return convertView; }
The third ListView optimization: through convertView +ViewHolder to achieve, ViewHolder is a static class, the key benefit of using ViewHolder is to cache the view (View) that displays data, speeding up the response speed of the UI.
When we judge convertView == null , if it is empty, we will assign a value to the convertView according to the designed Item layout (XML) of the List, and generate a viewHolder to bind each View control in the convertView (XML those controls in the layout). Then use convertView's setTag to set the viewHolder to the Tag so that it can be taken out of the Tag when the system draws the ListView for the second time. (See the code below)
If convertView is not empty, convertView's getTag() will be used directly to obtain a ViewHolder.
//在外面先定义,ViewHolder静态类 staticclass ViewHolder { public ImageView img; public TextView title; public TextView info; } //然后重写getView @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView == null) { holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.list_item, null); holder.img = (ImageView)item.findViewById(R.id.img) holder.title = (TextView)item.findViewById(R.id.title); holder.info = (TextView)item.findViewById(R.id.info); convertView.setTag(holder); }else { holder = (ViewHolder)convertView.getTag(); holder.img.setImageResource(R.drawable.ic_launcher); holder.title.setText("Hello"); holder.info.setText("World"); } return convertView; }
At this point, someone may ask what is the difference between ViewHolder static class combined with caching convertView and using convertView directly? Is it repeated?
Here, the official explanation is given
Two methods to improve Adapter
To work efficiently the adapter implemented here uses two techniques: -It reuses the convertView passed to getView() to avoid inflating View when it is not necessary
(Translation: reuse cache convertView passed to getView() method to avoid filling unnecessary views) -It uses the ViewHolder pattern to avoid calling findViewById() when it is not necessary
(Translation: Use the ViewHolder pattern to avoid unnecessary calls to findViewById(): because too many findViewById will also affect performance) The role of the ViewHolder class - The ViewHolder pattern consists in storing a data structure in the tag of the view returned by getView().This data structures contains references to the views we want to bind data to, thus avoiding calling to findViewById() every time getView() is invoked
(Translation: ViewHolder mode stores a data structure in the tag of the view returned by the getView() method. This data structure contains a reference to the view to which we
want to bind data, thereby avoiding calling getView every time () when calling findViewById())
Example 1: Use BaseAdapter to customize the ListView layout
main.xml
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <ListView android:id="@+id/lv" android:layout_width="fill_parent" android:layout_height="wrap_content" android:fastScrollEnabled="true" /> </LinearLayout>
list_item.xml
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" /> <TextView android:id="@+id/info" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14sp" /> </LinearLayout> </LinearLayout>
Activity
package com.loulijun.demo17; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; publicclass Demo17Activity extends Activity { private ListView lv; private List<Map<String, Object>> data; @Override publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lv = (ListView)findViewById(R.id.lv); //获取将要绑定的数据设置到data中 data = getData(); MyAdapter adapter = new MyAdapter(this); lv.setAdapter(adapter); } private List<Map<String, Object>> getData() { List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); Map<String, Object> map; for(int i=0;i<10;i++) { map = new HashMap<String, Object>(); map.put("img", R.drawable.ic_launcher); map.put("title", "跆拳道"); map.put("info", "快乐源于生活..."); list.add(map); } return list; } //ViewHolder静态类 staticclass ViewHolder { public ImageView img; public TextView title; public TextView info; } publicclass MyAdapter extends BaseAdapter { private LayoutInflater mInflater = null; private MyAdapter(Context context) { //根据context上下文加载布局,这里的是Demo17Activity本身,即this this.mInflater = LayoutInflater.from(context); } @Override publicint getCount() { //How many items are in the data set represented by this Adapter. //在此适配器中所代表的数据集中的条目数 return data.size(); } @Override public Object getItem(int position) { // Get the data item associated with the specified position in the data set. //获取数据集中与指定索引对应的数据项 return position; } @Override publiclong getItemId(int position) { //Get the row id associated with the specified position in the list. //获取在列表中与指定索引对应的行id return position; } //Get a View that displays the data at the specified position in the data set. //获取一个在数据集中指定索引的视图来显示数据 @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; //如果缓存convertView为空,则需要创建View if(convertView == null) { holder = new ViewHolder(); //根据自定义的Item布局加载布局 convertView = mInflater.inflate(R.layout.list_item, null); holder.img = (ImageView)convertView.findViewById(R.id.img); holder.title = (TextView)convertView.findViewById(R.id.tv); holder.info = (TextView)convertView.findViewById(R.id.info); //将设置好的布局保存到缓存中,并将其设置在Tag里,以便后面方便取出Tag convertView.setTag(holder); }else { holder = (ViewHolder)convertView.getTag(); } holder.img.setBackgroundResource((Integer)data.get(position).get("img")); holder.title.setText((String)data.get(position).get("title")); holder.info.setText((String)data.get(position).get("info")); return convertView; } } }
The running results are as follows:
Example 2: Apply BaseAdapter
main.xml
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <ImageView android:id="@+id/img" android:layout_width="480px" android:layout_height="480px" android:layout_gravity="center" /> <Gallery android:id="@+id/gallery" android:layout_width="fill_parent" android:layout_height="wrap_content" android:spacing="3dp" android:layout_gravity="bottom" /> </LinearLayout>
Activity on Gallery: getView in this part has not been optimized, and it has not been adjusted after debugging for a long time. For the time being, the most basic method is still used. I will find a special time to write about the memory leak in Gallery, because when there are a lot of image resources, it will cause out of memory errors
package com.loulijun.demo16; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.Gallery; import android.widget.ImageView; publicclass Demo16Activity extends Activity { private Gallery mGallery; private ImageView mImg; //图片数组 privateint[] pics = { R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6 }; @Override publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mImg = (ImageView)findViewById(R.id.img); mGallery = (Gallery)findViewById(R.id.gallery); MyAdapter adapter = new MyAdapter(this); mGallery.setAdapter(adapter); mGallery.setOnItemClickListener(new Gallery.OnItemClickListener() { @Override publicvoid onItemClick(AdapterView<?> adapter, View view, int position, long arg3) { mImg.setImageResource(pics[position]); } }); } //内部类 class MyAdapter extends BaseAdapter { //用来接收传递过来的Context上下文对象 private Context context; //构造函数 public MyAdapter(Context context) { this.context = context; } @Override publicint getCount() { //返回图片数组大小 return pics.length; } @Override public Object getItem(int position) { //根据选中项返回索引位置 return position; } @Override publiclong getItemId(int position) { //根据选中项id返回索引位置 return position; } //未优化的getView,这部分可以使用recycle()释放内存、或者BitmapFacotry.Options缩小,或者软引用,或者控制图片资源大小等等很多方法,找时间专门写 @Override public View getView(int position, View convertView, ViewGroup parent) { ImageView img = new ImageView(context); img.setAdjustViewBounds(true); img.setImageResource(pics[position]); img.setScaleType(ImageView.ScaleType.FIT_XY); img.setLayoutParams(new Gallery.LayoutParams(120,120)); return img; } } }
Operation effect: The principle is the same, but there will be a difference when the layout is loaded, but Just this small difference is annoying enough