Note that there are some explanatory texts on larger screens.

plurals
  1. POAndroid onLayout() and AsyncTask() does not work together
    primarykey
    data
    text
    <p>I need a scrollable table with fixed header, so I followed <a href="http://blog.stylingandroid.com/archives/432" rel="nofollow noreferrer">this great blog</a> and everything is fine. </p> <p>The idea is using one table for header, one table for content added in scrollview, both of them are in a customized LinearLayout. In customized LinearLayout, we will overwrite the onLayout() to get the max width of each row and set width for each row of both header and content table. </p> <p>Here is the activity and its layout: </p> <pre><code>package com.stylingandroid.ScrollingTable; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.widget.LinearLayout; import android.widget.TableLayout; import android.widget.TableRow; public class ScrollingTable extends LinearLayout { public ScrollingTable( Context context ) { super( context ); } public ScrollingTable( Context context, AttributeSet attrs ) { super( context, attrs ); } @Override protected void onLayout( boolean changed, int l, int t, int r, int b ) { super.onLayout( changed, l, t, r, b ); TableLayout header = (TableLayout) findViewById( R.id.HeaderTable ); TableLayout body = (TableLayout) findViewById( R.id.BodyTable ); if (body.getChildCount() &gt; 0 ) { TableRow bodyRow = (TableRow) body.getChildAt(0); TableRow headerRow = (TableRow) header.getChildAt(0); for ( int cellnum = 0; cellnum &lt; bodyRow.getChildCount(); cellnum++ ){ View bodyCell = bodyRow.getChildAt(cellnum); View headerCell = headerRow.getChildAt(cellnum); int bodyWidth = bodyCell.getWidth(); int headerWidth = headerCell.getWidth(); int max = Math.max(bodyWidth, headerWidth); TableRow.LayoutParams bodyParams = (TableRow.LayoutParams)bodyCell.getLayoutParams(); bodyParams.width = max; TableRow.LayoutParams headerParams = (TableRow.LayoutParams)headerCell.getLayoutParams(); headerParams.width = max; } } } } </code></pre> <p>main.xml </p> <pre><code> &lt;?xml version="1.0" encoding="utf-8"?&gt; &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"&gt; &lt;com.stylingandroid.ScrollingTable.ScrollingTable android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent"&gt; &lt;TableLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:id="@+id/HeaderTable"&gt; &lt;/TableLayout&gt; &lt;ScrollView android:layout_width="match_parent" android:layout_height="wrap_content"&gt; &lt;TableLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:id="@+id/BodyTable"&gt; &lt;/TableLayout&gt; &lt;/ScrollView&gt; &lt;/com.stylingandroid.ScrollingTable.ScrollingTable&gt; &lt;/LinearLayout&gt; </code></pre> <p>Main activity </p> <pre><code> package com.stylingandroid.ScrollingTable; import android.app.Activity; import android.app.ProgressDialog; import android.graphics.Color; import android.os.AsyncTask; import android.os.Bundle; import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; public class ScrollingTableActivity extends Activity { private String[][] tableData = { {"header11111111111", "header2","header3","header4"}, {"column1", "column1","column1","column1"}, {"column1", "column1","column1","column1"}, {"column1", "column1","column1","column1"}, {"column1", "column1", "column1","column1"}, {"column1", "column1","column1","column1"}, {"column1", "column1","column1","column1"}, {"column1", "column1","column1","column1"}, {"column1", "column1","column1","column1"}, {"column1", "column1","column1","column1"}, {"column1", "column1","column1","column1"}, {"column1", "column1","column1","column1"}, {"column1", "column1","column1","column1"} }; /** Called when the activity is first created. */ @Override public void onCreate( Bundle savedInstanceState ) { super.onCreate( savedInstanceState ); setContentView( R.layout.main ); TableLayout tableHeader = (TableLayout)findViewById(R.id.HeaderTable); TableLayout tableBody = (TableLayout)findViewById(R.id.BodyTable); appendRows(tableHeader, tableBody, tableData); } private void appendRows(TableLayout tableHeader ,TableLayout tableContent, String[][] amortization) { int rowSize=amortization.length; int colSize=(amortization.length &gt; 0)?amortization[0].length:0; for(int i=0; i&lt;rowSize; i++) { TableRow row1 = new TableRow(this); for(int j=0; j&lt;colSize; j++) { TextView c = new TextView(this); c.setText(amortization[i][j]); c.setPadding(3, 3, 3, 3); if (i == 0) { c.setTextColor(Color.BLACK); } row1.addView(c); } if (i == 0) { row1.setBackgroundColor(Color.LTGRAY); tableHeader.addView(row1, new TableLayout.LayoutParams()); } else { tableContent.addView(row1, new TableLayout.LayoutParams()); } } } </code></pre> <p>The above code work perfectly (<img src="https://i.stack.imgur.com/X9Gzv.png" alt="expected">), however, when I use AnysnTask to get data from server and add data to table later, the onLayout() in my custom view doesn't work anymore. I simulate getting data by log out some number: </p> <pre><code>public void onCreate( Bundle savedInstanceState ) { super.onCreate( savedInstanceState ); setContentView( R.layout.main ); new MyTask().execute(); } private class MyTask extends AsyncTask&lt;Void, Void, Void&gt; { private ProgressDialog progressDialog; protected void onPreExecute() { progressDialog = ProgressDialog.show(ScrollingTableActivity.this, "", "Loading. Please wait...", true); } @Override protected Void doInBackground(Void... reportTypes) { for (int i = 0; i &lt; 500; i++) { System.out.println(i); } return null; } @Override protected void onPostExecute(Void result) { progressDialog.dismiss(); TableLayout tableHeader = (TableLayout)findViewById(R.id.HeaderTable); TableLayout tableBody = (TableLayout)findViewById(R.id.BodyTable); appendRows(tableHeader, tableBody, tableData); } } </code></pre> <p>So the onLayout() only work when I call appendRows() from main UI thread by putting it in onCreate() method. If I call from another UI thread (in onPostExecute() of AsyncTask), the onLayout() is called (I checked it by create some logs) but it doesn't effect to the GUI. I tried with invalidate(), forceLayout(), requestLayout() but doesn't change anything.<img src="https://i.stack.imgur.com/Jwp8q.png" alt="wrong"> </p> <p>I think we need to call a method to make the GUI refresh but don't know what it is, I have searched and tried a lot of ways in 2 days but got nothing, so it will be very appreciated if you can give any idea about this. Many thanks. </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload