22

我正在开发一个应该从 web 服务获取 JSON 响应并在listview中写入每个元素的应用程序,我已经读到我应该使用AsyncTask来获取 HTTP 响应并且我做到了,我可以从 web 服务中检索数据并将它们显示在TextViews中。但是当我尝试在列表视图中显示元素时,它不会显示任何内容,并在 logcat 中给我以下消息:06-05 19:44:27.418: I/Choreographer(20731): Skipped 60 frames! The application may be doing too much work on its main thread.

这是我的主要代码:

public class MainActivity extends Activity {

    private static JsonObject response = new JsonObject();
    private ArrayList<SearchResults> results = new ArrayList<SearchResults>(); 
    private SearchResults sr1 = null;

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

        new LoginAction().execute("");  

        ArrayList<SearchResults> searchResults = results;
        final ListView lv1 = (ListView) findViewById(R.id.ListView01);
        lv1.setAdapter(new MyCustomBaseAdapter(this, searchResults));
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    private class LoginAction extends AsyncTask<String, Void, String> {

        @Override
        protected String doInBackground(String... params) {

            Map<String, String> callArgs = new HashMap<String, String>(1);

            callArgs.put("suuid", "dtr0bdQGcqwSh3QO7fVwgVfBNWog6mvEbAyljlLX9E642Yfmur");

            try {
                response = EventPulseCloud.call("ListEvents", callArgs);
            } catch (HttpClientException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (JsonException e) {
                e.printStackTrace();
            } 

            return response.get("Type").toString();
        }

        protected void onPostExecute(String result) {

            if(result.equals("success")) {
                JsonArray records = null;
                try {
                    records = response.getObject ("Data").getArray ("Records");
                } catch (JsonException e) {
                    e.printStackTrace();
                }

                for(int i = 0; i < records.count(); i++) {
                    JsonObject record = (JsonObject) records.get(i);
                    sr1 = new SearchResults();
                    sr1.setAddress(record.get("address").toString());
                    results.add(sr1);
                }
            }   
        }   
    }
    }

我的列表适配器:

public class MyCustomBaseAdapter extends BaseAdapter {
    private static ArrayList<SearchResults> searchArrayList;

    private LayoutInflater mInflater;

    public MyCustomBaseAdapter(Context context, ArrayList<SearchResults> results) {
        searchArrayList = results;
        mInflater = LayoutInflater.from(context);
    }

    public int getCount() {
        return searchArrayList.size();
    }

    public Object getItem(int position) {
        return searchArrayList.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.custom_row_view, null);
            holder = new ViewHolder();
            holder.txtAddress = (TextView) convertView.findViewById(R.id.address);

            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.txtAddress.setText(searchArrayList.get(position).getAddress());

        return convertView;
    }

    static class ViewHolder {
        TextView txtAddress;
    }
}

最后是 SearchResults.java :

public class SearchResults {
    private String address = "";

    public void setAddress(String address) {
        this.address = address;
    }

    public String getAddress() {
        return address;
    }
}

那么,我做错了什么?你对此有什么想法吗?

谢谢你。

4

2 回答 2

20

onPostExecute()发生在主 UI 线程上。看起来您仍在该方法中做大量工作,这些工作应该在 UI 线程之外完成,即处理响应、迭代 JSON 对象等。这样做doInBackground()并返回结果列表,所以onPostExecute 唯一需要做的就是将新项目传递给您的列表适配器。

此外,不要使用与您的适配器相同的 ArrayList。如果由于某种原因适配器发现数据已更改而您没有调用notifyDataSetChanged(),它可能会崩溃(或至少显示奇怪的行为)。在 AsyncTask 中创建一个新的 ArrayList,然后将其放入 Adapter 并从 onPostExecute 调用它:

public void setListItems(ArrayList<SearchResult> newList) {
    searchArrayList = newList;
    notifyDataSetChanged();
}
于 2013-06-05T20:30:54.297 回答
9
private class LoginAction extends AsyncTaskList<String, Void, ArrayList<SearchResult>> {

    @Override
    protected ArrayList<SearchResult> doInBackground(String... params) {
        List<SearchResults> resultList =  new ArrayList<SearchResults>();

        Map<String, String> callArgs = new HashMap<String, String>(1);

        callArgs.put("suuid", "dtr0bdQGcqwSh3QO7fVwgVfBNWog6mvEbAyljlLX9E642Yfmur");

        try {
            response = EventPulseCloud.call("ListEvents", callArgs);
        } catch (HttpClientException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JsonException e) {
            e.printStackTrace();
        } 
      //See here I am running the loop in the background so its not on the main thread, then passing the list off to the onpostexecute that way all the main thread does is set the adapter list and notify it of the data update and the list should be updated on the screen
       if( response.get("Type").toString().equals("success")) {
            JsonArray records = null;
            try {
                records = response.getObject ("Data").getArray ("Records");
            } catch (JsonException e) {
                e.printStackTrace();
            }

            for(int i = 0; i < records.count(); i++) {
                JsonObject record = (JsonObject) records.get(i);
                sr1 = new SearchResults();
                sr1.setAddress(record.get("address").toString());
                resultList.add(sr1);
            }
        }  
        return resultList;
    }

    protected void onPostExecute(ArrayList<SearchResult> resultList) {
          setListItems(resultList);

    }   
}
}

在 oncreate 之前添加此行以及所有其他全局变量

   //here you want to create an adapter var with your base adapter so you can set it the updated list later when you have populated data from the internet
         ArrayList<SearchResults> searchResults = new ArrayList<SearchResults>();
         MyCustomBaseAdapter adapter = new MyCustomBaseAdapter(this, searchResults)

将此粘贴到您的 oncreate 方法上(替换它)

//here is just the code to update your main method to reflect all the changes I made
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    new LoginAction().execute("");  

    final ListView lv1 = (ListView) findViewById(R.id.ListView01);
    lv1.setAdapter(adapter);

}

并将此方法添加到适配器(MyCustomnBaseAdapter 类)代码中

public void setListItems(ArrayList<SearchResult> newList) {
     searchArrayList = newList;
     notifyDataSetChanged();
}
于 2013-06-05T21:14:20.940 回答