Android学习—ListView由浅入深

【转载】http://www.cnblogs.com/ryan-ys/p/4751375.html

前段时间学习了RecyclerView,发现对ListView有更加明显的感觉,于是决定把之前理清点思路的ListView,整理整理毕竟在5.0普及之前,ListView还是有用武之地的。一如既往的我们从简单的开始。——站在巨人的肩膀之上

译自:https://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView#using-a-basic-arrayadapter,可能本人理解不深,翻译偏生硬,带我多敲几遍,再来几篇供大家分享。

Using an ArrayAdapter with ListView

在android的开发中,我们经常会使用ListView来展示一组垂直滚动列表的需求,这时我们会使用Adapter填充数据。最简单的Adaper是Arrayadapter,因为这个适配器把ArrayList的对象转变为View列表,从而被加载到ListView的容器中。

                  

Row View Recycling

  当使用Adapter和ListView时,我们要确保明白,View的回收机制是怎样工作的。

  当你的ListView与adapter进行联系是,adapter将会实例每一行列表,直到ListView被充足的items填充(items填充ListView的总高度),在这种情况下,不会有多余的行列表的对象再在内存当中创建。

  取而代之的是,当用户向下滚动列表的时候,离开屏幕的Items将会保存到内存当中供之后使用,进而,每一个新的行列表进入屏幕时,将会复用保存在内存当中的行列表。如此,即使有1000个列表的List,仅仅需要大约7个行列表的视图需要被实例化,或者保存在内存中,这是回收的直观概述:

                

  这是另一张回收视图相关图。

                 

  请参阅另一个本指南的ListView(个人觉得有更好的选择,以后会写博客),看看这是如何工作来优化你的列表的性能。

Using a Basic ArrayAdapter

为了使用基本的 ArrayAdaper,我们仅仅需要去实例化一个adapter,并且将该适配器连接到ListView。第一步,我们初始化一个adapter。

Adapter<String> itemsadapter = new ArrayAdapter<String> (this,android.R.layout.simple_list_item_1,items);

ArrayAdapter需要去声明item当被转换为View时的类型(a String in this case),进而接收三个参数:context(activity实例),XML item layout,and the array date。注意我们选择了

simple_list_item_1,她是一个简单用TextView作为布局,为每一个Items。

现在,我们需要这个适配器连接到ListView进行填充,

ListView listView = (ListView) findViewById(R.id.lvItems);
listView.setAdapter(itemsAdapter);

By default, this will now convert each item in the data array into a view by callingtoString on the item and then assigning the result as the value of a TextView(simple_list_item_1.xml) that is displayed as the row for that data item。(实在翻译不来,自己意会吧,求好心人指导翻译)。如果你的应用程序需要更加复杂的转变在Item和View之中,那我们需要创建自定义的ArrayAdapter来取代之。

Using a Custom ArrayAdapter(准备数据模版,视图模版)

当我们想要在List里展示你一系列的自定义的列表,我们需要给每一个Items使用,我们自定义的XML layout文件。为了完成这一步,我们要创建自定义的ArrayAdapter的类。 See this repo for the source code.

第一步,我们经常会定义一个模版,去描述List里每一个Item所需要的数据。

  Defining the Model

创建一个Java对象,来定义某些字段,,例如, User class

public class User {
    public String name;
    public String hometown;

    public User(String name, String hometown) {
       this.name = name;
       this.hometown = hometown;
    }
}

  Creating the View Template

下一步,我们需要创建一个XML 布局文件,来代表每一个Item的模版,res/layout/item_user.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent" >
    <TextView
      android:id="@+id/tvName"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Name" />
   <TextView
      android:id="@+id/tvHome"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="HomeTown" />
</LinearLayout>

  Defining the Adapter

下一步,我们需要去定义Adapter并且去描述,Java对象转变为View的过程(在 getView 方法中)。稚嫩的方法如下(没有任何缓存):

public class UsersAdapter extends ArrayAdapter<User> {
    public UsersAdapter(Context context, ArrayList<User> users) {
       super(context, 0, users);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
       // Get the data item for this position
       User user = getItem(position);
       // Check if an existing view is being reused, otherwise inflate the view
       if (convertView == null) {
          convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_user, parent, false);
       }
       // Lookup view for data population
       TextView tvName = (TextView) convertView.findViewById(R.id.tvName);
       TextView tvHome = (TextView) convertView.findViewById(R.id.tvHome);
       // Populate the data into the template view using the data object
       tvName.setText(user.name);
       tvHome.setText(user.hometown);
       // Return the completed view to render on screen
       return convertView;
   }
}

Adapter有一个 构造和getView()的方法去描述 数据项和视图之间的转变。

getView()是返回在特定位置用作排在ListView内的实际视图的方法。

Attaching the Adapter to a ListView

现在,我们可以在Activity里使用那个Adapter,去展示Items的数组嵌入到ListView中:

// Construct the data source
ArrayList<User> arrayOfUsers = new ArrayList<User>();
// Create the adapter to convert the array to views
UsersAdapter adapter = new UsersAdapter(this, arrayOfUsers);
// Attach the adapter to a ListView
ListView listView = (ListView) findViewById(R.id.lvItems);
listView.setAdapter(adapter);

此刻,ListView控件现在已经成功绑定到用户数组数据。

Populating Data into ListView

一旦适配器连接,Items都将自动填充到ListView中,基于数组中的内容。

我们可以添加新的Item到适配器中:

// Add item to adapter
User newUser = new User("Nathan", "San Diego");
adapter.add(newUser);
// Or even append an entire new collection
// Fetching some data, data has now returned
// If data was JSON, convert to ArrayList of User objects.
JSONArray jsonArray = ...;
ArrayList<User> newUsers = User.fromJson(jsonArray)
adapter.addAll(newUsers);

这将会追加新的Items到List中。我们也可以清除所有的List在任何时候,只要一句:

adapter.clear();

现在我们可以添加,,删除,修改用户并且ListView中的Items会自动的做出相应的反射。

Constructing Models from External Source(从外部源构建模型)

为了创建模型实例,我们可能从外部源加载数据(即数据库或者REST JSON API),所以我们应该在每个模型中创建2个额外的方法,允许构建一个List或者但单一的Item如果数据是从JSON API而来的。

public class User {
    // Constructor to convert JSON object into a Java class instance
    public User(JSONObject object){
        try {
            this.name = object.getString("name");
            this.hometown = object.getString("hometown");
       } catch (JSONException e) {
            e.printStackTrace();
       }
    }

    // Factory method to convert an array of JSON objects into a list of objects
    // User.fromJson(jsonArray);
    public static ArrayList<User> fromJson(JSONArray jsonObjects) {
           ArrayList<User> users = new ArrayList<User>();
           for (int i = 0; i < jsonObjects.length(); i++) {
               try {
                  users.add(new User(jsonObjects.getJSONObject(i)));
               } catch (JSONException e) {
                  e.printStackTrace();
               }
          }
          return users;
    }
}

For more details, check out our guide on converting JSON into a model. If you are not using a JSON source for your data, you can safely skip this step.

(暂时没遇到过,感觉哼重要的样子)

Improving Performance with the ViewHolder Pattern

To improve performance, we should modify the custom adapter by applying the ViewHolder pattern which speeds up the population of the ListView considerably by caching view lookups for smoother, faster item loading:

public class UsersAdapter extends ArrayAdapter<User> {
    // View lookup cache
    private static class ViewHolder {
        TextView name;
        TextView home;
    }

    public UsersAdapter(Context context, ArrayList<User> users) {
       super(context, R.layout.item_user, users);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
       // Get the data item for this position
       User user = getItem(position);
       // Check if an existing view is being reused, otherwise inflate the view
       ViewHolder viewHolder; // view lookup cache stored in tag
       if (convertView == null) {
          viewHolder = new ViewHolder();
          LayoutInflater inflater = LayoutInflater.from(getContext());
          convertView = inflater.inflate(R.layout.item_user, parent, false);
          viewHolder.name = (TextView) convertView.findViewById(R.id.tvName);
          viewHolder.home = (TextView) convertView.findViewById(R.id.tvHome);
          convertView.setTag(viewHolder);
       } else {
           viewHolder = (ViewHolder) convertView.getTag();
       }
       // Populate the data into the template view using the data object
       viewHolder.name.setText(user.name);
       viewHolder.home.setText(user.hometown);
       // Return the completed view to render on screen
       return convertView;
   }
}

在这个栗子中中,我们使用了一个 private static class called ViewHolder。在实践当中,调用FindViewById()是真的非常慢,如果你的adapter每次都调用他,为你的每一个行列都去调用她,你会很快发现将会出现性能问题。而ViewHolder这个类所做的事情就是缓存调用FindViewById()这个方法。一旦你的ListView到达它可以在屏幕上显示的行的最大数量,Android会非常聪明的回收这些行的View。我们测试一下,如果既if(convertView == Null)之后,一个View(Item的视图)被回收。如果不是Null的话,我们就有可以使用的回收后的View,并且我们可以改变她的值,否则我们需要擦魂归一个新的行的View。The magic behind this is the setTag() method which lets us attach an arbitrary object onto a View object, which is how we save the already inflated View for future reuse.(在这背后的魔法就是setTag()方法,这个方法能够让我们附属任意的对象到View对象之上,这就是我们如何保存已经实例化的View,供以后使用。

Beyond ViewHolders

Customizing Android ListView Rows by Subclassing describes a strategy for obtaining instances of child views using a similar approach as a ViewHolder but without the explicit ViewHolder subclass.

References

资料查找部分:

http://www.cnblogs.com/xiangtailiang/p/3379543.html

http://www.javacodegeeks.com/2013/09/android-viewholder-pattern-example.html

http://www.codeofaninja.com/2013/09/android-listview-with-adapter-example.html

http://stackoverflow.com/questions/4145602/how-to-implement-a-view-holder

http://stackvoid.com/

时间: 2024-10-06 15:16:46

Android学习—ListView由浅入深的相关文章

Android学习---ListView的点击事件,simpleAdapter和arrayadapter的原理和使用 - Hi_Amos

如题,本文将介绍 listview的点击事件,simpleAdapter和arrayadapter的原理和使用. 1.ListView的注册点击事件 //注册点击事件 personListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { /** * * @param parent 当前ListView * @param view 代表当前被点击的条目 * @param position 当前条目的位置 * @p

Android学习---ListView和Inflater的使用,将一个布局文件转化为一个对象

本文将介绍ListView和Inflater的使用,将接上一篇文章内容. 一.什么是ListView? 在android开发中ListView是比较常用的控件,ListView 控件可使用四种不同视图显示项目,1.大(标准)图标2.小图标3.列表4.报表,比较常用的是列表的形式.ListItem 对象可包含文本和图片.然而,若要使用图片则必须通过 Icons 和 SmallIcons 属性引用 ImageList控件. 本文将接着上一篇文章,将sqlite数据库的数据以列表的形式显示出来. 二.

Android学习---ListView的点击事件,simpleAdapter和arrayadapter,SimpleCursoAdapter的原理和使用

如题,本文将介绍 listview的点击事件,simpleAdapter和arrayadapter的原理和使用. 1.ListView的注册点击事件 //注册点击事件 personListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { /** * * @param parent 当前ListView * @param view 代表当前被点击的条目 * @param position 当前条目的位置 * @p

Android 学习--ListView 的使用(二)

基于ArrayAdapter 创建ListView 程序清单 listview2.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="match_parent" android:l

Android 学习--ListView 的使用(三)

使用SimpleAdapter 创建ListView 程序清单1 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="match_parent" android:layout_height

Android 学习--ListView 的使用(四)

基于BaseAdapter 实现ListView 注意扩展BaseAdapter 需要重写以下四个方法 getCount(); getItem(); getItemId(); getView(); 程序清单 package xiaocool.net.listviewtest; import android.graphics.Color; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; impor

Android学习--ListView

这篇文章用于总结自己这两天学到的安卓的ListView和RecyclerView 的笔记,以及从我这个iOS开发者的角度去理解和学习这两个控件,会比较一下他们个iOS中那些控件是一致的,可以用来对比的. 一:ListView 最简单的用法 ListView最简单的用法无非就是用它写一个最基本的列表界面,展示的数据也就是我们最基本和常见的单条数据,一步一步的走下去: ListView的创建,先说说它的布局的创建,直接代码了,很简单的一个ListView的宽.高和id: 布局文件创建完之后就是我们的

Android 学习--ListView 的使用(一)

基于数组的ListView listview1.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="match_parent" android:layout_height=&quo

Android学习系列(17)--App列表之圆角ListView(续)

http://www.cnblogs.com/qianxudetianxia/archive/2011/09/19/2068760.html 本来这篇文章想并到上篇Android学习系列(16)--App列表之圆角ListView中的,但是若是如此就让大家错过一篇新的好的文章,着实可惜.上篇中我们使用shape,corners,gradient实现了一个渐变的圆角效果,但是在完文之后的实践中,我发现有时效果不甚满意,选中和放手的事件监听没有去正确的判断,然后渐变效果也比较单一,性能也觉得不是很快