Android 使用Runnable填充ListView-返回太多

Android 使用Runnable填充ListView-返回太多,android,arrays,listview,Android,Arrays,Listview,我正在组装一个应用程序,它在relativeLayout中有一个列表视图,里面有几个线性布局。因此,我有我的适配器和一个函数,可以将项目放入列表中。此函数仅在应用程序主进程的OnCreate函数中调用,并在线程上的runnable中调用。你们都明白为什么这个东西会多次调用adding到我的数组中吗?(当我只向数组中添加了一项内容时,for循环会被调用数千次。 在主流程的OnCreate方法中: array = new ArrayList<Item>(); //The mi

我正在组装一个应用程序,它在relativeLayout中有一个列表视图,里面有几个线性布局。因此,我有我的适配器和一个函数,可以将项目放入列表中。此函数仅在应用程序主进程的OnCreate函数中调用,并在线程上的runnable中调用。你们都明白为什么这个东西会多次调用adding到我的数组中吗?(当我只向数组中添加了一项内容时,for循环会被调用数千次。 在主流程的OnCreate方法中:

      array = new ArrayList<Item>(); //The misbehaving array
      ListView lv = (ListView)findViewById(R.id.ItemList);
      this.m_adapter = new ItemAdapter(this, R.layout.Itemlist_item, array);
      lv.setAdapter(this.m_adapter);
      viewItems = new Runnable(){
          @Override
          public void run() {
             getItems();
          }
      };
      Thread thread =  new Thread(null, viewItems, "ListThread");
      thread.start(); 
array=new ArrayList();//行为不正常的数组
ListView lv=(ListView)findViewById(R.id.ItemList);
this.m_adapter=新项目适配器(this,R.layout.Itemlist_项目,数组);
lv.setAdapter(此.m_适配器);
viewItems=new Runnable(){
@凌驾
公开募捐{
getItems();
}
};
线程线程=新线程(null,viewItems,“ListThread”);
thread.start();
getItems函数和第二个Runnable函数:

private void getItems(){
  try{
     //Try Some Stuff
  } 
  catch (Exception e) {
     Log.e("BACKGROUND_PROC", e.getMessage());
  }
  runOnUiThread(returnRes);
}
private Runnable returnRes = new Runnable() {
  @Override 
  public void run() {
    if(array != null && array.size() > 0){
        listAdapter.notifyDataSetChanged();
        //This loop is where I'm seeing the problem
        for(int i=0;i<array.size();i++) {
            listAdapter.add(array.get(i));
        }
    }
  }
};
private void getItems(){
试一试{
//试试看
} 
捕获(例外e){
Log.e(“BACKGROUND_PROC”,e.getMessage());
}
runOnUiThread(returnRes);
}
private Runnable returnRes=new Runnable(){
@凌驾
公开募捐{
if(array!=null&&array.size()>0){
listAdapter.notifyDataSetChanged();
//这个循环就是我看到问题的地方

对于(int i=0;i问题在于
ListView
和其他与适配器一起工作的UI小部件不允许适配器的内容在其上意外更改。您需要告诉
ListView
您所做的更改,然后它再尝试与您的适配器交互。如果您允许另一个线程修改适配器r、 或者在主线程上修改它,但在允许任何其他事情发生之前,不要告诉
ListView
有关更改的信息,您将随机(由于竞争)得到
ListView
引发的异常,这些异常与适配器意外更改有关

相反,类似的方法应该会奏效(来自HackBod的帖子):


问题是
ListView
和其他与适配器一起工作的UI小部件不允许适配器的内容在它们上意外更改。您需要在
ListView
下一次尝试与适配器交互之前告诉它您所做的更改。如果您允许其他线程修改适配器,或modi在主线程上设置它,但在允许任何其他事情发生之前,不要告诉
ListView
有关更改的信息,您将随机(由于竞争)得到
ListView
引发的异常,这些异常与适配器意外更改有关

相反,类似的方法应该会奏效(来自HackBod的帖子):



您是否记录了array.size()看看它认为它有多大?是的,它只是反复运行,直到它有成千上万个entries“array”对象中有多少个元素?也就是说,你认为循环应该运行多少次?现在只运行一次。但在将来,它的运行次数将与用户创建对象的次数相同。在for循环日志之前添加这一行.i(“TAG”“”+array.size());再次运行它并检查日志以查看它的输出。是否记录了array.size()看看它认为它有多大?是的,它只是反复运行,直到它有成千上万个entries“array”对象中有多少个元素?也就是说,你认为循环应该运行多少次?现在只运行一次。但在将来,它的运行次数将与用户创建对象的次数相同。在for循环日志之前添加这一行.i(“TAG”“”+array.size());再次运行它并检查日志以查看它的输出。我读取了链接,您将希望扩展BaseAdapter而不是ArrayAdapter OP甚至可以通过放置
notifyDataSetChanged()而不受影响
for
循环本身中…?从他/她提供的代码来看,不是100%确定…我认为允许
适配器本身填充自己的数据(而不是在单独的线程上顺序添加项)更有意义在之前的循环中,但在应用程序的行为中没有看到任何变化。我也在循环之前和之后尝试了所有操作,但仍然没有看到任何变化。我肯定会处理一些代码,这可能就是正在发生的事情。但为什么它会增长阵列本身?我不完全确定你对chan说的是什么ge在评论中,但我肯定会努力看看是否可以尝试。@L7ColWinters我对适配器做得不多,为什么BaseAdapter会更好?@user1425245您是否从arraylist中删除过项?因为循环执行数千次的原因可能是因为
array.size()
已经成长为一个巨大的数字。没有,但没有理由它应该添加任何内容超过一次。我设置它的方式应该只是一个项目列表。进入循环后,大小为1,之后它会增长,但我的问题是为什么?我阅读了链接,您将希望扩展BaseAdapter而不是ArrayAdapter。OP甚至可能能够为了避免将
notifyDataSetChanged()
放在
for
循环本身中…?从他/她提供的代码来看不是100%确定…我认为允许
适配器本身填充自己的数据(而不是在单独的线程上顺序添加项)但是这更有意义。亚历克斯洛克伍德:我已经把notifyDataSetChanged()放在在之前的循环中,但在应用程序的行为中没有看到任何变化。我也在循环之前和之后尝试了所有操作,但仍然没有看到任何变化。我肯定会处理一些代码,这可能就是正在发生的事情。但为什么它会增长阵列本身?我不完全确定你对chan说的是什么通用电气在评论中写道,但是
  public class ItemAdapter extends ArrayAdapter<Item> {

        public ArrayList<Item> items;
        public ItemAdapter(Context context, int textViewResourceId, ArrayList<Item> items) {
            super(context, textViewResourceId, items);
            this.items = items;
        }
        @Override
        public View getView(int position, View conView, ViewGroup parent) {
            View v = conView; //The content view

            if (v == null){
                LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.itemlist_item, null);
            }

            Item o = items.get(position);
            if (o != null){
                TextView name = (TextView)v.findViewById(R.id.item_name);
                if(name != null){
                    name.setText("name:"+o.getItemName());
                }
            }

            return v;

        }

    }
public class MyAdapter extends BaseAdapter<Item> {
    private ArrayList<Item> mItems;

    public int getCount() {
        return mItems != null ? mItems.size() : 0;
    }

    public MyItem getItem(int position) {
        return mItems.get(i);
    }

    /* ... */
}
private Handler mHandler = new Handler();

private void setDataFromThread(ArrayList<Item> data) {
    // Enqueue work on mHandler to change the data on
    // the main thread.
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            mItems = newData;
            notifyDataSetChanged();
        }
    });
}