2013-05-02 10 views
25

Hier ist der Code des Fragments, in dem ich einen benutzerdefinierten Adapter auf die Liste festlegen.Benutzerdefinierte Adapter getView() -Methode heißt nicht

Es gibt keine Fehler, aber die ListView ist leer. Ich habe getCount() implementiert, die die richtige Anzahl von Elementen in meiner ArrayList zurückgibt. Ich sehe nicht, ("Inside", "GetView") im logcat

Fragment

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

} 

Antwort

130

Die einzigen Gründe getView nicht genannt wird:

  1. getCount liefert 0.
  2. Sie vergessen, setAdapter auf der ListView zu rufen.
  3. Wenn die Sichtbarkeit ListView (oder die Sichtbarkeit des Containers) GONE ist. Danke an @ TaynãBonaldo für den wertvollen Input.
  4. ListView ist keinem Layout des Ansichtsfensters zugeordnet. Das heißt, mListView = new ListView(...) wird ohne myLayout.addView(mListView) verwendet.

Im onPostExcute, nachdem Sie eine neue Instanz von CarListAdapter schaffen werde ich Ihnen vorschlagen, die neue Instanz zu Ihrem ListView zu aktualisieren. Tatsächlich müssen Sie wieder anrufen

mList.setAdapter(adapter); 

Edit: setAdapter sollte immer auf dem UI-Thread aufgerufen werden, um unerwartete Verhaltensweisen zu vermeiden

Edit2:

Gleiches gilt für RecyclerView. Stellen Sie sicher, dass

  • getItemCount ist ein Wert größer als 0 (in der Regel der Datensatz Größe)
  • beide setLayoutManager und setAdapter rief die UI Thread
  • Die Sichtbarkeit des Widgets festgelegt werden muss haben Rückkehr zu VISIBLE
+0

es funktionierte, aber können Sie erklären, warum denn in Fragment Lifecycle onCreate() vor onCreateView() aufgerufen wird und im die AsyncTask in onCreate() und Einstellen des Adapters in onCreateView Aufruf () welches nachher aufgerufen wird. – Ravi

+1

@Ravi Erstens kann niemand versichern, dass die AsyncTask-Ausführung beendet ist, bevor oder nachdem die onCreateView aufgerufen wird. Das ist es, was Async bedeutet. Zwei, in der onPostExcute erstellen Sie einen neuen CarListAdapter und Ihr ListView muss informiert werden, dass der Adapter – Blackbelt

+0

geändert hat ich meine, indem Sie den Adapter in onPosExecute Methode ist ein guter Weg für diese Art von Situation, oder es gibt eine bessere Architektur zu vermeiden Probleme – Ravi

0

Sie verpassen die Superklasse im Konstruktor.Siehe mein Beispiel unten:

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

Ich würde hinzufügen, dass: adapter = neue CarListAdapter ... nicht tatsächlich den Adapter für die Ansicht festlegen. Er hat also eine Race Condition zwischen onCreateView und onPostExecute – Raanan

+0

Du hast recht, ich hatte nicht bemerkt, dass er den neuen Adapter nicht an die ListView in Post Execute gebunden hat.Blackbelt ftw – o0rebelious0o

+0

@Raanan können Sie erarbeiten, was getan werden sollte, um diese Race-Bedingung zu vermeiden und zu erklären .. ich bin neu in Android-Entwicklung .. es wäre gr8, wenn Sie erklären könnten ... danke – Ravi

0

Was Sie getan haben

In Ihrem Adapter

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

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

} 

in Ihrem Fragment

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

I hoffen, dass Sie verwenden FragmentActivity

Sie müssen

nennen
adapter = new CarListAdapter(YOUR_ACTIVITY_CONTEXT, carDetailList); 

wo YOUR_ACTIVITY_CONTEXT Ihre FragmentActivity

3

ich konfrontiert ähnliches Problem sein wird. Hier ist eine einfache Arbeit um es zu lösen:

In Ihrem onCreateView müssen Sie warten, bevor die Ansicht erstellt wird. So Ihre Zeilen aus dieser Änderung:

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

CHANGE Die obigen zwei Zeilen in:

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

Hope this anderen helfen wird, die in ähnliche Probleme laufen würde

+0

Ich sehe nicht, wie das hilft. ASAIK, die Ansicht wird erstellt, wenn das Aktivitätslayout aufgebläht ist. Ich sehe keine Notwendigkeit, für seine Schaffung weiter zu "warten". Ich stehe vor einem ähnlichen Problem, und das ist keine Lösung. – Bamaco

4

Sie müssen sicherstellen, dass die Liste Elemente können einen Fehler beim Hinzufügen von Elementen zu Ihrer Liste haben. Um zu überprüfen, verwenden Sie die Methode:

adapter.getCount(); 
Verwandte Themen