2

私は、relativeLayoutにリストビューがあり、その中にいくつかのLinearLayoutがあるアプリをまとめています。だから私は私のアダプターと、アイテムをリストに入れるための関数を持っています。この関数は、アプリのメインプロセスのOnCreate関数でのみ呼び出され、スレッド上のランナブルで呼び出されます。このことが私の配列への追加を何度も呼び出す可能性がある理由を皆さんは理解できますか?(配列に1つだけ追加した場合、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(); 

getItems関数と2番目の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));
        }
    }
  }
};

そしてリストアダプタ:

  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;

        }

    }

どんな助けでも大歓迎です。ありがとう、-クリス

4

1 に答える 1

0

問題はListView、アダプタで動作するその他の UI ウィジェットでは、アダプタの内容が予期せず変更されないことです。ListView次にアダプタとの対話を試みる前に、行った変更についてに通知する必要があります。別のスレッドにアダプタの変更を許可するか、メイン スレッドで変更するが、他の処理ListViewを許可する前に変更を通知しない場合、(競合により)ListViewアダプタの予期しない変更に関する例外がランダムにスローされます。

代わりに、次のようなものが機能するはずです (HackBod の投稿はこちら)。

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

    /* ... */
}

次にListView

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();
        }
    });
}
于 2012-07-10T14:59:27.400 に答える