Android: ListView-Adapter: Adapter wird ständig aufgerufen

Thaflasher

Mitglied
Hi Forum,

ich habe mir einen Adapter geschrieben damit ich in eine ListView abwechselnd einen String und eine RadioButtonGroup einfügen kann. Soweit funzt das auch.

Leider wenn meine ListView zu groß wird und ich zu scrollen anfange (was erwünscht ist), duplizieren sich die Einträge.

Durch den Debugger habe ich erkannt, das der Adapter immer dann wenn die View weiter scrollt, wieder aufgerufen wird und das ist etwas unschön.

Zuerst hab ich versucht es mit einem "ViewHolder" zu lösen, indem ich das ganze mit view.setTag(holder) speichere und dann wieder hole. Leider stand im Tag nur der String und nie die RadioButtonGroup d.h. ich hab zwar meine Strings angezeigt bekommen aber meine Auswahlmöglichkeiten waren weg. ;(

Google hat mir verraten das man auch eien ViewBinder schreiben kann aber da steh ich völlig auf dem Schlauch, da ich nicht verstehe wie bzw. wann der Adapter die getViewValue() aufruft.


Der Code:

Java:
package tsystem.adapter;

import java.util.ArrayList;

import tsystem.activity.R;

import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;

import android.widget.TextView;

public class RadiogroupAdapter extends ArrayAdapter<Object> {
  
	RadioGroup mRadioGroup;
	TextView re;
	Context context;
	String TAG = "RGA";

      private ArrayList<Object> items;

      public RadiogroupAdapter(Context context, int textViewResourceId, ArrayList<Object> items) {
              super(context, textViewResourceId, items);
              this.context = context;
              this.items = items;
      }
      
      @Override
      public View getView(int position, View convertView, ViewGroup parent) {
              View v = convertView;

              if (v == null || v.getTag()==null) {
                  LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                  v = vi.inflate(R.layout.list_items, null);
                  

              Object o = items.get(position);
              
              if (o != null) {
            	  if(o instanceof String){
            		  re=((TextView)v.findViewById(R.id.listtv));
            		  re.setText((CharSequence) o);
            		  re.setPadding(10, 10, 10, 10);
            	  }
            	  else if(o instanceof String[]){
            		  mRadioGroup = (RadioGroup)v.findViewById(R.id.radiobuttons);
            		  mRadioGroup.setPadding(15, 10, 15, 10);
            		  createRadioButtons((String[]) o);
            	  }
            	  
              }
              }
              else{
              }
              return v;
              
      }
      
      private void createRadioButtons(String[] rating)	{

  		LinearLayout.LayoutParams lp = new RadioGroup.LayoutParams(RadioGroup.LayoutParams.WRAP_CONTENT, RadioGroup.LayoutParams.WRAP_CONTENT);
  		lp.setMargins(10, 10, 10, 10);
  		
				for (int j = rating.length-1; j >= 0; j--) {
					RadioButton rb = new RadioButton(context);
					rb.setTextColor(Color.BLACK);
					rb.setTextSize(25.0f);
					rb.setText(rating[j]);
					rb.setOnClickListener(new OnClickListener() {
						
						@Override
						public void onClick(View v) {
							RadioButton bb = (RadioButton)v;
							bb.setSelected(true);
						}
					});
					
					mRadioGroup.addView(rb,0,lp);
				}
  	}
}


Frage:

Hat jemand eine Idee wie ich die öfteren Aufrufe dazu bringe mir die Werte die ich ihm am Anfang übergebe zu behalten, ohne mir die Reihenfolge durcheinander zu bringen, noch die Einträge zu duplizieren? ???:L


Grüße
thaFlasher
 
Update:

habe nun das ganze nochmal mit dem ViewHolder versucht.

Hier die geänderte getView

Java:
@Override
      public View getView(int position, View convertView, ViewGroup parent) {
              View v = convertView;
              ViewHolder holder;

              if (v == null || v.getTag()==null) {
                  LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                  v = vi.inflate(R.layout.list_items, null);
                  holder = new ViewHolder();

              Object o = items.get(position);
              
              if (o != null) {
            	  if(o instanceof String){
            		  re=((TextView)v.findViewById(R.id.listtv));
            		  re.setText((CharSequence) o);
            		  re.setPadding(10, 10, 10, 10);
            		  holder.re=re;
            	  }
            	  else if(o instanceof String[]){
            		  mRadioGroup = (RadioGroup)v.findViewById(R.id.radiobuttons);
            		  mRadioGroup.setPadding(15, 10, 15, 10);
            		  createRadioButtons((String[]) o);
            		  holder.mRadioGroup=mRadioGroup;
            	  }
            	  
              }
              v.setTag(holder);
              }
              else{
            	  holder = (ViewHolder)v.getTag();
            	  if(holder.re==null){
            		  mRadioGroup= holder.mRadioGroup;
            		  Log.d(TAG, "RG");
            	  }
            	  else{
            		  re=holder.re;
            		  Log.d(TAG,"RE");
            	  }
              }
              return v;
              
      }


Jetzt behält er schon mal Daten und dupliziert auch nichts mehr. Leider gibt es immer noch eine Störung:

Bevor der User seine Ergebnisse abgeschickt hat, überprüfe ich ob er auch alle RadioButtons angeklickt hat. D.h. ich gehe die ListView von oben bis unten durch und drücke auf absenden.
Leider nehmen jetzt alle obrigen Werte null an, bis ich wieder hoch scrolle. Dann geht das abschicken da die unten Objekte nicht null werden.

Frage:

Warum zur Hölle ist das so? 🙂
 
Antwort: Weil Android um Ressourcen zu sparen die Views zerstört die gerade nicht sichtbar sind. Muss nicht sein, kann es aber - wie eben in deinem Fall.

Doch des Pudels Kern ist nicht Android Sparsamkeit sondern dein Design-Fehler: Um solche Grauslichkeiten zu vermeiden musst du Logik bzw. Daten von UI bzw. View trennen.

Steck also einen EventHandler in deine Checkboxen die das jeweilige Attribut in einer Modelklasse an der aktuellen Position setzen und gut ist. Daraus folgt allerdings auch, dass du eine Modelklasse schreiben musst die deine Checkboxes bzw. deinen String ordentlich abbildet.

PS: "LayoutInflater.from(context)" => deutlich schöner und schneller getippt als "context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);"
 

Zurück
Oben