Reputation: 257
I have dynamic and quite large contents which needs to be populated on user interaction (click next / prev page).
The dynamic contents displayed programmatically on myTableLayout (see xml below). Each time user clicked next/prev
page then I call myTableLayout.removeAllViews()
, do some stuff and repopulate with myTableLayout.addView()
.
On small contents it draws quite fast, but I notice two to three seconds lag if populating large contents.
I already saw an application that do same functionality as mine (also with quite large contents) but it really paging so fast even on low-end device.
Need some advice on how to increase the layout performance.
Thanks.
Note: Upper TableLayout used as title (header), LinearLayout below it is where the contents placed.
<TableLayout
android:layout_width="fill_parent"
android:layout_height="45dip"
android:stretchColumns="0,2"
android:shrinkColumns="0,2"
>
<TableRow>
<LinearLayout
android:id="@+id/llLeft"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/tvLeft1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/llCenter"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/tvCenter1"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
/>
<TextView
android:id="@+id/tvCenter2"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/llRight"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/tvRight1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
</TableRow>
</TableLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<com.MyScrollView
android:id="@+id/myScrollView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<TableLayout
android:id="@+id/**myTableLayout**"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:shrinkColumns="1"
android:stretchColumns="1"
/>
</com.MyScrollView>
</LinearLayout>
Here is the code that create the dynamic content. The content fetched from memory (ArrayList) so it should not be the problem.
private void gotoPage() {
myTableLayout.removeAllViews();
GlobalVar g = GlobalVar.getInstance();
ArrayList<String> arrScripts = g.getDatasMap().get(SCRIPT_INDEX);
ArrayList<String> arrTrans = g.getTranslationMap().get(SCRIPT_INDEX);
Log.i(APP_NAME, "finished preparing data");
try {
// Data Title
tvCenter1.setText(arrScripts.get(0));
tvCenter2.setText(" (" + SCRIPT_INDEX + ")");
int countScripts = arrScripts.size();
for(int i=1; i<countScripts; i++) {
// Row Script
TableRow trScript = new TableRow(this);
trScript.setPadding(0, 5, 0, 0);
TextView tvIndex = new TextView(this);
tvIndex.setGravity(Gravity.CENTER);
tvIndex.setWidth(40);
tvIndex.setText("" + i);
TextView tvScript = new TextView(this);
tvScript.setGravity(Gravity.RIGHT);
tvScript.setTypeface(g.getFontTypeFace());
tvScript.setTextSize(FONT_SIZE);
tvScript.setPadding(0, 0, 5, 0);
tvScript.setText(arrScripts.get(i));
trScript.addView(tvIndex);
trScript.addView(tvScript);
TableRow trTrans = null;
if(IS_USE_TRANSLATION) {
// Row Translation
trTrans = new TableRow(this);
TextView tvBlank = new TextView(this);
tvBlank.setPadding(0, 0, 0, 5);
TextView tvTrans = new TextView(this);
tvTrans.setPadding(0, 0, 0, 5);
tvTrans.setText(arrTrans.get(i));
trTrans.addView(tvBlank);
trTrans.addView(tvTrans);
}
// Place for line separator
View vSep = new View(this);
ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
p.height = 3;
vSep.setLayoutParams(p);
// Combine rows to table
if(IS_USE_SCRIPT) myTableLayout.addView(trScript);
if(IS_USE_TRANSLATION) myTableLayout.addView(trTrans);
myTableLayout.addView(vSep);
}
} catch (Exception e) {
Log.e(APP_NAME, e.getMessage());
}
}
Here is the traceview result.
Upvotes: 2
Views: 5996
Reputation: 64399
I agree with @amplify91 that it might be from generating the content, but one of the other things you might want to look at is the number of layouts you are using. The basic thought is "the fewer the better". You can check out some of googles layout tricks
Example: I see your header is a table
with linearlayout
s with textview
s. Couldn't that be fixed by a Relative layout
with the textviews
as children?
You'll save some Views, and also some 'depth' in the layout tree.
Upvotes: 4
Reputation: 4483
If all you want to do is add text in a nicely formatted table format (all columns auto-sized etc), don't use a TableLayout at all and just use something like java.util.Formatter to format text into a table shape. This requires some pre-work like computing the max string length of each column, but in the end resulted in large performance gains as you basically reduce your view usage to a single TextView (~2 seconds to load activity down to almost instant).
For example:
// Compute max string length of each column
for (Entry entry : entries) {
if (entry.column1.length() > column1MaxLength) {
column1MaxLength = entry.column1.length();
}
...
if (entry.columnN.length() > columnNMaxLength) {
columnNMaxLength = entry.columnN.length();
}
}
// Formatter internally stores output string in StringBuilder
Formatter formatter = new Formatter();
// Construct table header
formatter.format("%1$" + column1MaxLength + "s", "Column 1 Title");
...
formatter.format("%1$" + columnNMaxLength + "s", "Column N Title");
// Add each entry into table
for (Entry entry : entries) {
formatter.format("%1$" + column1MaxLength + "s", entry.column1.value);
...
formatter.format("%1$" + columnNMaxLength + "s", entry.columnN.value);
}
// Get string representing formatted table from Formatter and put into TextView
textView.setText(formatter.toString());
Upvotes: 0
Reputation: 4511
To put it simply, get rid of TableLayout and TableRow and TextView altogether!
If you collect profiling data from Eclipse, you'll see that most of the CPU/real time is spent in the addView() method from the TabletLayout and also the TextView. calls!
Each time I've replaced a TableLayout and TextView with custom implementations it resulted in a HUGE performance gain!
TextView should be replaced by custom View, TableLayout by custom ListView.
EDIT: I have created a few custom views depending on my needs. To put it simply I've overwritten the View class with onDraw() and onMeasure() methods:
In below code, the painter is created once in the static constructor, so are textBaseline and textHeight as I'm using a single font size for all those custom "text" views.
@Override
protected void onDraw(Canvas canvas)
{
final int width = getWidth();
final float size = painter.measureText(innerText);
canvas.drawText(innerText, width - size - 5, textBaseline, painter);
if (underline)
{
canvas.drawLine(0, canvas.getHeight() - 1, canvas.getWidth(), canvas.getHeight() - 1, painter);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int w = MeasureSpec.getSize(widthMeasureSpec);
int h = MeasureSpec.getSize(heightMeasureSpec);
if (innerText != null && painter != null)
{
switch (MeasureSpec.getMode(widthMeasureSpec))
{
case MeasureSpec.EXACTLY:
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
w = (int)( (painter.measureText(innerText) + 5) );
break;
}
}
switch (MeasureSpec.getMode(heightMeasureSpec))
{
case MeasureSpec.EXACTLY:
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
h = (int)( textHeight );
break;
}
setMeasuredDimension(w, h);
}
Upvotes: 2
Reputation: 30934
I think you should surround your code by Debug.startMethodTracing("xx")
and Debug.stopMethodTracing()
calls and then use traceview
to find out what is going on. Everything else is just guesswork.
Upvotes: 1
Reputation: 2660
I would say that the delay isn't in building the layout from XML, but from generating your dynamic content. What kind of content is it? Could you post some of your code? If you're accessing it from a website you may want to pre-fetch it. If you're creating when you change pages, it could be in how you're creating it.
Upvotes: 0