Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Day27-ListView基本使用

Day27-ListView基本使用

編輯:關於Android編程

學過ListView的人都知道, 它在Android學習中有著舉足輕重的地位, 雖然現在有了RecyClerView來替代ListView, 但是對於我們初學者來說, 了解和使用ListView還是非常重要的!!!

我們應該知道, 顯示復雜內容的控件一般會有一個Adapter來控制它的顯示. 這其實就是我們平常所說的MVC設計模式. Adapter就扮演了Controller的角色.

在具體實現之前我們要從大方向上來了解一下ListView的實現機制.

ListView是用來顯示數據的控件, 在xml布局文件中存放(當然也可以用Java代碼實現, 就不要這麼鑽牛角尖了^v^), 所以它需要有數據源, 才能顯示數據, 但是它也需要知道我們的數據怎樣展示在手機上, 這就用到了我們的Adapter. 好,先簡單介紹到這兒, 後面會有詳細的闡述.

實現ListView的幾種簡單的方式

接下來, 我先介紹幾種實現ListView非常簡單的方式, 不過這幾種在我們後來的工作, 項目中幾乎不用, 所以我也不做過多的解釋.

直接在XML文件中指定數據源.

簡單到沒朋友, 後期幾乎沒用

ArrayAdapter的實現方式

ArrayAdapter adapter = 
new ArrayAdapter<>(this,
 android.R.layout.simple_list_item_1, 
 list);
ListView listView = (ListView) findViewById(R.id.main_listview);
listView.setAdapter(adapter);

不解釋

SimpleAdapter實現方式

它雖然叫簡單Adapter, 但是還是比ArrayAdapter復雜點, 靈活性要高些,因為用到機率也不大, 所以不解釋了, 自己可以看看使用方式

//只能用id或本地
SimpleAdapter adapter = new SimpleAdapter(this, list,R.layout.item,
       new String[]{"title", "img"},
       new int[]{R.id.item_tv, R.id.item_iv}
);

adapter.setViewBinder(new SimpleAdapter.ViewBinder() {
   @Override//返回值: 是否綁定完成
   public boolean setViewValue(View view, Object data, String textRepresentation) {

       switch (view.getId()){
           //綁定ImageView
           case R.id.item_iv:

               ImageView imageView = (ImageView) view;
               String url = (String) data;
               new ImageLoader(imageView).execute(url);

               return true;
       }
       return false;
   }
});

使用BaseAdapter實現ListView

我們現在前面做理論說明, 整理好後代碼在最後貼出

簡單介紹

首先我們寫個類(MyAdapter) extents BaseAdapter, 因為BaseAdapter為抽象類, 所以需要實現父類的四個方法

@Override//返回數據的數量
public int getCount() {
    return 0;
}
@Override//返回當前數據的對象, 參數: 位置
public Object getItem(int position) {
    return null;
}
@Override//返回當前數據對象的id(如果沒有可以直接返回position) //參數: 位置
public long getItemId(int position) {
    return 0;
}
/*
    在這裡非常重要的方法, 每次item(數據項)顯示在手機上時都會調用一次getView, 也就是說它返回的View就是每次顯示在手機上的item
*/
@Override//參數: 位置, 復用的View(一邊item出去後,再次調用時會傳入該item), 父控件
public View getView(int position, View convertView, ViewGroup parent) {
    return null;
}

ListView優化方案

1, listView布局的高度必須是定值或match_parent

    先去取第1個條目的高度和第2個條目想加,...
    計算自身的高度, 所以不要使用wrap_content
2, convertView的復用

3, 減少findViewById的使用次數

盡量減少自己去控制數據源!!(符合MVC設計模式)

貼出代碼, 一般一個完整的Adapter就是下面的格式

public class MyAdapter extends BaseAdapter{
   private final LayoutInflater inflater;
   private Context context;
   private List list;

   public MyAdapter(Context context, List list) {
       this.context = context;
       this.list = list;
       inflater = LayoutInflater.from(context);
   }
   @Override
   public int getCount() {
       return list.size();
   }

   @Override
   public Object getItem(int position) {
       return list.get(position);
   }

   @Override
   public long getItemId(int position) {
       return position;
   }

   @Override           //位置        //重復利用的控件    //父控件
   public View getView(int position, View convertView, ViewGroup parent) {
       if (convertView == null) {
           convertView = inflater.inflate(R.layout.item, parent, false);
           convertView.setTag(new ViewHolder(convertView));
       }
       ViewHolder holder = (ViewHolder) convertView.getTag();
       Entry entry = list.get(position);
       ImageUtil.loadImage(holder.image, "http://tnfs.tngou.net/image" + entry.getImgURL());
       return convertView;
   }

   //批量添加
   public void addAll(Collection collection){
       list.addAll(collection);
       notifyDataSetChanged();
   }
   //數據清理
   public void clear() {
       list.clear();
       notifyDataSetChanged();
   }
   //就是View的持有
   public static class ViewHolder {
       private final TextView text;
       private final ImageView image;

       public ViewHolder(View itemView) {
           text = ((TextView) itemView.findViewById(R.id.item_tv));
           image = ((ImageView) itemView.findViewById(R.id.item_iv));
       }
   }
}

到目前為止我們可以解決顯示本地圖片問題, 但是我們加載網絡數據(尤其是圖片)還是有問題的

解決item顯示圖片錯位的問題和圖片緩存問題 (Lru算法緩存機制)

細心的朋友會發現, 在上面的代碼中, 有下面一句 :

ImageUtil.loadImage(holder.image, "http://tnfs.tngou.net/image" + entry.getImgURL());

裡面的代碼已經解決了這個問題, 我將會把源碼上傳到雲盤供大家下載, 我在源碼中已經加上了注釋 https://yunpan.cn/cMzI4y8SykZrR 訪問密碼 e1dc

自己封裝BaseAdapter

BaseAdapter中有很多代碼都可以復用, 所以我們寫一個通用的Adapter

package com.lulu.day26_listview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.net.IDN;
import java.util.Collection;
import java.util.List;

/**
 * Created by Lulu on 2016/9/2.
 */
public abstract class CommonAdapter extends BaseAdapter {

    private final LayoutInflater inflater;
    private Context context;
    private int layoutId;
    //數據源
    private List list;

    public CommonAdapter(Context context, int layoutId, List list) {
        this.context = context;
        this.layoutId = layoutId;
        this.list = list;
        inflater = LayoutInflater.from(context);
    }
    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public D getItem(int position) {
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        D d = list.get(position);
        Class aClass = (Class) d.getClass();
        Field id = null;
        try {

            id = aClass.getField("id");

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        if (id == null) {
            try {
                id = aClass.getDeclaredField("id");
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }

        if (id != null) {
            try {
                return (long) id.get(d);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        Method getId = null;
        try {
            getId = aClass.getMethod("getId");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        if (getId == null) {
            try {
                getId = aClass.getDeclaredMethod("getId");
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        if (getId != null) {
            try {
                return (long) getId.invoke(id);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        if (convertView == null) {
            convertView = inflater.inflate(layoutId, parent, false);
            //如何獲取Vh怎樣獲取它的子類呢? 
            Class type = (Class) ((ParameterizedType) getClass()
                    .getGenericSuperclass())
                    .getActualTypeArguments()[0];
            try {
                Constructor constructor = type.getConstructor(View.class);
                Object o = constructor.newInstance(convertView);
                convertView.setTag(o);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        onBindView(list.get(position), (VH) convertView.getTag());
        return convertView;
    }

    public abstract void onBindView(D data, VH holder);
    public static class ViewHolder {
        private View itemView;

        public ViewHolder(View itemView) {
            this.itemView = itemView;
        }
    }

    public void addAll(Collection collection) {
        list.addAll(collection);
        notifyDataSetChanged();
    }
    public void clear() {
        list.clear();
        notifyDataSetChanged();
    }
    public void add(D d) {
        list.add(d);
        notifyDataSetChanged();
    }
    public void add(int index, D d) {
        list.add(index, d);
        notifyDataSetChanged();
    }
    public void remove (D d) {
        list.remove(d);
        notifyDataSetInvalidated();
    }
    public void remove (int index) {
        list.remove(index);
        notifyDataSetInvalidated();
    }
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved