2012-04-05 31 views
10

tại sao listview của tôi không cập nhật khi tôi gọi notifyDatasetChanged()? cách duy nhất tôi có thể làm cho nó hiển thị dữ liệu là, để gọi setAdatper() trên ListView một lần nữa ... tôi cũng đã cố gắng gọi nó qua runOnUIThread() mà không thay đổi bất cứ điều gìBaseAdapter.notifyDatasetChanged() không cập nhật ListView

Các Adaptor

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

Activity

Các XMLLoaderThread hoạt động tốt, nó chỉ là notifyDatasetChanged dường như không làm gì cả ...

/** 
* 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

bạn có phải là một thông báo lỗi không? Ngoài ra, bạn đã kiểm tra giá trị của numPositions trước vòng lặp for? –

+0

như tôi đã nói, khi tôi gọi setListAdapter() thay vì notifiyDataSetChanged() dữ liệu xuất hiện ... nhưng sau đó danh sách bắt đầu ở trên cùng và không phải nơi người dùng đã cuộn đến. vì vậy dữ liệu ở đó nhưng khung nhìn không được cập nhật –

+0

cũng đã thử nó với một AsyncTask bây giờ, cùng một kết quả, không cập nhật của khung nhìn, chỉ khi tôi gọi setAdapter() một lần nữa –

Trả lời

0

Bạn nên gọi adapter.notifyDataSetChanged() sau mỗi thao tác của tập dữ liệu. Nếu bạn đang thêm các mục trong một lô (ví dụ một -loop for), điều này có nghĩa là bạn phải đặt .notifyDataSetChanged trong vòng lặp của bạn, như vậy:

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

Đảm bảo bạn gọi adapter.notifyDataSetChanged() từ UI-thread của bạn.

Nếu bạn thay vì cập nhật adapter của bạn một lần, lưu trữ ScoreItem của bạn trong một ArrayList và sau khi cuộc gọi vòng lặp:

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

Nhưng sau đó một lần nữa, như xa như tôi biết có thực sự không có lý do để làm điều đó .

+0

Tôi cũng đã cố gắng gọi thông báo trong vòng lặp nhưng nó không thay đổi bất cứ điều gì. –

+0

Có vẻ như bạn không gọi nó từ Giao diện người dùng. Đảm bảo gọi '.notifyDataSetChanged()' từ chuỗi giao diện người dùng của bạn, ví dụ: bằng cách sử dụng runOnuiThread (Runnable mới() {...}); – Reinier

+0

cũng không thay đổi bất cứ điều gì –

1

Tôi không thực sự chắc chắn nếu việc triển khai Custom BaseAdapter của bạn là chính xác.

Hãy thử thay đổi

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

để

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

Tôi cũng thấy đơn giản tutorial này có thể hữu ích về cách thực hiện BaseAdapter. Sau khi bạn nhận được điều này, bạn có thể thử lại notificationDataSetChanged().

+0

không giúp được –

+0

đây là những gì hiệu quả đối với tôi. Tôi đã làm một chút nghiên cứu, và có vẻ như không cung cấp itemId hợp lệ, BaseAdapter sẽ không có DataSetObserver mà không có nó, rõ ràng, adapter của bạn sẽ không được thông báo về những thay đổi dữ liệu. –

5

Một hơi muộn nhưng câu trả lời là bạn không nên thực hiện

public void registerDataSetObserver(DataSetObserver arg0) { 

} 

public void unregisterDataSetObserver(DataSetObserver arg0) { 

} 

Tôi chỉ có một đơn giản BaseAdapter làm việc như dự định, người ngừng làm việc sau khi thêm hai phương pháp. Tôi giả sử rằng "ai đó" cần quan sát các thay đổi dữ liệu và như vậy :)

Các vấn đề liên quan