Android onLayout () and AsyncTask () do not work together

I need a scrollable table with a fixed header, so I followed this great blog and everything is fine.

The idea is to use one table for the title, one table for the content added to the scrollview, both of which are in a custom LinearLayout. In the individual LinearLayout, we overwrite onLayout () to get the maximum width of each row and set the width for each row of the header table and content.

Here is the activity and layout:

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() > 0 ) { TableRow bodyRow = (TableRow) body.getChildAt(0); TableRow headerRow = (TableRow) header.getChildAt(0); for ( int cellnum = 0; cellnum < 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; } } } } 

main.xml

  <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.stylingandroid.ScrollingTable.ScrollingTable android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent"> <TableLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:id="@+id/HeaderTable"> </TableLayout> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content"> <TableLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:id="@+id/BodyTable"> </TableLayout> </ScrollView> </com.stylingandroid.ScrollingTable.ScrollingTable> </LinearLayout> 

Primary activity

  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 > 0)?amortization[0].length:0; for(int i=0; i<rowSize; i++) { TableRow row1 = new TableRow(this); for(int j=0; j<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()); } } } 

The above code works fine ( expected ), however, when I use AnysnTask to get data from the server and add data to the table later, onLayout () in my user view no longer works. I simulate getting data by logging out:

 public void onCreate( Bundle savedInstanceState ) { super.onCreate( savedInstanceState ); setContentView( R.layout.main ); new MyTask().execute(); } private class MyTask extends AsyncTask<Void, Void, Void> { 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 < 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); } } 

So, onLayout () only works when calling appendRows () from the main UI thread by placing it in the onCreate () method. If I call from another thread of the user interface (in onPostExecute () AsyncTask), onLayout () is called (I checked it by creating several logs), but this does not affect the GUI. I tried with invalidate (), forceLayout (), requestLayout (), but didn't change anything. wrong

It seems to me that we need to call a method to update the GUI, but I don’t know what it is, I searched and tried many ways in 2 days, but didn’t get anything, so I would really appreciate if you can give any idea about this one. Thank you very much.

+4
source share
3 answers

Finally, I’ll find out the answer: setColumnCollapsed () forces the table layout to be updated, however we need to put it in another AsyncTask, otherwise it won’t work, it’s strange :(. I put the last code here, so I hope it is useful for someone. In addition, this is just a workaround, so feel free to post your answer if you have ...

 private class MyTask extends AsyncTask<Void, Void, Void> { 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 < 500; i++) { System.out.println(i); } return null; } @Override protected void onPostExecute(Void result) { progressDialog.dismiss(); appendRows(tableHeader, tableBody, tableData); new My1Task().execute(); } } private class My1Task extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... reportTypes) { return null; } @Override protected void onPostExecute(Void result) { tableHeader.setColumnCollapsed(0, false); tableBody.setColumnCollapsed(0, false); } } 
+1
source

You can look at this answer: Android Set the width of the text view layout dynamically

but basically try setting the width of each TextView to the same as the title.

This may require you to do everything twice, since you probably need the system to execute the layout, so use View.INVISIBLE , then you will need to exit AsyncTask, calling another, so the layout can happen.

Then in the second you can get invisible tables, scroll to find the largest width in this column, and then set all the text elements in this column to the largest.

This is not the best solution, but should work.

I think your main problem in AsyncTask is that the layout has to be done, then you can make a correction.

+2
source

The answer is that you must declare your TableLayouts method outside the onCreate () method and create an instance in onCreate (). Here is the solution. It works well.

 public class ScrollingTableActivity extends Activity { TableLayout tableHeader; TableLayout tableBody; private String[][] tableData = { { "header11111111111", "header2", "header3", "header4" }, { "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); tableHeader = (TableLayout) findViewById(R.id.HeaderTable); tableBody = (TableLayout) findViewById(R.id.BodyTable); Log.d("ScrollingTable", "Before appendRows"); //appendRows(tableHeader, tableBody, tableData); new MyTask().execute(); } private void appendRows(TableLayout tableHeader, TableLayout tableContent, String[][] amortization) { int rowSize = amortization.length; int colSize = (amortization.length > 0) ? amortization[0].length : 0; for (int i = 0; i < rowSize; i++) { TableRow row1 = new TableRow(this); for (int j = 0; j < 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()); } } } private class MyTask extends AsyncTask<Void, Void, Void> { 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 < 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); } } } 
0
source

Source: https://habr.com/ru/post/1387692/


All Articles