【问题标题】:What's the quickest way to add several views to a LinearLayout?向 LinearLayout 添加多个视图的最快方法是什么?
【发布时间】:2012-01-22 08:42:54
【问题描述】:

我有一个LinearLayout 视图,其中已经包含多个元素。我想以编程方式向它添加更多视图。因为这是在ScrollView 内,所以所有内容都会滚动。

所以我要做的是浏览我的列表,并将我的自定义视图的新实例添加到其中。该自定义视图扩展了 XML 布局并添加了一些方法。

这种方法效果很好。问题是它非常慢,即使没有任何疯狂的代码……一个包含 10 个项目的列表需要大约 500 毫秒来实例化。从用户体验的角度来看,这很难接受。

我的问题是,这是正确/最好的方法吗?尽管“R.layout.my_list_item”非常简单,但 Android 似乎需要花费大量时间来扩充布局。我想知道是否有一种方法可以将“膨胀”布局重用于其他视图,有点缓存更复杂的解析?

我已经尝试使用ListView(以及适配器和包装器)来执行此操作,它似乎要快得多。问题是我不能使用简单的ListView;我的布局比一个简单的列表更复杂(LinearLayout 本身包含额外的自定义图标,并且在被ScrollView 包裹之前,它还有另一个父级具有更多视图)。

但是有没有办法为 LinearLayout 使用适配器?这会比尝试自己添加视图更快吗?

感谢任何帮助。我很想加快速度。

代码如下。

主要活动:

// The LinearLayout that will contain everything
lineList = (LinearLayout) findViewById(R.id.lineList);

// Add a lot of items for testing
for (int i = 0; i < 10; i++) {
    addListItem("Item number " + i);
}

protected void addListItem(String __title) {
    MyListItem li;
    li = new MyListItem(this);
    li.setTitle(__title);
    lineList.addView(li);       
}

我的列表项:

public class MyListItem extends RelativeLayout {

    protected TextView textTitle;

    public MyListItem(Context __context) {
        super(__context);
        init();
    }

    public MyListItem(Context __context, AttributeSet __attrs) {
        super(__context, __attrs);
        init();
    }

    public MyListItem(Context __context, AttributeSet __attrs, int __attrsdefStyle) {
        super(__context, __attrs, __attrsdefStyle);
        init();
    }

    protected void init() {
        // Inflate the XML layout
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.my_list_item, this);

        // Create references
        textTitle = (TextView)findViewById(R.id.textTitle);
    }

    public void setTitle(String __text) {
        textTitle.setText(__text);
    }
}

我想要完成的是这个。考虑这种布局:

此布局是一个FrameLayout(外框),其中包含一个ImageView(灰色)、一个TextView(内部矩形,在顶部)和一个LinearLayout(内部矩形,在底部)。这个LinearLayout 矩形是我动态填充的几个项目。

填充后,我希望最终结果是这样的(每个新矩形都是一个新的MyListItem 实例):

也就是说,一切都是可滚动的(例如,背景图像在顶部对齐)。 LinearLayout 本身不能滚动(其他所有内容都在后面),因此据我所知,为什么 ListView 不能很好地工作 就我而言。

【问题讨论】:

  • 该活动中有多少个元素,是否有任何自定义类继承 UI 元素?
  • ListViews 如此之快,因为它们回收了项目布局。他们夸大了填满屏幕所需的项目布局数量。向下滚动时,顶部的一个视图被隐藏,底部的一个视图被显示。列表视图从顶部获取旧的、不可见的视图,并将新数据放在底部。避免昂贵的通货膨胀。总的来说:这里看起来非常效率低下,我很确定你想做的任何事情都可以通过列表视图来完成。如果您展示您尝试过的内容并发布您的预期布局草图,我们可以帮助您解决这个问题。
  • 保罗:元素不多。也许是 4 或 5 个。是的,其中一些是从基本框架继承的自定义类。 alexsc:感谢您的解释。我添加了一个图表,可以更好地解释我的情况,因此很清楚我是否以及如何使用 ListView 代替(或不)。
  • @zeh:这可能没有多大帮助,但您每次在init() 中“获得”LayoutInflater 的事实可能会为每次通话增加相当多的时间。我会在主要活动中获得一次充气机,然后将对它的引用传递给init()。这样,您只需调用一次getSystemService(Context.LAYOUT_INFLATER_SERVICE),并且您也不需要调用getContext(),因为主要活动可以直接执行此操作。只是一个想法 - 它可能会稍微加快速度。
  • @zeh 好吧,我发现这比我最初的要复杂一些。在我写一个长答案之前如何做到这一点:I wrote a short throwaway layout-prototype project with a ListView。看看这是否是大约。你想要的结果。它有点简化:背景不是图像,而是简单的灰色。您可以通过将列表视图android:background 设置为可绘制文件夹(在main.xml 中) 中的图像来更改它。列表项也是简单的默认项。这可以通过使用自定义适配器轻松更改。

标签: android layout view android-linearlayout inflate


【解决方案1】:

ListView 是要走的路。

你说你的布局太复杂了。但是小时候给复杂的布局充气是完全可以的。例如一个包含文本和图标的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >
    <TextView
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" />
    <ImageView 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" />
</LinearLayout>

可以像这样在您的适配器中充气:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    LinearLayout root = null;
    ImageView editImageView;

    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        root = (LinearLayout)inflater.inflate(R.layout.item, null);
    } else {
        root = (LinearLayout)convertView;
    }
}

您也可以更聪明一点来支持标题。只需添加检查索引是否为根并膨胀不同的视图。由于标题是唯一不同的标题,您仍然可以利用所有其他可重复使用的行。您甚至可以预先膨胀并存储标头并重复使用它以完全摆脱通货膨胀。

【讨论】:

  • 谢谢。但请注意,我说布局“比简单列表更复杂”,而不是“太复杂”(布局本身很简单)。我不会有膨胀整个事情的问题。问题是我看不到如何使我的布局与ListView 上的标题一起工作,考虑到列表后面有元素(我的图表中的图像)。我可以将图像附加到 ListView 的顶部但在子元素下吗?
【解决方案2】:

只需使用 ListView!

这是最容易设置和最容易维护的。您为 List-Row 定义一个 XML 布局,并为包含整个 List 的 View 定义一个 XML 布局。 ListAdapter 会为您完成其余的工作。

只需创建一个:

List<HashMap<String, String>> services = new ArrayList<HashMap<String, String>>();

...并循环遍历您的数据以向地图添加任意数量的项目。然后将此映射设置为您的 ListAdapter。无论是 10 个项目还是 100 个项目,ListAdapter 都会创建一个包含那么多项目的列表。

例子:

    public void updateProductList(String searchTerm) {
        createOrOpenDB(this);
        Cursor cursor = (searchTerm!=null)? dbAdapter.fetchWhere(TBL_NAME, KEY_NAME+" LIKE '%"+searchTerm+"%'")
                : dbAdapter.fetchAll(TBL_NAME);
        int rows = cursor.getCount();
        if (rows<=0) return;
        services.clear(); //clear current list
        for (int i=0; i<rows; i++) {
            HashMap<String, String> map = new HashMap<String, String>();
            cursor.moveToPosition(i);
            map.put(KEY_NAME, "" + cursor.getString(cursor.getColumnIndex(KEY_NAME)));
            map.put(KEY_DESC, "" + cursor.getString(cursor.getColumnIndex(KEY_DESC)));
            map.put(KEY_COST, "" + cursor.getDouble(cursor.getColumnIndex(KEY_COST)));
            services.add(map);
        }
        cursor.close();
        closeDB();

        ListAdapter adapter = new SimpleAdapter(this, services, R.layout.products_view_row,
                new String[] {KEY_NAME, KEY_DESC, KEY_COST},
                new int[] {R.id.listViewText1, R.id.listViewText2, R.id.listViewText3});
        setListAdapter(adapter);
    }

【讨论】:

  • 谢谢。但是,我在同一应用程序的其他部分创建了一个带有适当适配器的ListView,因此问题不在于实现ListView。我在这里不使用 ListView 的原因是因为它似乎没有完成我需要的东西(并行滚动其他非列表、非标题元素)。我很想被证明是错误的,但答案比“只使用列表视图”更复杂。
  • 哦,我明白了。那么你想要的是:stackoverflow.com/questions/3192595/…(见接受的答案)加上一个 ScrollView 来封装你的整个布局。
  • 呃,就像我在原帖中所说的那样,这正是我正在做的,但我遇到了性能问题(手动将项目添加到 LinearLayout 很慢)。
  • 哦,对了。您是否使用 AsyncTask 在后台运行此循环?您可以通过 * 使用 Handler.post() 方法发布列表项。这应该有助于提高性能?
  • 是的,这就是我现在正在为类似列表做的事情(我在应用程序上有几个类似的列表):我只创建初始视口所需的前几个项目,但后来我有了在后台填充列表其余部分的线程。我正在使用 Handlers 和 Runnables 和 Threads,但不知道 AsyncTask - 听起来更好,谢谢!
【解决方案3】:

3 个选项:

  1. 将所有内容替换为 ListView,将其他父图标和自定义图标作为 ListView 的标题视图。 ListView 更快,因为它只在需要时创建视图。

  2. 以编程方式创建 my_list_item 的内容而不是膨胀,可能会更快

  3. 使用ViewStubs 可以让您按需加载视图。

  4. 也许加载的不是视图而是数据?在这种情况下,在后台线程中准备数据。

【讨论】:

  • 感谢您的直截了当、实际的回复。我会在列表中添加“在单独的线程上创建视图”(正如 user1031312 在下面的评论中建议的那样)。除此之外,我认为您很好地总结了可能的解决方案。
猜你喜欢
  • 1970-01-01
  • 2023-03-25
  • 2015-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-28
  • 1970-01-01
  • 2021-08-30
相关资源
最近更新 更多