다양한 어댑터를 개발하고 사용해본 결과, 제가 가장 편하게 사용하는 것은 BaseAdapter입니다. 다른 어댑터에 비해 사용하기가 조금 더 번거롭기는 하지만 이를 사용하면 ListView, GridView, 갤러리, Spinner 등 이는 인터페이스 클래스 Adapter에서 직접 상속됩니다. BaseAdapter를 사용하는 경우 많은 메서드를 다시 작성해야 하며, 그 중 가장 중요한 것은 ListView 최적화와 같은 문제가 포함되기 때문입니다. 다른 메서드에 대해서는 링크된 기사를 참조하세요. 🎜>
BaseAdapter는 다른 어댑터와 다소 다릅니다. 다른 어댑터는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}});과 같이 구성 메서드에서 직접 데이터를 설정할 수 있지만 BaseAdapter에서는 BaseAdapter에서 상속된 클래스를 구현하고 다시 작성해야 합니다.
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; } }등 많은 메소드가 있습니다. 별 어려움은 없으나, getView 메소드를 잘 처리해야 하는데 이것이 가장 번거롭습니다첫 번째 유형: 처리 없음, 이와 같이 작성하는 것은 권장되지 않습니다. 데이터의 양이 적으면 괜찮지만, 목록 항목의 데이터의 양이 크면 매번 View가 다시 생성되고 리소스가 설정되므로 성능에 심각한 영향을 미칠 수 있으므로 하지 마십시오. 처음부터 이 방법을 사용하지 마세요.
@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; }ListView 최적화의 두 번째 유형: ConvertView를 캐시하여 캐시된 contentView를 사용하는 이 방법은 View를 생성하기 전에 해당 View가 캐시에 존재하지 않는지 확인할 수 있습니다. 이미 존재하는 경우 캐시에 있는 뷰를 사용하여 성능을 향상할 수 있습니다.
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; }ListView 최적화의 세 번째 유형: ConvertView+ViewHolder를 통해 구현됩니다. ViewHolder는 정적 클래스입니다. 데이터를 표시하는 뷰(View)를 캐싱하여 UI의 응답속도를 빠르게 한다는 것입니다. convertView == null 이라고 판단할 때 비어 있으면 목록의 설계된 항목 레이아웃(XML)을 기반으로 ConvertView에 값이 할당되고, viewHolder가 생성되어 ConvertView.View 컨트롤(XML 레이아웃의 컨트롤) 그런 다음 시스템이 두 번째로 ListView를 그릴 때 태그에서 제거될 수 있도록 변환 뷰의 setTag를 사용하여 viewHolder를 태그로 설정합니다. (아래 코드 참조) convertView가 비어 있지 않은 경우, ConvertView의 getTag()를 사용하여 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; }
여기서 어댑터는 효율적으로 작동하기 위해 두 가지 기술을 사용합니다. - 필요하지 않을 때 View 확장을 방지하기 위해 구현된 getView()에 전달된 ConvertView를 재사용합니다
(번역: 불필요한 뷰를 채우지 않도록 getView() 메서드에 전달된 캐시 변환 뷰 재사용) - 필요하지 않은 경우 findViewById() 호출을 방지하기 위해 ViewHolder 패턴을 사용합니다
(번역: ViewHolder 패턴 사용 findViewById()에 대한 불필요한 호출을 피하기 위해: 너무 많은 findViewById도 성능에 영향을 미칩니다) ViewHolder 클래스의 역할 - ViewHolder 패턴은 getView()에 의해 반환된 뷰의 태그에 데이터 구조를 저장하는 것으로 구성됩니다. 이 데이터 구조에는 참조가 포함되어 있습니다. 데이터를 바인딩하려는 뷰에 연결하여 getView()가 호출될 때마다 findViewById()를 호출하지 않아도 됩니다
(번역: ViewHolder 모드에서 getView() 메서드에 의해 반환된 뷰의 태그 데이터 저장 이 데이터 구조에는
데이터를 바인딩하려는 뷰에 대한 참조가 포함되어 있으므로 getView()가 호출될 때마다 findViewById()를 호출하지 않아도 됩니다.
인스턴스 1: BaseAdapter를 사용하여 ListView 레이아웃
main.xml
list_item.xmlActivity
<?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>
실행 결과를 사용자 정의합니다. 다음:
<?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>
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; } } }예제 2: 갤러리에 BaseAdapter 적용main.xml활동: 여기에는 getView가 없습니다. 부분 최적화는 오랫동안 디버깅을 한 후에도 아직 조정하지 않았습니다. 아직 가장 기본적인 방법을 사용하고 있습니다. 이미지 리소스가 많으면 메모리 부족 오류가 발생하기 때문에 갤러리의 메모리 누수에 대해 특별한 시간을 찾아 작성하겠습니다.
작동 효과: 원리는 동일하지만 레이아웃이 로드됩니다. 가끔 차이가 있을 수 있지만, 이 작은 차이도 충분히 짜증납니다
<?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>