2013-05-02 2 views
25

Вот код фрагмента, в котором я устанавливаю пользовательский адаптер в список.Метод пользовательского адаптера getView() не называется

Ошибок нет, но ListView пуст. Я внедрил getCount(), который возвращает правильное количество элементов в моем ArrayList. Я не вижу ("Inside", "GetView") в LogCat

Фрагмент

public class ServiceCarListFragment extends Fragment { 

    private String url; 
    private ArrayList<CarDetail> carDetailList = new ArrayList<CarDetail>(); 
    private CarListAdapter adapter; 
    private ListView mList; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     // TODO Auto-generated method stub 
     super.onCreate(savedInstanceState); 
     url = getActivity().getIntent().getStringExtra("url"); 
     new DownloadCarDetail().execute(url); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 
     // TODO Auto-generated method stub 
     View v = inflater.inflate(R.layout.fragment_service_car_list, container, false); 
     mList = (ListView) v.findViewById(R.id.list); 
     mList.setAdapter(adapter); 

     for (CarDetail car : carDetailList) { 
      // START LOADING IMAGES FOR EACH STUDENT 
      car.loadImage(adapter); 
     } 
     return v; 
    } 

    class DownloadCarDetail extends AsyncTask<String, String, ArrayList<CarDetail>> { 

     @Override 
     protected ArrayList<CarDetail> doInBackground(String... params) { 
      // TODO Auto-generated method stub 
      ArrayList<CarDetail> carDetailList = JsonParser.parseJson(params[0]); 
      return carDetailList; 
     } 

     @Override 
     protected void onPostExecute(ArrayList<CarDetail> carDetailList) { 
      // TODO Auto-generated method stub 
      ServiceCarListFragment.this.carDetailList = carDetailList; 
      Log.d("dccs", String.valueOf(ServiceCarListFragment.this.carDetailList.size())); 
      adapter = new CarListAdapter(getActivity(), ServiceCarListFragment.this.carDetailList); 
      Log.d("dccs", String.valueOf((adapter.getCount()))); 
     } 

    } 
} 

CustomAdapter

public class CarListAdapter extends BaseAdapter { 

    private ArrayList<CarDetail> items = new ArrayList<CarDetail>(); 
    private Context context; 

    public CarListAdapter(Context context, ArrayList<CarDetail> items) { 
     this.context = context; 
     this.items = items; 
    } 

    @Override 
    public int getCount() { 
     // TODO Auto-generated method stub 
     return items.size(); 
    } 

    @Override 
    public Object getItem(int position) { 
     // TODO Auto-generated method stub 
     return items.get(position); 
    } 

    @Override 
    public long getItemId(int position) { 
     // TODO Auto-generated method stub 
     return position; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     // TODO Auto-generated method stub 
     Log.d("Inside", "GetView"); 
     LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE); 
     ViewHolder holder = null; 
     CarDetail car = items.get(position); 

     if (convertView == null) { 
      convertView = mInflater.inflate(R.layout.car_list_row, null); 
      holder = new ViewHolder(); 
      holder.tvCarName = (TextView) convertView.findViewById(R.id.tvCarName); 
      holder.tvDailyPriceValue = (TextView) convertView.findViewById(R.id.tvWeeklyPriceValue); 
      holder.tvWeeklyPriceValue = (TextView) convertView.findViewById(R.id.tvWeeklyPriceValue); 
      holder.imgCar = (ImageView) convertView.findViewById(R.id.imgCar); 
      convertView.setTag(holder); 
     } else { 
      holder = (ViewHolder) convertView.getTag(); 
     } 

     holder.tvCarName.setText(car.getCarName()); 
     if (car.getImage() != null) { 
      holder.imgCar.setImageBitmap(car.getImage()); 
     } else { 
      // MY DEFAULT IMAGE 
      holder.imgCar.setImageResource(R.drawable.ic_action_call); 
     } 

     return convertView; 
    } 

    static class ViewHolder { 
     TextView tvCarName; 
     TextView tvDailyPriceValue; 
     TextView tvWeeklyPriceValue; 
     ImageView imgCar; 
    } 

} 

ответ

130

Единственные причины getView не называют, являются:

  1. getCount 0.
  2. Вы забываете позвонить в setAdapter на номер ListView.
  3. Если видимость ListView (или ее видимость) составляет GONE. Спасибо @ TaynãBonaldo за ценный вклад.
  4. ListView не прилагается к любому макету видового экрана. То есть mListView = new ListView(...) используется без myLayout.addView(mListView).

В onPostExcute, после создания нового экземпляра CarListAdapter я предлагаю вам обновить новый экземпляр вашего ListView. Действительно, вы должны вызвать снова

mList.setAdapter(adapter); 

Edit: setAdapter должен быть всегда вызывается на поток пользовательского интерфейса, чтобы избежать неожиданных поведения

edit2:

То же самое относится и к RecyclerView. Убедитесь, что

  • getItemCount возвращается терке значение, чем 0 (обычно размер набора данных)
  • как setLayoutManager и setAdapter должны называться по UI Thread
  • Видимость виджета должен быть установлен VISIBLE
+0

он работал, но вы можете объяснить, почему, потому что в фрагмент жизненного цикла OnCreate() вызывается до onCreateView() и им вызывающей AsyncTask в OnCreate() и установки адаптера в onCreateView (), который вызывается после. – Ravi

+1

@Ravi, в первую очередь, никто не может гарантировать, что выход AsyncTask завершен до или после вызова onCreateView. Это то, что означает асинхронное. Во-вторых, в onPostExcute вы создаете новый CarListAdapter, и ваш ListView должен быть проинформирован о том, что адаптер изменился. – Blackbelt

+0

Я имею в виду, что установка адаптера в методе onPosExecute является хорошим способом для такого типа ситуации или существует лучшая архитектура, чтобы избежать таких проблемы – Ravi

0

Вам не хватает суперкласс в конструкторе.Смотрите мой пример ниже:

public AppDataAdapter(Activity a, int textViewResourceId, ArrayList<AppData> entries) { 
    super(a, textViewResourceId, entries); 
    this.entries = entries; 
    this.activity = a; 
} 
+0

Я бы добавил, что: adapter = new CarListAdapter ... на самом деле не устанавливает адаптер для представления. Поэтому у него есть условие гонки между onCreateView и onPostExecute – Raanan

+0

Вы правы, я не заметил, что он не привязывал новый адаптер к списку в post execute.Blackbelt ftw – o0rebelious0o

+0

@ Raanan вы можете уточнить, что нужно сделать, чтобы избежать этого состояния гонки и объяснить .. Я новичок в разработке Android ... это было бы gr8, если бы вы могли объяснить ..thanks – Ravi

0

То, что вы делаете

В адаптере

public CarListAdapter(Context context , ArrayList<CarDetail> items) { 

    this.context = context; 
    this.items = items; 

} 

в вашем фрагменте

adapter = new CarListAdapter(getActivity(),ServiceCarListFragment.this.carDetailList); 

Я надеюсь, что вы будете использовать FragmentActivity

Вы должны вызвать

adapter = new CarListAdapter(YOUR_ACTIVITY_CONTEXT, carDetailList); 

где YOUR_ACTIVITY_CONTEXT будет вашим FragmentActivity

3

я столкнулся с подобной проблемой. Чтобы решить эту проблему, выполните простую работу:

В вашем onCreateView вам придется подождать до создания представления. Таким образом изменить строки из этого:

mList = (ListView)v.findViewById(R.id.list); 
mList.setAdapter(adapter); 

изменяющих вышеупомянутые две строк в:

mList = (ListView)v.findViewById(R.id.list); 
mList.post(new Runnable() { 
    public void run() { 
     mList.setAdapter(adapter); 
    } 
}); 

Надеется, что это поможет другим, кто будет работать в подобные проблемы

+0

Я не вижу, как это помогает. ASAIK, представление создается, когда разметка Activity раздута. Я не вижу необходимости «ждать» для его создания. Я столкнулся с аналогичной проблемой, и это не решение. – Bamaco

4

вы должны убедиться, что в списке есть элементы могут иметь ошибку при добавлении элементов в ваш список. Для проверки используйте метод:

adapter.getCount(); 
Смежные вопросы