【问题标题】:Android onLayout() and AsyncTask() does not work togetherAndroid onLayout() 和 AsyncTask() 不能一起工作
【发布时间】:2011-12-23 07:44:06
【问题描述】:

我需要一个带有固定标题的可滚动表格,所以我关注了this great blog,一切都很好。

这个想法是使用一个表作为标题,一个表用于滚动视图中添加的内容,它们都在自定义的线性布局中。在自定义的 LinearLayout 中,我们将覆盖 onLayout() 以获取每行的最大宽度,并为表头和内容表的每一行设置宽度。

这是活动及其布局:

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>

主要活动

 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());
        }
    }
}

上面的代码完美运行(),但是,当我使用 AnysnTask 从服务器获取数据并稍后将数据添加到表中时,我的自定义视图中的 onLayout() 不再起作用。我通过注销一些数字来模拟获取数据:

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);
        }
        
    }

所以 onLayout() 仅在我从主 UI 线程调用 appendRows() 并将其放入 onCreate() 方法时才起作用。如果我从另一个 UI 线程(在 AsyncTask 的 onPostExecute() 中)调用,则会调用 onLayout()(我通过创建一些日志来检查它)但它不会影响 GUI。我尝试了 invalidate()、forceLayout()、requestLayout() 但没有改变任何东西。

我认为我们需要调用一个方法来刷新 GUI,但不知道它是什么。

【问题讨论】:

  • 没有“另一个”用户界面线程。 onPostExecute 与 onCreate 在同一线程上调用。
  • 如果是这样,为什么当我将 appendRow 放在 onCreate 中时它才起作用。
  • 我不知道。我没有深入查看您的代码。但是您可能想在不考虑线程的情况下考虑这个问题。
  • 在设置宽度时,您可能希望使用调试来查看单元格的宽度,并查看它们是什么。理想情况下,将每个宽度写入 logcat。此外,您可能需要在全部完成后对表格调用 invalidate,以便它可以重做布局。这可能会解决问题。
  • @JamesBlack 使用单元格宽度进行调试是我做的第一件事,它可以正确获取最大宽度列。我试图在 appendRows() 之后放置 invalidate() 但没有运气。 :) appendRows(tableHeader, tableBody, tableData); tableHeader.invalidate(); tableBody.invalidate();

标签: android layout android-asynctask ui-thread


【解决方案1】:

你可能想看看这个答案: Android Set textview layout width dynamically

但是,基本上,尝试将每个 TextView 的宽度设置为与标题相同。

这可能需要你做两次,因为你可能需要让系统做布局,所以使用View.INVISIBLE,然后你需要退出AsyncTask,调用另一个,这样布局工作才能发生.

然后在第二个中,您可以获取不可见的表格,循环查找该列中的最大宽度,然后将该列中的所有TextView设置为最大。

这不是最好的解决方案,但应该可以。

我认为您在 AsyncTask 中的主要问题是需要完成布局,然后您可以进行修复。

【讨论】:

  • 感谢 James 给了我关于调用另一个 AsyncTask 的想法,但使用 setColumnCollapsed() 可能会更好。无论如何,我会将此作为公认的答案,为您提供 50 声望。 :)
【解决方案2】:

终于找到答案了,setColumnCollapsed() 刷新了表格布局,不过需要放到另一个AsyncTask中,不然不行,奇怪:(。我把最新的代码放在这里了,望采纳对某人有帮助。此外,这只是一种解决方法,所以如果有任何答案,请随时发布......

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);
    }
}

【讨论】:

    【解决方案3】:

    答案是您应该在 onCreate() 方法之外声明您的 TableLayouts,并在 onCreate() 中实例化它们。这是解决方案。效果很好。

    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);
            }
        }
    }
    

    【讨论】:

    • 感谢 Yury,但它不起作用,我尝试了您的代码,但列未按预期对齐。我在我的问题中添加了一些截图,请看一下
    • 是的,对不起。现在我明白问题出在哪里了。抱歉回答不正确。
    猜你喜欢
    • 1970-01-01
    • 2013-04-11
    • 1970-01-01
    • 1970-01-01
    • 2015-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    相关资源
    最近更新 更多