跳过60帧!应用程序可能在其主线程上做了太多工作

22 android android-listview android-asynctask baseadapter

我正在开发一个应该从Web服务获取JSON响应的应用程序并编写listview中的每个元素,我已经读过我应该使用AsyncTask来获取HTTP响应并且我做了它并且我可以从webservice检索数据并在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);
                }
            }   
        }   
    }
    }
Run Code Online (Sandbox Code Playgroud)

我的列表适配器:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,SearchResults.java:

public class SearchResults {
    private String address = "";

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

    public String getAddress() {
        return address;
    }
}
Run Code Online (Sandbox Code Playgroud)

那么,我做错了什么?你对此有所了解吗?

谢谢.

Kar*_*uri 21

onPostExecute()发生在主UI线程上.看起来你仍然在该方法中做了相当多的工作,应该在UI线程之外完成,即处理响应,迭代JSON对象等.执行此操作doInBackground()并返回结果列表,以便只有onPostExecute需要做的就是将新项目传递给列表适配器.

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

public void setListItems(ArrayList<SearchResult> newList) {
    searchArrayList = newList;
    notifyDataSetChanged();
}
Run Code Online (Sandbox Code Playgroud)


Osm*_*man 10

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

    }   
}
}
Run Code Online (Sandbox Code Playgroud)

在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)
Run Code Online (Sandbox Code Playgroud)

将其粘贴到您的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);

}
Run Code Online (Sandbox Code Playgroud)

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

public void setListItems(ArrayList<SearchResult> newList) {
     searchArrayList = newList;
     notifyDataSetChanged();
}
Run Code Online (Sandbox Code Playgroud)

  • 这很好,这只是意味着你的应用程序的规模越来越大,这是可以理解的.你知道那个循环是如何阻塞他的主线程的,因为它太大了,那就是因为你正在下载大量的数据导致android增加为你的应用程序分配的内存大小,这并不意味着内存不足,只是您的应用程序正在增长,这很好,可以理解.现在要解决你在listview中看不到任何内容的事实,请确保在某个时间点调用`notifyDataSetChanged();`如果按照我的大纲,它应该在setListItems方法中 (2认同)