AndroidのListViewのAdapterの多重化
Android開発では1つのプロジェクトで多くの場所で使用するListViewが必要です.ListViewを使用する以上、Adapterを使用することは避けられないが、論理がほぼ同じAdapterを繰り返し書くのも退屈なことであり、以下ではAdapterをどのように多重化するかを検討する.ListViewの2つの場所(アナログコード):
上記の2つのコードは開発の過程でよく使われているが、現在はAdapterを抽出してカプセル化している:1.まずAdapterの最初の3つの方法:getCount(),getItem(),getItemId()は全く同じで,1つのArrayListで完成する.我々が抽出したAdapterはサブクラスにArrayListを注入した.
2.このときAdapterのgetView()は膨大に表示され、getView()メソッドの概要のために、getView()メソッドと多重化のためのView Holderをさらに修正する(2番目のListViewについて):
Adapter:
ViewHolder:
3.2つのListViewを上記のように操作すると、getViewが極めて類似していることがわかります.では、分類に抽出できます.この場合、ListViewのViewHolderごとに異なる問題が見つかります.そのため、ViewHolderを1つのListViewに入力したものと抽出します(2番目のListViewについて):BaseViewHolder:
抽出後:ViewHolderごとに2つの抽象的なメソッドを実装する必要があります.
4.このときgetView()を抽象に抽出する:ViewHolderごとにBaseViewHolderもあるが、getView()で具体的なViewHodlerを生成する際にどちらを生成するかわからないので、サブクラスViewHolderを取得する抽象的な方法を定義することができる.サブクラスを自身のViewHolderの実装に戻す(ここではDAO設計モードにおけるBaseServiceMaplと同様に抽象的な方法を宣言し、サブクラスを自身のDaoの実装に戻す.BaseServiceMaplはどのDaoで完了するか分からないため、サブクラスに捨てて処理するしかない).
最終コード(2番目のListViewの場合):
抽象的な2つのクラスAdapterとViewHolder:
これでListViewがAdapterを設定する抽象化が完了し,以降Adapterを使用する場所で直接AdapterにDefaultAdapterを継承させる必要がある.ViewHolderにBaseViewHolderを実装させ、親定義の抽象メソッド(Adapter実装では自分のViewHolderを返すメソッド、ViewHolder実装では各エントリを生成するViewメソッドとこのViewにデータを設定するメソッド)をそれぞれ実装すればよい.
.// ListView
listView.setAdapter(new MyAdapter());
class MyAdapter extends BaseAdapter{
//arrayList ListView
@Override
public int getCount() {
return arrayList.size();
}
@Override
public Object getItem(int i) {
return arrayList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder =null;
if(view == null){
view = View.inflate(ThemeFragment.this.getActivity(), R.layout.theme_adapt_item,null);
viewHolder = new ViewHolder();
viewHolder.icon = (ImageView) view.findViewById(R.id.theme_iv);
viewHolder.textView = (TextView) view.findViewById(R.id.theme_text);
view.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) view.getTag();
}
// ViewHolder , ListView
BitmapHelper.getBitmapUtils().display(viewHolder.icon, GlobalUrl.ICON_URL+theme.themeInfos.get(i).url);
viewHolder.textView.setText(theme.themeInfos.get(i).des);
return view;
}
}
// ListView ViewHolder
static class ViewHolder{
ImageView icon;
TextView textView;
}
.// ListView
listView.setAdapter(new MyAdapter());
class MyAdapter extends BaseAdapter{
//arrayList ListView
@Override
public int getCount() {
return arrayList.size();
}
@Override
public Object getItem(int i) {
return arrayList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder =null;
if(view == null){
view = View.inflate(HomeFragment.this.getActivity(), R.layout.home_adapt_item, null);
viewHolder = new ViewHolder();
viewHolder.item_icon = (ImageView) view.findViewById(R.id.item_icon);
viewHolder.app_name = (TextView) view.findViewById(R.id.item_title);
viewHolder.app_size = (TextView) view.findViewById(R.id.item_size);
viewHolder.app_introduce = (TextView) view.findViewById(R.id.item_bottom);
view.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) view.getTag();
}
// ViewHolder , ListView
BitmapHelper.getBitmapUtils().display(this.item_icon, GlobalUrl.ICON_URL + detailAppInfos.iconUrl);
this.app_name.setText(detailAppInfos.name);
this.app_size.setText(detailAppInfos.size);
this.app_introduce.setText(detailAppInfos.des);
return view;
}
}
// ListView ViewHolder
static class ViewHolder{
ImageView item_icon;
TextView app_name;
TextView app_size;
TextView app_introduce;
}
上記の2つのコードは開発の過程でよく使われているが、現在はAdapterを抽出してカプセル化している:1.まずAdapterの最初の3つの方法:getCount(),getItem(),getItemId()は全く同じで,1つのArrayListで完成する.我々が抽出したAdapterはサブクラスにArrayListを注入した.
public class DefaultAdapter<T> extends BaseAdapter {
private List<T> listData;
public DefaultAdapter(List<T> list){
this.listData = list;
}
@Override
public int getCount() {
return listData.size();
}
@Override
public Object getItem(int i) {
return listData.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
return null;
}
}
2.このときAdapterのgetView()は膨大に表示され、getView()メソッドの概要のために、getView()メソッドと多重化のためのView Holderをさらに修正する(2番目のListViewについて):
Adapter:
class MyAdapter extends DefaultAdapter<HomeInfos.DetailAppInfos>{
public MyAdapter(List<HomeInfos.DetailAppInfos> list) {
super(list);
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder = null;
if(view==null){
// view ViewHolder
viewHolder = new ViewHolder();
}else{
viewHolder = (ViewHolder) view.getTag();
}
// viewHolder , ( )
viewHolder.setDetailInfos(homeInfos.list.get(i));
return viewHolder.getView();
}
}
ViewHolder:
static class ViewHolder{
ImageView item_icon;
TextView app_name;
TextView app_size;
TextView app_introduce;
// View
private View view;
private BitmapUtils bitmapUtils;
// , ListView
private HomeInfos.DetailAppInfos detailAppInfos;
//
public void setDetailInfos(HomeInfos.DetailAppInfos detailAppInfos) {
this.detailAppInfos = detailAppInfos;
// , view。 view viewHolder
refreshView();
}
public ViewHolder(){
bitmapUtils = BitmapHelper.getBitmapUtils();
view = View.inflate(UiUtil.getContext(), R.layout.home_adapt_item, null);
this.item_icon = (ImageView) view.findViewById(R.id.item_icon);
this.app_name = (TextView) view.findViewById(R.id.item_title);
this.app_size = (TextView) view.findViewById(R.id.item_size);
this.app_introduce = (TextView) view.findViewById(R.id.item_bottom);
view.setTag(this);
}
public View getView() {
return view;
}
// viewHolder
public void refreshView(){
BitmapHelper.getBitmapUtils().display(this.item_icon, GlobalUrl.ICON_URL + detailAppInfos.iconUrl);
this.app_name.setText(detailAppInfos.name);
this.item_rating.setRating((float) detailAppInfos.stars);
this.app_size.setText(detailAppInfos.size);
this.app_introduce.setText(detailAppInfos.des);
}
}
3.2つのListViewを上記のように操作すると、getViewが極めて類似していることがわかります.では、分類に抽出できます.この場合、ListViewのViewHolderごとに異なる問題が見つかります.そのため、ViewHolderを1つのListViewに入力したものと抽出します(2番目のListViewについて):BaseViewHolder:
public abstract class BaseViewHolder<T> {
private View view;
private BitmapUtils bitmapUtils;
private T detailInfos;
public void setDetailInfos(T detailInfos) {
this.detailInfos = detailInfos;
refreshView(detailInfos);
}
public BaseViewHolder(){
bitmapUtils = BitmapHelper.getBitmapUtils();
view = initView();
view.setTag(this);
}
public abstract View initView();
public View getView() {
return view;
}
public abstract void refreshView(T detailInfos);
}
抽出後:ViewHolderごとに2つの抽象的なメソッドを実装する必要があります.
static class ViewHolder extends BaseViewHolder<HomeInfos.DetailAppInfos>{
ImageView item_icon;
TextView app_name;
RatingBar item_rating;
TextView app_size;
TextView app_introduce;
@Override
public View initView() {
View view = View.inflate(UiUtil.getContext(), R.layout.home_adapt_item, null);
this.item_icon = (ImageView) view.findViewById(R.id.item_icon);
this.app_name = (TextView) view.findViewById(R.id.item_title);
this.item_rating = (RatingBar) view.findViewById(R.id.item_rating);
this.app_size = (TextView) view.findViewById(R.id.item_size);
this.app_introduce = (TextView) view.findViewById(R.id.item_bottom);
return view;
}
@Override
public void refreshView(HomeInfos.DetailAppInfos detailAppInfos){
BitmapHelper.getBitmapUtils().display(this.item_icon, GlobalUrl.ICON_URL + detailAppInfos.iconUrl);
this.app_name.setText(detailAppInfos.name);
this.item_rating.setRating((float) detailAppInfos.stars);
this.app_size.setText(detailAppInfos.size);
this.app_introduce.setText(detailAppInfos.des);
}
}
4.このときgetView()を抽象に抽出する:ViewHolderごとにBaseViewHolderもあるが、getView()で具体的なViewHodlerを生成する際にどちらを生成するかわからないので、サブクラスViewHolderを取得する抽象的な方法を定義することができる.サブクラスを自身のViewHolderの実装に戻す(ここではDAO設計モードにおけるBaseServiceMaplと同様に抽象的な方法を宣言し、サブクラスを自身のDaoの実装に戻す.BaseServiceMaplはどのDaoで完了するか分からないため、サブクラスに捨てて処理するしかない).
最終コード(2番目のListViewの場合):
class MyAdapter extends DefaultAdapter<HomeInfos.DetailAppInfos>{
public MyAdapter(List<HomeInfos.DetailAppInfos> list) {
super(list);
}
@Override
protected BaseViewHolder getViewHolder() {
return new ViewHolder();
}
}
static class ViewHolder extends BaseViewHolder<HomeInfos.DetailAppInfos>{
ImageView item_icon;
TextView app_name;
TextView app_size;
TextView app_introduce;
@Override
public View initView() {
View view = View.inflate(UiUtil.getContext(), R.layout.home_adapt_item, null);
this.item_icon = (ImageView) view.findViewById(R.id.item_icon);
this.app_name = (TextView) view.findViewById(R.id.item_title);
this.app_size = (TextView) view.findViewById(R.id.item_size);
this.app_introduce = (TextView) view.findViewById(R.id.item_bottom);
return view;
}
@Override
public void refreshView(HomeInfos.DetailAppInfos detailAppInfos){
BitmapHelper.getBitmapUtils().display(this.item_icon, GlobalUrl.ICON_URL + detailAppInfos.iconUrl);
this.app_name.setText(detailAppInfos.name);
this.app_size.setText(detailAppInfos.size);
this.app_introduce.setText(detailAppInfos.des);
}
}
抽象的な2つのクラスAdapterとViewHolder:
public abstract class DefaultAdapter<T> extends BaseAdapter {
private List<T> listData;
public DefaultAdapter(List<T> list){
this.listData = list;
}
@Override
public int getCount() {
return listData.size();
}
@Override
public Object getItem(int i) {
return listData.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
BaseViewHolder viewHolder =null;
if(view == null){
viewHolder = getViewHolder();
}else{
viewHolder = (BaseViewHolder) view.getTag();
}
viewHolder.setDetailInfos(listData.get(i));
return viewHolder.getView();
}
protected abstract BaseViewHolder getViewHolder();
}
public abstract class BaseViewHolder<T> {
private View view;
private BitmapUtils bitmapUtils;
private T detailInfos;
public void setDetailInfos(T detailInfos) {
this.detailInfos = detailInfos;
refreshView(detailInfos);
}
public BaseViewHolder(){
bitmapUtils = BitmapHelper.getBitmapUtils();
view = initView();
view.setTag(this);
}
public abstract View initView();
public View getView() {
return view;
}
public abstract void refreshView(T detailInfos);
}
これでListViewがAdapterを設定する抽象化が完了し,以降Adapterを使用する場所で直接AdapterにDefaultAdapterを継承させる必要がある.ViewHolderにBaseViewHolderを実装させ、親定義の抽象メソッド(Adapter実装では自分のViewHolderを返すメソッド、ViewHolder実装では各エントリを生成するViewメソッドとこのViewにデータを設定するメソッド)をそれぞれ実装すればよい.