CellTable - Synchronization problem with AsyncDataProvider

543 views
Skip to first unread message

Magnus

unread,
Aug 26, 2012, 9:13:27 AM8/26/12
to google-we...@googlegroups.com
Hello,

I have a class "UserListPanel", which shows a CellTable of users. When such a panel is created it initially shows all existing users.

The set of users in the list may be changed by calling a method "setUserFilter", e. g. for selecting all users that match some criteria. Then, the list is reloaded by calling "CellTable.setVisibleRangeAndClearData".

There is a problem, when setUserFilter is called immediately after class instantiation:

UserListPanel p = new UserListPanel ();
RootLayoutPanel.get().add(p);
UserFilter f = new UserFilter (some criteria);
Window.alert ("Test");
p.setFilter (f); // has no effect, when Window.alert above is omitted

In this case, the call to setFilter has no effect, i. e. the list shows all users.

Note that within the AsyncDataProvider's onRangeChange a RPC call to the server is made in order to fetch data from the database.

I assume that there is a synchronization problem with the asynchronous calls and that they return in wrong order.
When I trace within "onRangeChanged" by opening a message box with "Window.alert", it works fine.

I also tried to put the reload method into a Scheduler.get().scheduleDeferred, without success.

So I need to ensure that all open RPC calls have returned before the call to setFilter is made.
How can I do that?

I would appreciate any hints.

Thanks 
Magnus


public class UserListPanel extends AbsolutePanel
{
 private CellTable<UserData>              tbl;
 private AsyncDataProvider<UserData>      pvd;
 private UserFilter flt; // filter users to display

 public UserListPanel ()
 {
  ...
  initTable ();
 }
 
 private void initTable ()
 {
  ...
  tbl.setPageStart (0);
  tbl.setPageSize (PAGESIZE);
  
  pvd = new AsyncDataProvider<UserData>()
  {
   @Override
   protected void onRangeChanged(HasData<UserData> display)
   {
    Range r = display.getVisibleRange();
    int start = r.getStart() + 1;
    int end = start + r.getLength() - 1;

    loadUserDataList (start,end);
   }
  };
   
  pvd.addDataDisplay(tbl);
  
  Pager p = getPager ();
  p.setDisplay(tbl);
  p.setRangeLimited(true);
 }

 public void loadUserDataList (int i0,int i1)
 {
  // call asynchronous service, which calls loadUserDataList below
 }
 
 @Override
 public void loadUserDataList (List<UserData> lst)
 {
  if (lst == null)
   return;
  
  Pager pgr = getPager ();
  Range r = pgr.getDisplay().getVisibleRange();
  int start = r.getStart();

  pvd.updateRowData (start,lst);
 }

 public void setUserFilter (UserFilter flt)
 {
  this.flt = flt;
  reload ();
 }

 public void reload ()
 {
  Range r = tbl.getVisibleRange();
  tbl.setVisibleRangeAndClearData (r,true);
 }


}

Magnus

unread,
Aug 26, 2012, 9:42:26 AM8/26/12
to google-we...@googlegroups.com
Hi,

I found out the following:

When the second call to onRangeChanged occurrs, there are fewer records in the list than visible rows in the CellTable!
The first rows are updated correctly, but the remaining visible rows are not cleared!

So there is probably no synchronization problem, but a display problem:
When after calling tbl.setVisibleRangeAndClearData there are fewer rows than visible rows, the remaining visible rows are not cleared.

When the data comes in it is pushed into the table by a call to provider.updateRowData.
At this moment: How can I ensure that the remaining rows are cleared and why does not CellTable clear them?

Thanks
Magnus

Thomas Broyer

unread,
Aug 26, 2012, 10:14:23 AM8/26/12
to google-we...@googlegroups.com
You should call updateRowCount if the "row count" changes (such as when applying a filter)

Magnus

unread,
Aug 26, 2012, 10:55:43 AM8/26/12
to google-we...@googlegroups.com
Hi Thomas,

I tried to modify the reload method like this, but without success:

 public void reload ()
 {
  pvd.updateRowCount (0,true); // avoid to many visible rows
  
  Range r = tbl.getVisibleRange();
  tbl.setVisibleRangeAndClearData (r,true);
  
  loadRecordCount (); // asynchronously load the real record count
 }

Magnus

Alfredo Quiroga-Villamil

unread,
Aug 26, 2012, 4:18:04 PM8/26/12
to google-we...@googlegroups.com
I have a similar post. I was trying to do something as simple as when
I click on a refresh button to completely clear my provider and
display the freshly received entities from the server. I haven't had
time to go back and look at it, but I would also be interested in
getting a definitive idea as to what the right approach for reloading
a CellTable should be. I not only want to get say 1000 rows and change
what gets displayed by manipulating the visible range. I am talking
about completely clearing my provider and repopulating it with freshly
received objects. I would think a simple clear() and add() in the
provider would do, but it doesn't seem to be that simple. The provider
clears and adds the new list of objects but the display never updates
it. I tried a handful of things to force a resync of the display and
nothing.

I read a whole lot of stuff online and there seems to be many people
confused in this area. I started to dive in also and investigate in
the code, but never finished it. There are a handful of methods that
all look similar but do different things.

My post can be found at:
https://groups.google.com/forum/?fromgroups=#!topic/google-web-toolkit/Qbkgk03-cTs

Any help will be greatly appreciated.

Alfredo
> --
> You received this message because you are subscribed to the Google Groups
> "Google Web Toolkit" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/google-web-toolkit/-/fgp4CJThaXcJ.
>
> To post to this group, send email to google-we...@googlegroups.com.
> To unsubscribe from this group, send email to
> google-web-tool...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/google-web-toolkit?hl=en.



--
Alfredo Quiroga-Villamil

AOL/Yahoo/Gmail/MSN IM: lawwton

Magnus

unread,
Aug 26, 2012, 10:29:55 PM8/26/12
to google-we...@googlegroups.com
Hello,

I found this interesting article:

It also states that one should always update both row count and row data. But when looking to the code in the article, it seems that the author assumes that AsyncDataProvider.updateRowCount expects the number of *visible* rows. My understanding is that it expects the number of *total* rows. Is this correct?

However, I cannot call both at the same time with the exact values. I have to make two different RPC calls, one for the data in onRangeChanged, and one to fetch the total record count.
As I posted before, I call updateRowCount(0) on reload, just to be sure that old rows disappear. Later, when the RPC call for the row count returns, I call updateRowCount with the exact number.

Unfortunately the old rows still remain visible after reload...

Magnus

Magnus

unread,
Aug 27, 2012, 12:58:21 PM8/27/12
to google-we...@googlegroups.com
Hello,

when I add a delay of 1 sec before the reload it works.
So there must still be some sync problem...

What can I test next?

Magnus

-----

 public void setFilter (UserFilter flt)
 {
  sel.setFilter(flt);
  this.flt = flt;
  //reload ();
  delayedReload ();
 }
 
 public void delayedReload ()
 {
  Timer t = new Timer ()
  {
   public void run()
   {
    reload ();
   }
  };
 
  t.schedule (1000);
 }
 
 public void reload ()
 {
  Range r = tbl.getVisibleRange();
  tbl.setVisibleRangeAndClearData (r,true);

  Pager p = getPager ();
  p.firstPage();
  
  loadRecordCount ();
 }

Magnus

unread,
Aug 28, 2012, 7:54:11 AM8/28/12
to google-we...@googlegroups.com
Hi,

I'm sorry, but I made a stupid mistake. I set both row data and row count within on RangeChanged, but I only used the (correct) user filter when fetching the row data via RPC call. When fetching the row count via RPC call I used a new, empty user filter, so the count was wrong.

Sorry for the time...
Magnus
Reply all
Reply to author
Forward
0 new messages