2012-04-05 14 views
10

Warum wird meine Listview nicht aktualisiert, wenn ich notifyDatasetChanged() aufrufe? der einzige Weg, ich kann es die Daten machen angezeigt werden, wieder setAdatper() auf dem Listview zu nennen ... Ich habe auch versucht, es über runOnUIThread() aufzurufen, die nichtsBaseAdapter.notifyDatasetChanged() Aktualisierung der ListView

Der Adapter

änderte sich
/** 
* Adapter to provide the data for the online scores 
* 
* @author soh#zolex 
* 
*/ 
public class OnlineScoresAdapter extends BaseAdapter { 

    private Context context; 
    private List<ScoreItem> scores = new ArrayList<ScoreItem>(); 

    /** 
    * Constructor 
    * 
    * @param Context context 
    */ 
    public OnlineScoresAdapter(Context context) { 

     this.context = context; 
    } 

    /** 
    * Add an item to the adapter 
    * 
    * @param item 
    */ 
    public void addItem(ScoreItem item) { 

     this.scores.add(item); 
    } 

    /** 
    * Get the number of scores 
    * 
    * @return int 
    */ 
    public int getCount() { 

     return this.scores.size(); 
    } 

    /** 
    * Get a score item 
    * 
    * @param int pos 
    * @return Object 
    */ 
    public Object getItem(int pos) { 

     return this.scores.get(pos); 
    } 

    /** 
    * Get the id of a score 
    * 
    * @param in pos 
    * @retrn long 
    */ 
    public long getItemId(int pos) { 

     return 0; 
    } 

    /** 
    * Get the type of an item view 
    * 
    * @param int pos 
    * @return int 
    */ 
    public int getItemViewType(int arg0) { 

     return arg0; 
    } 

    /** 
    * Create the view for a single list item. 
    * Load it from an xml layout. 
    * 
    * @param int pos 
    * @param View view 
    * @param ViewGroup viewGroup 
    * @return View 
    */ 
    public View getView(int pos, View view, ViewGroup group) { 

     LinearLayout layout; 
     if (view == null) { 

      layout = (LinearLayout)View.inflate(this.context, R.layout.scoreitem, null); 

     } else { 

      layout = (LinearLayout)view; 
     } 

     TextView position = (TextView)layout.findViewById(R.id.pos); 
     TextView time = (TextView)layout.findViewById(R.id.time); 
     TextView player = (TextView)layout.findViewById(R.id.player); 
     TextView createdAt = (TextView)layout.findViewById(R.id.created_at); 

     ScoreItem item = (ScoreItem)getItem(pos); 
     player.setText(item.player); 
     position.setText(String.valueOf(new Integer(item.position)) + "."); 
     time.setText(String.format("%.4f", item.time)); 
     createdAt.setText(item.created_at); 

     return layout; 
    } 

    /** 
    * Get the number of different views 
    * 
    * @return int 
    */ 
    public int getViewTypeCount() { 

     return 1; 
    } 

    /** 
    * Return wheather the items have stable IDs or not 
    * 
    * @return boolean 
    */ 
    public boolean hasStableIds() { 

     return false; 
    } 

    /** 
    * Return wheather the list is empty or not 
    * 
    * @return boolean 
    */ 
    public boolean isEmpty() { 

     return this.scores.size() == 0; 
    } 

    /** 
    * No need of a data observer 
    * 
    * @param DataSetObserver arg0 
    * @return void 
    */ 
    public void registerDataSetObserver(DataSetObserver arg0) { 

    } 

    /** 
    * No need of a data observer 
    * 
    * @param DataSetObserver arg0 
    * @return void 
    */ 
    public void unregisterDataSetObserver(DataSetObserver arg0) { 

    } 

    /** 
    * No item should be selectable 
    * 
    * @return boolean 
    */ 
    public boolean areAllItemsEnabled() { 

     return false; 
    } 

    /** 
    * No item should be selectable 
    * 
    * @param int pos 
    * @return boolean 
    */ 
    public boolean isEnabled(int arg0) { 

     return false; 
    } 
} 

Die Aktivität

Die XMLLoaderThread funktioniert gut, es ist nur notifyDatasetChanged scheint nichts zu tun ...

/** 
* Obtain and display the online scores 
* 
* @author soh#zolex 
* 
*/ 
public class OnlineScoresDetails extends ListActivity { 

    WakeLock wakeLock; 
    OnlineScoresAdapter adapter; 
    boolean isLoading = false; 
    int chunkLimit = 50; 
    int chunkOffset = 0; 

    @Override 
    /** 
    * Load the scores and initialize the pager and adapter 
    * 
    * @param Bundle savedInstanceState 
    */ 
    public void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 

     PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); 
     this.wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "racesow"); 

     adapter = new OnlineScoresAdapter(this); 
     setListAdapter(adapter); 
     this.loadData(); 

     setContentView(R.layout.listview); 
     getListView().setOnScrollListener(new OnScrollListener() { 

      public void onScrollStateChanged(AbsListView view, int scrollState) { 

      } 

      public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 

       if (totalItemCount > 0 && visibleItemCount > 0 && firstVisibleItem + visibleItemCount >= totalItemCount) { 

        if (!isLoading) { 

         loadData(); 
        } 
       } 
      } 
     }); 
    } 

    public void loadData() { 

     final ProgressDialog pd = new ProgressDialog(OnlineScoresDetails.this); 
     pd.setProgressStyle(ProgressDialog.STYLE_SPINNER); 
     pd.setMessage("Obtaining scores..."); 
     pd.setCancelable(false); 
     pd.show(); 

     isLoading = true; 
     String mapName = getIntent().getStringExtra("map"); 
     XMLLoaderThread t = new XMLLoaderThread("http://racesow2d.warsow-race.net/map_positions.php?name=" + mapName + "&offset=" + this.chunkOffset + "&limit=" + this.chunkLimit, new Handler() { 

      @Override 
      public void handleMessage(Message msg) { 

       switch (msg.what) { 

        // network error 
        case 0: 
         new AlertDialog.Builder(OnlineScoresDetails.this) 
          .setMessage("Could not obtain the maplist.\nCheck your network connection and try again.") 
          .setNeutralButton("OK", new OnClickListener() { 

           public void onClick(DialogInterface arg0, int arg1) { 

            finish(); 
            overridePendingTransition(0, 0); 
           } 
          }) 
          .show(); 
         break; 

        // maplist received 
        case 1: 
         pd.dismiss(); 
         InputStream xmlStream; 
         try { 

          xmlStream = new ByteArrayInputStream(msg.getData().getString("xml").getBytes("UTF-8")); 
          XMLParser parser = new XMLParser(); 
          parser.read(xmlStream); 

          NodeList positions = parser.doc.getElementsByTagName("position"); 
          int numPositions = positions.getLength(); 
          for (int i = 0; i < numPositions; i++) { 

           Element position = (Element)positions.item(i); 

           ScoreItem score = new ScoreItem(); 
           score.position = Integer.parseInt(parser.getValue(position, "no")); 
           score.player = parser.getValue(position, "player"); 
           score.time = Float.parseFloat(parser.getValue(position, "time")); 
           score.created_at = parser.getValue(position, "created_at"); 

           adapter.addItem(score); 
          } 

          adapter.notifyDataSetChanged(); 


          chunkOffset += chunkLimit; 
          isLoading = false; 

         } catch (UnsupportedEncodingException e) { 

          new AlertDialog.Builder(OnlineScoresDetails.this) 
           .setMessage("Internal error: " + e.getMessage()) 
           .setNeutralButton("OK", null) 
           .show(); 
         } 

         break; 
       } 

       pd.dismiss(); 
      } 
     }); 

     t.start(); 
    } 

    /** 
    * Acquire the wakelock on resume 
    */ 
    public void onResume() { 

     super.onResume(); 
     this.wakeLock.acquire(); 
    } 

    /** 
    * Release the wakelock when leaving the activity 
    */ 
    public void onDestroy() { 

     super.onDestroy(); 
     this.wakeLock.release(); 
    } 

    /** 
    * Disable animations when leaving the activity 
    */ 
    public void onBackPressed() { 

     this.finish(); 
     this.overridePendingTransition(0, 0); 
    } 
} 
+0

erhalten Sie eine Fehlermeldung? Haben Sie auch den Wert von numPositions vor der for-Schleife überprüft? –

+0

wie ich schon sagte, wenn ich setListAdapter() anstelle von notifiyDataSetChanged() aufrufen, erscheinen die Daten ... aber dann beginnt die Liste ganz oben und nicht wo der Benutzer gescrollt hat. also die Daten sind da aber die Ansicht wird nicht aktualisiert –

+0

habe es auch mit einer AsyncTask versucht, gleiches Ergebnis, keine Aktualisierung der Ansicht, nur wenn ich setAdapter() erneut aufrufen –

Antwort

0

Sie sollten nach jeder Manipulation Ihres Datensatzes adapter.notifyDataSetChanged() aufrufen. Wenn Sie Elemente in einem Batch-Zugabe (beispielsweise ein for -loop), bedeutet dies, Sie .notifyDataSetChanged in der Schleife zu setzen haben, etwa so:

for(int i = 0; i < numPositions; i++) { 
    .... 
    adapter.addItem(score); 
    adapter.notifyDataSetChanged(); 
} 

Stellen Sie sicher, adapter.notifyDataSetChanged() von Ihrem UI-Thread aufrufen.

Wenn Sie lieber einmal Ihren Adapter aktualisieren, speichern Sie Ihre ScoreItem s in einem ArrayList und nach dem Aufruf Schleife:

adapter.addAll(scoreList); 
adapter.notifyDataSetChanged(); 

Aber dann wieder, soweit ich keinen Grund, es gibt wirklich bewusst bin, das zu tun .

+0

Ich habe auch versucht, notify in der Schleife anzurufen, aber es hat nichts geändert. –

+0

Es sieht so aus, als würden Sie es nicht über den UI-Thread aufrufen. Stellen Sie sicher, dass Sie '.notifyDataSetChanged()' von Ihrem UI-Thread aus aufrufen, z. mit runOnuiThread (new Runnable() {...}); – Reinier

+0

ändert auch nichts –

1

Ich bin nicht wirklich sicher, ob Ihre Implementierung von Custom BaseAdapter korrekt ist.

Try Ändern

public long getItemId(int pos) { 
    return 0; 
} 

zu

public long getItemId(int pos) { 
    return pos; 
} 

ich auch diese einfachen tutorial gefunden, die hilfreich sein könnten, wie BaseAdapter zu implementieren. Nachdem Sie das Problem behoben haben, können Sie notifyDataSetChanged() erneut versuchen.

+0

das hat nicht geholfen –

+0

das ist, was für mich gearbeitet hat. Ich habe ein wenig Nachforschungen angestellt, und es sieht so aus, als hätte BaseAdapter ohne Data ItD keinen DataSetObserver, ohne den Ihr Adapter natürlich nicht über Änderungen der Daten informiert wird. –

5

Ein bisschen spät, aber die Antwort ist, dass Sie nicht

implementieren sollten
public void registerDataSetObserver(DataSetObserver arg0) { 

} 

public void unregisterDataSetObserver(DataSetObserver arg0) { 

} 

Ich hatte nur eine einfache BaseAdapter wie beabsichtigt, die aufhören zu arbeiten, nachdem diese beiden Methoden hinzufügen. Ich nehme an, dass "jemand" Datenänderungen und solche :) beobachten muss