在创建自己的自定义适配器时,getView()方法如何工作?

时间:2012-04-12 08:38:20

标签: android android-arrayadapter android-view layout-inflater

我的问题是:

  1. LayoutInflater的功能究竟是什么?
  2. 为什么我读过的所有文章都会检查convertview是否为空?当它为空时它意味着什么?它不是什么意思?
  3. 此方法接受的父参数是什么?

9 个答案:

答案 0 :(得分:114)

1:LayoutInflater获取布局XML文件,并从其内容创建不同的View对象。

2:构建适配器以重用视图,当滚动视图使其不再可见时,它可用于出现的新视图之一。这个重用的View是convertView。如果这是null,则意味着没有回收的View,我们必须创建一个新的View,否则我们应该使用它来避免创建新的。

3:提供了parent,因此您可以将视图扩展为正确的布局参数。

所有这些可以用于有效地创建将出现在列表中的视图(或带有适配器的其他视图):

public View getView (int position, View convertView, ViewGroup parent){
    if( convertView == null ){
        //We must create a View:
        convertView = inflater.inflate(R.layout.my_list_item, parent, false);
    }
    //Here we can do changes to the convertView, such as set a text on a TextView 
    //or an image on an ImageView.
    return convertView;
}

请注意LayoutInflater的使用,parent可用作参数,以及convertView如何重复使用。

答案 1 :(得分:67)

适配器中的

getView()方法用于生成ListViewGallery的项目视图,...

  1. LayoutInflater 用于获取您在布局xml中定义的View对象(根对象,通常为LinearLayoutFrameLayoutRelativeLayout

  2. convertView 用于回收。假设您有一个列表视图,一次只能显示10个项目,目前它是 显示项目1 - >项目10.当您向下滚动一个项目时, 项目1将在屏幕外,并将显示项目11。至 为项目11生成View,将调用getView()方法,并且 convertView这里是第1项的观点(这不是必要的 了)。因此,为项目11创建一个新的View对象(即 昂贵的),为什么不重用convertView? =>我们只检查convertView是 是否为null,如果为null,则创建新视图,否则重复使用convertView

  3. parentView 是ListView或Gallery ...,其中包含getView()生成的项目视图。

  4. 注意:你不直接调用这个方法,只需要实现它来告诉父视图如何生成项目的视图。

答案 2 :(得分:8)

您可以查看有关列表视图的视频。它来自去年的谷歌IO,并且仍然是我脑海中最佳的列表视图。

http://www.youtube.com/watch?v=wDBM6wVEO70

  1. 它将布局(res / layout /文件夹中的xml文件)扩展为java对象,如LinearLayout和其他视图。

  2. 看一下视频,会告诉你最新的转换视图是什么,基本上它是一个等待你重复使用的循环视图,以避免创建一个新对象并减慢滚动你的清单。

  3. 允许您从适配器引用列表视图。

答案 3 :(得分:5)

  

LayoutInflater的功能究竟是什么?

使用XML进行设计时,所有UI元素都只是标签和参数。在使用这些UI元素(例如TextView或LinearLayout)之前,需要创建与这些xml元素对应的实际对象。这就是inflater的用途。 inflater使用这些标签及其相应的参数来创建实际对象并设置所有参数。在此之后,您可以使用findViewById()获取对UI元素的引用。

  

为什么我读过的所有文章都会检查convertview是否为null?当它为空时它意味着什么?它不是什么意思?

这是一个有趣的问题。你看,每次绘制列表中的项目时都会调用getView()。现在,在绘制项目之前,必须创建它。现在convertView基本上是最后一个用于绘制项目的视图。在getView()中,首先对xml进行膨胀,然后使用findByViewID()来获取listitem的各种UI元素。当我们检查(convertView == null)时,我们要做的是检查一个视图是否为null(对于第一个项目)然后创建它,否则,如果它已经存在,重用它,不需要再次通过膨胀过程。使它更有效率。

您还必须在getView()中遇到ViewHolder的概念。这使列表更有效。我们所做的是创建一个视图,并存储我们在充气后获得的所有UI元素的引用。这样,我们可以避免调用众多的findByViewId()并节省大量时间。此ViewHolder在(convertView == null)条件下创建,并使用setTag()存储在convertView中。在else循环中,我们只需使用getView()获取它并重用它。

  

此方法接受的父参数是什么?

父级是最终附加了由getView()创建的视图的ViewGroup。现在在你的情况下,这将是ListView。

希望这会有所帮助:)

答案 4 :(得分:4)

  1. 布局充气器会将外部XML扩展/添加到当前视图中。

  2. 多次调用getView(),包括滚动时。因此,如果它已经有了膨胀的观点我们不想再这样做,因为膨胀是一个代价高昂的过程。这就是为什么我们检查它是否为空然后膨胀它。

  3. 父视图是列表的单个单元格。

答案 5 :(得分:2)

LayoutInflater用于为ListView项或片段的onCreateView生成XML的动态视图。

ConvertView主要用于回收当前不在视图中的视图。假设你有一个可滚动的ListView。向下或向上滚动时,convertView会显示滚动的视图。这种重用可以节省内存。

getView()方法的parent参数提供对具有listView的父布局的引用。假设您想获得可以使用的父XML中任何项目的ID:

ViewParent nv = parent.getParent();

while (nv != null) {

    if (View.class.isInstance(nv)) {
        final View button = ((View) nv).findViewById(R.id.remove);
        if (button != null) {
            // FOUND IT!
            // do something, then break;
            button.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    Log.d("Remove", "Remove clicked");

                    ((Button) button).setText("Hi");
                }
            });
        }
        break;
    }

 }

答案 6 :(得分:1)

getView()方法为View或Spinner的每一行创建新的ViewGroupListview。您可以在View文件夹中的ViewGroup文件中定义此Layout XMLres/layout,并可以将其引用到Adapter类对象。

如果您将数组中的4项传递给适配器。 getView()方法将为4行Adaper创建4个View。

LayoutInflater类有一个方法inflate(),它从XML资源布局创建View对象。

答案 7 :(得分:0)

您还可以在Adapter.java文件的Adapter接口中找到有关getView的有用信息。 它说;

    /**
 * Get a View that displays the data at the specified position in the data set. You can either
 * create a View manually or inflate it from an XML layout file. When the View is inflated, the
 * parent View (GridView, ListView...) will apply default layout parameters unless you use
 * {@link android.view.LayoutInflater#inflate(int, android.view.ViewGroup, boolean)}
 * to specify a root view and to prevent attachment to the root.
 * 
 * @param position The position of the item within the adapter's data set of the item whose view
 *        we want.
 * @param convertView The old view to reuse, if possible. Note: You should check that this view
 *        is non-null and of an appropriate type before using. If it is not possible to convert
 *        this view to display the correct data, this method can create a new view.
 *        Heterogeneous lists can specify their number of view types, so that this View is
 *        always of the right type (see {@link #getViewTypeCount()} and
 *        {@link #getItemViewType(int)}).
 * @param parent The parent that this view will eventually be attached to
 * @return A View corresponding to the data at the specified position.
 */
View getView(int position, View convertView, ViewGroup parent);

答案 8 :(得分:0)

如果要将视图传递给函数(作为参数),您可以先定义一个元素,例如框架布局:

FrameLayout frameLayout = findViewById(R.id.frame_layout);

然后获取元素的视图:

 frameLayout.getRootView();