Mark
Mark

Reputation: 1400

How to add views to layout from AsyncTask

Based on user inputs I'm dynamically adding many textviews to a relative layout in a loop.

The problem is that as the number of tv increase the amount of time it takes to build the layout also increases to the point when the user will get the "wait/force close" message.

I know this due to being on the main UI thread but as far as I know I cannot add views to a layout asynchronously, say in doInBackground as you get "Only the original thread that created a view hierarchy can touch its views" error.

Each new tv is either to the right_of or below the previous tv, calculated in the loop, so I cannot move the addview statement into AsyncTask onPostExecute.

Is there a way to add the tvs, in the for loop, to a layout while using AsyncTask?

This is how it needs to be done:

public class LoadData extends AsyncTask<Void, Void, Void> {

    protected void onPreExecute(){ ....

    protected Void doInBackground(Void... params){  ...

        while (yCoord + CellSizeH < b2.getHeight()) {
             while (xCoord + CellSizeW < b2.getWidth() ) {

                tv = new TextView(this);
                tv.setTextSize(DisplayCellSizeH * 0.5f);
                tv.setWidth(DisplayCellSizeW);
                tv.setHeight(DisplayCellSizeH);
                tv.setOnClickListener(new View.OnClickListener() {...
                }

                //this will error so needs to be in onPostExecute
                thelayout.addView(tv, params1);
              }
          }


    protected void onPostExecute(Void result){ ...

Hope this makes sense. Thanks

Upvotes: 2

Views: 1692

Answers (3)

mohammed momn
mohammed momn

Reputation: 3210

This code from one of implementation in some project , try it

declare your layout and the activity you work on it

LinearLayout asyncLayout;
Activity myactivity;

and in onCreate

asyncLayout = (LinearLayout) findViewById(R.id.asyncLayout);
    myactivity= this;

    new LoadData().execute();

then your Async implementation

public class LoadData extends AsyncTask<Void, Void, Void> {

    protected void onPreExecute() {
    }

    protected Void doInBackground(Void... params) {

        myactivity.runOnUiThread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                for (int i = 0; i < 3; i++) {

                     TextView text = new TextView(List_Activity.this);
                     text.setWidth(40);
                     text.setHeight(20);
                     text.setText("text : " + i);
                     asyncLayout.addView(text);
                }


            }
        });

                    return null;

    }

    protected void onPostExecute(Void result) {
    }

feed me back

Upvotes: 1

Mark
Mark

Reputation: 1400

Adding this to AsyncTask doinbaground allow the views to be adding during the async task loop

Viewchart.this.runOnUiThread(new Runnable() {
    public void run() {
        thelayout.addView(tv, params1);
    }
});

Upvotes: 2

PearsonArtPhoto
PearsonArtPhoto

Reputation: 39698

This is what ListViews are for. Putting in a custom adapter will work. Essentially, each row in the table will load only what is required to get it to work.

Essentially, the ListView is your container, and you create an adapter which populates the data appropriately. You add a custom adapter to the ListView, and you're set. Here's a simple layout of an Adapter.

public class CustomAdapter extends BaseAdapter {

    public CustomAdapter (Context c) {
    }

    public int getCount() {
        /Number of rows
    }

    public Object getItem(int position) {
        //Probably not required for your applications
    }

    public long getItemId(int position) {
        //Probably not required for your applications
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        //Create a view here, and return it.
    }
}

Upvotes: 3

Related Questions