9

I want to figure out the main effectivity issues of the Android layouts and views. I'm doing a research now but maybe somebody has answers already.

I have a RelativeLayout that is populated with views dynamically. Basically, the application loads a forum thread in XML and then renders the discussion tree so each message is displayed in its own group of views. I've decided not to use WebView because I want to implement some client-side functions that should be easier to do on custom views than on HTML page.

However this approach has a major flaw: it's heavy.

The first problem (which I've solved) was nesting of views. This is not an issue now, my layout is almost flat so the maximum depth is 10-12 (counting from the very top PhoneWindow$DecorView, the actual depth depends on data).

Now I've reached the next limit that is somehow connected to (or caused by) resource consumption of the views. After loading the data, the application hangs for a while to build the layout (creates the views and populates them with the data), and the hang time seems to grow linear with the data size; and if the data is large enough, the view will never appear (eventually the system suggests closing the application because it isn't responding).

Now the questions:

  1. Does memory consumption depend significantly on the view class? In other words, is there any major difference between a Button and a TextView, or an ImageView? I can attach a click handler to any view so they don't differ much in usage.

  2. Do background images affect the performance? If the same image is set in N views, will it make the layout N times heavier? (I understand that this question may look silly but anyway.)

  3. Are nine-patch images significantly heavier than regular ones? What is better: to create N views where each has some background images, or to make one view that is N times wider and has a repeating background?

  4. Given some layouts, what should be optimized first: overall number of views, nesting levels, or something else?

  5. The most interesting. Is that possible to measure or at least estimate the resources consumed by the activity and its views? If I make some change, how could I see that I'm going the right way?

UPDATE

Thanks to User117, some questions that I asked above are now answered. I've used the Hierarchy Viewer and optimized my layout: compared to what I had before, the overall number of views is now reduced almost twice, and the nesting is also reduced.

However the application still hangs on a large forum thread.

UPDATE 2

I've connected the debugger to my device and found that the application gets out of memory.

But what is very unexpected for me is that the error occurs after I populate the layout. The sequence is as follows:

  1. All my views are added. I can see a slight slow down as they are being added.
  2. Almost nothing happens for a couple of seconds. During that time, a few info messages are spawned in the log, they are identical: [global] Loaded time zone names for en_US in XXXXms, the only difference is number of milliseconds.
  3. The out of memory error message is spawned: [dalvikvm-heap] Out of memory on a N-byte allocation (the actual size varies). The long error reporting starts.

What does this mean? Looks like the rendering have its own demands that may be considerable.

UPDATE 3

At last I've found the core issue. Here is a screenshot from my application, see an explanation below the image.

A tree-like hierarchy of messages.

Each message consists of a round button that shows or hides the replies and a red content frame to the right of the button. This is very simple and requires only 6 views including the layouts.

The problem is the indentation with these connection lines that show which message is related to which.

In my current implementation, the indentation is built of small ImageView's, each containing a square image that shows either empty space, or a vertical line, or a T-like connector, or a L-like corner. All these views are aligned to each other within the large RelativeLayout that holds the whole discussion tree.

This works fine for small and medium trees (up to few hundreds of messages), but when I try to load a large tree (2K+ messages), I get the result explained in UPDATE 2 above.

Obviously, I have two problems here. I spawn large number of views that all consume memory, and these views are ImageView's that require more memory for rendering because they render a bitmap and therefore create graphics caches (according to explanation given by User117 in the comments).

I tried disabling loading the images into the indentation views but got no effect. It seems like adding that huge number of views is quite enough to eat all available memory.

My other idea was to create an indentation image for each message that would contain all pipes and corners, so each message would have the only indentation view instead of 10 or 20. But this is even more consuming: I've got out of memory in the middle of populating the layout. (I cached the images in a map so two bitmaps with identical sequence of images weren't created, that didn't help.)

So I'm coming to conclusion that I'm in a dead end. Is it ever possible to draw all these lines at once?

4

1 回答 1

8
  1. 不同View的是不同种类的 Object。有些只有draw()轻量级的东西,有些可以容纳大型位图对象和处理程序对象等。所以,是的,不同View的会消耗不同数量的 RAM。

  2. 如果视图之间共享相同的 Bitmap 对象,RAM 中只有一个对象,每个视图将有一个指向该对象的引用变量。但是,当视图绘制时并非如此:在屏幕上的 n 个位置绘制相同的位图 n 次将消耗 n 倍 CPU 并bitmap_cache为每个视图生成 n 个不同的位图。

  3. 9 块图像的每一侧实际上比原始图像大 2 个像素。它们与文件没有太大区别。绘制它们时,两者都可以缩放并且占用几乎相等的空间。唯一的区别是 9-Patch 的缩放比例不同。

    1. 当子视图是透明的时,设置较大的父视图的背景会更好,并且背景会显示出来。

    2. 您可以保存小图像并设置平铺背景,以便它可以填充大区域。

  4. 首先要优化嵌套,因为在给定时间可能无法看到所有视图,假设在滚动布局中只有少数视图可见。然后,您可以减少使用的视图总数。从中获取提示ListView:鉴于用户一次只会看到总数据的子集,它会重新循环视图。并节省大量资源。

  5. SDK为此提供了Hierarchy Viewer工具。它显示了正在运行的布局的完整树结构,还为布局的缓慢部分放置了危险信号。

一个好的布局是:

  1. 易于测量(避免复杂的加权宽度、高度和对齐方式)。例如,不是layout_gravity="left"为每个孩子做,父母可以有gravity="left".

  2. 深度较小,每个重叠视图都会在绘制屏幕时添加另一个要合成的图层。每个嵌套的视图结构都要求链式布局调用。

  3. 是聪明的并且重新循环视图而不是创建所有视图。

  4. 重用它的部分:标签,如<merge><include>

更新:这个问题的 答案,在 android 中展示了许多树视图的方法。

于 2013-03-06T06:40:30.290 回答