user1281921
user1281921

Reputation: 163

ASyncTask and returning an ArrayList

Im trying to return an ArrayList from the AsyncTask class back to the MainAcitivity class and then use this arraylist to fill the gridview in MainActivity.

The parseURL takes a String paramater to parse the url. And parseURL is executed when the user clicks the button. The code i have compiles and run but the gridview is not populated after triggering the button event and pressing the button twice crashes the app.

EDIT: After adding loop callback, it stops crashing but it still wont populate the gridview. The ArrayList object that i want to populate the gridview is in this format 10,John,Smith

Here is my code for MainActivity (using Stanislav Bodnar suggestion)

private GridView grid1;
private ArrayAdapter<String> adapter;

 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //initalized the grid and adapter
    grid1 = (GridView)findViewById(R.id.gridView1);

    adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
    grid1.setAdapter(adapter);
 }

public void onButtonClick(View v) {
EditText textInput = (EditText) findViewById(R.id.editText1);
String code = textInput.getText().toString();

new parseURL() {
    @Override
    protected void onPostExecute(List<String> list) {
        //use the list from parseURL to fill grid view
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);

        gridView.setAdapter(adapter);
        adapter.notifyDataSetChanged();
    }
}.execute(code);

ParseURL class

public class parseURL extends AsyncTask<String, Void, List<String>> {

protected List<String> doInBackground(String... params) {
    List<String> str = new ArrayList<String>();
    try {
        Document doc = Jsoup.connect("http://www.mywebsite.com/id/" + params).get();

        Elements row1 = doc.select("table");
        Elements row2 = doc.select("td");
        Elements row3 = doc.select("td");

        for (int i = 0; i < row1.size(); i++) {
            str.add(row1.get(i).text() + "," + row2.get(i).text() + "," + row2.get(i).text());
        }
        return str;
    } catch (Exception e) {
        return new ArrayList<String>();
    }
}

Upvotes: 0

Views: 2348

Answers (4)

zeisuke
zeisuke

Reputation: 192

try this:

Mainactivity.class

private GridView grid1;
private ArrayAdapter<String> adapter;

 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //initalized the grid and adapter
    grid1 = (GridView)findViewById(R.id.gridView1);

    adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
    grid1.setAdapter(adapter);
 }

public void onButtonClick(View v) {
    EditText textInput = (EditText) findViewById(R.id.editText1);
    String code = textInput.getText().toString();
    new parseURL(this).execute(code);
}

public void onBackgroundTaskCompleted(List<String> result) {
    // TODO Auto-generated method stub
    Log.i(TAG, "onBackgroundTaskCompleted List: "+result);

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);

    gridView.setAdapter(adapter);
    adapter.notifyDataSetChanged();
}

Asynctask:

public class parseURL extends AsyncTask<String, Void, List<String>> {

MainActivity caller;

    public Scheduler(MainActivity mainActivity) {
        // TODO Auto-generated constructor stub
        this.caller = mainActivity;
    }
    protected void onPostExecute(List<String> result) {
            caller.onBackgroundTaskCompleted(result);
    }

    protected List<String> doInBackground(String... params) {
        List<String> str = new ArrayList<String>();
        try {
            Document doc = Jsoup.connect("http://www.mywebsite.com/id/" + params).get();

            Elements row1 = doc.select("table");
            Elements row2 = doc.select("td");
            Elements row3 = doc.select("td");

            for (int i = 0; i < row1.size(); i++) {
                str.add(row1.get(i).text() + "," + row2.get(i).text() + "," + row2.get(i).text());
            }
            return str;
        } catch (Exception e) {
            return new ArrayList<String>();
        }
    }
}

Upvotes: 1

denvercoder9
denvercoder9

Reputation: 3021

Don't do gridview.setAdapter() twice. There are a few problems with that code. As P-a Bäckström wrote:

Also, passing around the MainActivity feels a bit shaky. What happens if the Activity is destroyed during the async-task? Instead, make the AsyncTask a private inner class or an anonymous class in MainActivity

You need to fix that too. Now comes the updating part:

Declare a global Handler like this:

private final Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        if(msg.what == 1) {
            List<String> list = (List) msg.obj;
            adapter.insert(list);
            adapter.notifyDataSetChanged();
        }
    }
};

Then in onPostExecute() send your data to the UI thread using the handler and update the gridview:

protected void onPostExecute(List<String> list) {
    handler.obtainMessage(1, list);
}

Upvotes: 1

Stanislav Bodnar
Stanislav Bodnar

Reputation: 385

You can add loading callback.

public void onButtonClick(View v) {
    EditText textInput = (EditText) findViewById(R.id.editText1);
    String code = textInput.getText().toString();

    new parseURL() {
        @Override
        protected void onPostExecute(List<String> list) {
            //use the list from parseURL to fill grid view
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);

            gridView.setAdapter(adapter);
            adapter.notifyDataSetChanged();
        }
    }.execute(code);
}

Asynctask:

public class parseURL extends AsyncTask<String, Void, List<String>> {

    protected List<String> doInBackground(String... params) {
        List<String> str = new ArrayList<String>();
        try {
            Document doc = Jsoup.connect("http://www.mywebsite.com/id/" + params).get();

            Elements row1 = doc.select("table");
            Elements row2 = doc.select("td");
            Elements row3 = doc.select("td");

            for (int i = 0; i < row1.size(); i++) {
                str.add(row1.get(i).text() + "," + row2.get(i).text() + "," + row2.get(i).text());
            }
            return str;
        } catch (Exception e) {
            return new ArrayList<String>();
        }
    }
}

Supplement

If array list that returns by onPostExecute is not empty your grid will be populated in the next way each cell will have string 10,John,Smith. Please check that method doInBackground does not catch some exception and fills array list correctly.

Next if you want to do a table view where 1 row will contain 3 columns 10 | John | Smith then parse data into object structure:

class Person {
    private int id;
    private String firstName;
    private String lastName;
}

Then change method doInBackground to return array list of Person objects.

Create custom adapter (extend BaseAdapter) where init view using Person object. View will be as LinearLayout with horizontal orientation which will contain 3 TextView with Layout Weight (android:layout_weight="0.3" - set in each TextView, you can change this value). Then use ListView instead of GridView. Each row of list view will contain 1 Person.

Upvotes: 1

The AsyncTask is by definition asynchronous. Your code handles it like it was synchronous.

Move

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);

gridView.setAdapter(adapter);
adapter.notifyDataSetChanged();

into the setList method.

Also, passing around the MainActivity feels a bit shaky. What happens if the Activity is destroyed during the async-task? Instead, make the AsyncTask a private inner class or an anonymous class in MainActivity

And of course you will need to initialize your list before you populate it.

Upvotes: 1

Related Questions