AndroidのListViewのAdapterの多重化


Android開発では1つのプロジェクトで多くの場所で使用するListViewが必要です.ListViewを使用する以上、Adapterを使用することは避けられないが、論理がほぼ同じAdapterを繰り返し書くのも退屈なことであり、以下ではAdapterをどのように多重化するかを検討する.ListViewの2つの場所(アナログコード):
 .//   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にデータを設定するメソッド)をそれぞれ実装すればよい.