We have a GWT application which crashes in Firefox versions 21 and above, including in the latest version 23.0.1. In earlier versions of Firefox and IE 9, it works fine. This is in deployed mode and not because of the GWT plugin. The situation it crashes is when there are huge number of RPC calls, may be around 300 to 400.
As the application in which it happens is fairly complex, I tried to simulate this issue with a simple prototype. I observed that my prototype crashes when the number of RPC calls reach 100000. But this scenario is very unlikely in my application where RPC calls are around 300-400 as observed using Firebug.
I am trying to find out what else I am missing in my prototype so that it also crashes with 300-400 RPC calls.
GWT version - 2.4
GXT version - 2.2.5
package com.ganesh.check.firefox.client;
public class FirefoxCrash implements EntryPoint {
private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network "
+ "connection and try again.";
private final GreetingServiceAsync greetingService = GWT
.create(GreetingService.class);
public native static void consoleLog(String text)/*-{
$wnd.console.log(text);
}-*/;
public void onModuleLoad() {
final Button sendButton = new Button("Send");
final TextBox nameField = new TextBox();
nameField.setText("GWT User");
final Label errorLabel = new Label();
final Label countLabel = new Label();
// We can add style names to widgets
sendButton.addStyleName("sendButton");
// Add the nameField and sendButton to the RootPanel
// Use RootPanel.get() to get the entire body element
RootPanel.get("nameFieldContainer").add(nameField);
RootPanel.get("sendButtonContainer").add(sendButton);
RootPanel.get("errorLabelContainer").add(errorLabel);
RootPanel.get("count").add(countLabel);
// Focus the cursor on the name field when the app loads
nameField.setFocus(true);
nameField.selectAll();
// Create the popup dialog box
final DialogBox dialogBox = new DialogBox();
dialogBox.setText("Remote Procedure Call");
dialogBox.setAnimationEnabled(true);
final Button closeButton = new Button("Close");
// We can set the id of a widget by accessing its Element
closeButton.getElement().setId("closeButton");
final Label textToServerLabel = new Label();
final HTML serverResponseLabel = new HTML();
VerticalPanel dialogVPanel = new VerticalPanel();
dialogVPanel.addStyleName("dialogVPanel");
dialogVPanel.add(new HTML("<b>Sending name to the server:</b>"));
dialogVPanel.add(textToServerLabel);
dialogVPanel.add(new HTML("<br><b>Server replies:</b>"));
dialogVPanel.add(serverResponseLabel);
dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
dialogVPanel.add(closeButton);
dialogBox.setWidget(dialogVPanel);
// Add a handler to close the DialogBox
closeButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
dialogBox.hide();
sendButton.setEnabled(true);
sendButton.setFocus(true);
}
});
class MyHandler implements ClickHandler, KeyUpHandler {
private int resultCount = 0;
/**
* Fired when the user clicks on the sendButton.
*/
public void onClick(ClickEvent event) {
sendNameToServer();
}
public void onKeyUp(KeyUpEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
sendNameToServer();
}
}
private void sendNameToServer() {
// First, we validate the input.
errorLabel.setText("");
String textToServer = nameField.getText();
// Then, we send the input to the server.
textToServerLabel.setText(textToServer);
serverResponseLabel.setText("");
final int loopCount = Integer.parseInt(textToServer);
resultCount=0;
for (int i = 0; i < loopCount; i++) {
greetingService.getResult(textToServer,
new AsyncCallback<ResultBean>() {
public void onFailure(Throwable caught) {
consoleLog(caught.getMessage());
}
public void onSuccess(ResultBean result) {
//countLabel.setText(++resultCount + "");
resultCount++;
if(resultCount==loopCount){
countLabel.setText(resultCount + "");
}
consoleLog("Result returned for "+resultCount);
}
});
}
}
}
// Add a handler to send the name to the server
MyHandler handler = new MyHandler();
sendButton.addClickHandler(handler);
nameField.addKeyUpHandler(handler);
}
}
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService {
public ResultBean getResult(String name) {
ResultBean result = new ResultBean();
Random random = new Random();
int suffix = random.nextInt();
result.setName("Name "+suffix);
result.setAddress("Address "+suffix);
result.setZipCode(suffix);
result.setDoorNumber("Door "+suffix);
return result;
}
public class ResultBean implements Serializable {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getZipCode() {
return zipCode;
}
public void setZipCode(int zipCode) {
this.zipCode = zipCode;
}
public String getDoorNumber() {
return doorNumber;
}
public void setDoorNumber(String doorNumber) {
this.doorNumber = doorNumber;
}
private String name;
private String address;
private int zipCode;
private String doorNumber;
}
Related
In my Android app I use AAC.
Here my activity:
public class AddTraderActivity extends AppCompatActivity {
AddTraderViewModel addTraderViewModel;
private static final String TAG = AddTraderActivity.class.getName();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AddTraderActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.add_trader_activity);
binding.setHandler(this);
init();
}
private void init() {
ViewModelProvider viewViewModelProvider = ViewModelProviders.of(this);
addTraderViewModel = viewViewModelProvider.get(AddTraderViewModel.class);
Observer<String> () {
#Override
public void onChanged (String message){
Debug.d(TAG, "onChanged: message = " + message);
Toast.makeText(AddTraderActivity.this, message, Toast.LENGTH_LONG).show();
}
});
}
public void onClickStart() {
EditText baseEditText = findViewById(R.id.baseEditText);
EditText quoteEditText = findViewById(R.id.quoteEditText);
addTraderViewModel.doClickStart(baseEditText.getText().toString(), quoteEditText.getText().toString());
}
}
Here my ViewModel:
public class AddTraderViewModel extends AndroidViewModel {
private MutableLiveData<String> messageLiveData = new MutableLiveData<>();
private static final String TAG = AddTraderViewModel.class.getName();
public AddTraderViewModel(#NonNull Application application) {
super(application);
}
public void doClickStart(String base, String quote) {
Debug.d(TAG, "doClickStart: ");
if (base.trim().isEmpty() || quote.trim().isEmpty()) {
String message = getApplication().getApplicationContext().getString(R.string.please_input_all_fields);
messageLiveData.setValue(message);
return;
}
}
public LiveData<String> getMessageLiveData() {
return messageLiveData;
}
}
So when I click on button on Activity call method onClickStart()
If any fields is empty the show toast. In the activity call method:
onChanged (String message)
Nice. It's work fine.
But the problem is, when I rotate the device in the activity method onChanged(String message) is called AGAIN and as result show toast. This happened on every rotation.
Why?
This is the expected behaviour. If you want to avoid this you must set message = "" and keep an empty check before showing the toast.
A better way to use it is something like Event Wrapper or SingleLiveEvent
Highly recommend you to read this article. This explains why you are facing this and what are your options in detail.
I am using Room Database with LiveData , but my Local Database is updating too fast as per our requirement and at the same time i have to reload my recycler view .instead of calling notifyDataSetChanged() to adapter , i am trying to use DiffUtil , but is crashing or not reloading properly , this is uncertain .
i am following this tutorial :
Tutorials Link here
MyAdapter :
public class SwitchGridAdapter extends RecyclerView.Adapter<SwitchGridAdapter.ViewHolder> {
private List<Object> allItemsList;
private LayoutInflater mInflater;
private OnItemClickListener mClickListener;
private Context context;
private Queue<List<Object>> pendingUpdates =
new ArrayDeque<>();
// data is passed into the constructor
public SwitchGridAdapter(Context context,List<Appliance> applianceList,List<ZmoteRemote> zmoteRemoteList) {
this.mInflater = LayoutInflater.from(context);
this.context = context;
allItemsList = new ArrayList<>();
if (applianceList!=null) allItemsList.addAll(applianceList);
if (zmoteRemoteList!=null)allItemsList.addAll(zmoteRemoteList);
}
// inflates the cell layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R .layout.switch_grid_item, parent, false);
return new ViewHolder(view);
}
// binds the data to the textview in each cell
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Doing some update with UI Elements
}
// total number of cells
#Override
public int getItemCount() {
return allItemsList.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener,View.OnLongClickListener {
TextView myTextView;
ImageView imgSwitch;
ViewHolder(View itemView) {
super(itemView);
myTextView = (TextView) itemView.findViewById(R.id.txtSwitchName);
imgSwitch = (ImageView) itemView.findViewById(R.id.imgSwitchStatus);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
#Override
public void onClick(View view) {
// handling click
}
#Override
public boolean onLongClick(View view) {
return true;
}
// convenience method for getting data at click position
Object getItem(int id) {
return allItemsList.get(id);
}
// allows clicks events to be caught
public void setClickListener(OnItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongPressListner(View view, int position);
}
// ✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅
// From This Line Reloading with Diff Util is Done .
//✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅
public void setApplianceList( List<Appliance> applianceList,List<ZmoteRemote> zmoteRemoteList)
{
if (allItemsList == null)
allItemsList = new ArrayList<>();
List<Object> newAppliances = new ArrayList<>();
if (applianceList!=null) newAppliances.addAll(applianceList);
updateItems(newAppliances);
}
// when new data becomes available
public void updateItems(final List<Object> newItems) {
pendingUpdates.add(newItems);
if (pendingUpdates.size() > 1) {
return;
}
updateItemsInternal(newItems);
}
// This method does the heavy lifting of
// pushing the work to the background thread
void updateItemsInternal(final List<Object> newItems) {
final List<Object> oldItems = new ArrayList<>(this.allItemsList);
final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
final DiffUtil.DiffResult diffResult =
DiffUtil.calculateDiff(new DiffUtilHelper(oldItems, newItems));
handler.post(new Runnable() {
#Override
public void run() {
applyDiffResult(newItems, diffResult);
}
});
}
}).start();
}
// This method is called when the background work is done
protected void applyDiffResult(List<Object> newItems,
DiffUtil.DiffResult diffResult) {
dispatchUpdates(newItems, diffResult);
}
// This method does the work of actually updating
// the backing data and notifying the adapter
protected void dispatchUpdates(List<Object> newItems,
DiffUtil.DiffResult diffResult) {
// ❌❌❌❌❌❌ Next Line is Crashing the app ❌❌❌❌❌
pendingUpdates.remove();
dispatchUpdates(newItems, diffResult);
if (pendingUpdates.size() > 0) {
updateItemsInternal(pendingUpdates.peek());
}
}
}
Observing LiveData
public void setUpAppliancesListLiveData()
{
if (applianceObserver!=null)
{
applianceObserver = null;
}
Log.e("Appliance Fetch","RoomName:"+this.roomName);
applianceObserver = new Observer<List<Appliance>>() {
#Override
public void onChanged(#Nullable List<Appliance> applianceEntities) {
// Log.e("Appliance Result","Appliance List \n\n:"+applianceEntities.toString());
new Thread(new Runnable() {
#Override
public void run() {
List<Appliance> applianceListTemp = applianceEntities;
zmoteRemoteList = new ArrayList<>(); //appDelegate.getDatabase().zmoteRemoteDao().getRemoteList(roomName);
// Sort according to name
Collections.sort(applianceListTemp, new Comparator<Appliance>() {
#Override
public int compare(Appliance item, Appliance t1) {
String s1 = item.getSwitchName();
String s2 = t1.getSwitchName();
return s1.compareToIgnoreCase(s2);
}
});
if(getActivity()!=null) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
applianceList = applianceListTemp;
mRecyclerView.getRecycledViewPool().clear();
adapter.setApplianceList(applianceList,zmoteRemoteList);
}
});
}
}
}).start();
}
};
appDelegate.getDatabase().applianceDao().getApplinaceListByRoomName(this.roomName).observe(this, applianceObserver);
}
I am working on a simple app which will run on both wearable(Samsung Gear Live) and handheld(Moto G). I want to display the data from the wearable's heart rate sensor, accelerometer and gyroscope on the handheld. Which is the best way to achieve this.
Now I am using DataApi, but since I am updating data each second, it is allocating too much memory, and then killed by OS.
Here is my service which runs on the wearable
public class SensorDataListener extends Service implements SensorEventListener,
ConnectionCallbacks, OnConnectionFailedListener {
private static final String TAG = SensorDataListener.class.getSimpleName();
private static final int TIMEOUT_HEART_RATE = 1000000;
private static final int TIMEOUT_ACCELEROMETER = 1000000;
private static final int TIMEOUT_GYROSCOPE = 1000000;
private static final String PATH_SENSOR_DATA = "/sensor_data";
private static final String KEY_HEART_RATE = "heart_rate";
private static final String KEY_ACC_X = "acc_x";
private static final String KEY_ACC_Y = "acc_y";
private static final String KEY_ACC_Z = "acc_z";
private static final String KEY_GYRO_X = "gyro_x";
private static final String KEY_GYRO_Y = "gyro_y";
private static final String KEY_GYRO_Z = "gyro_z";
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private Sensor mGyroscope;
private Sensor mHeartRate;
private int mCurHeartRateVal;
private float[] mCurAccelerometerVal = new float[3];
private float[] mCurGyroscopeVal = new float[3];
private GoogleApiClient mGoogleApiClient;
ScheduledExecutorService mUpdateScheduler;
ScheduledExecutorService scheduler;
#Override
public void onCreate() {
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(com.google.android.gms.wearable.Wearable.API)
.build();
mGoogleApiClient.connect();
mSensorManager = ((SensorManager)getSystemService(SENSOR_SERVICE));
mHeartRate = mSensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
startDataUpdated();
}
private void startDataUpdated() {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate
(new Runnable() {
public void run() {
updateData();
}
}, 5, 3, TimeUnit.SECONDS);
}
private void updateData() {
PutDataMapRequest dataMap = PutDataMapRequest.create(PATH_SENSOR_DATA);
dataMap.getDataMap().putInt(KEY_HEART_RATE, mCurHeartRateVal);
dataMap.getDataMap().putFloat(KEY_ACC_X, mCurAccelerometerVal[0]);
dataMap.getDataMap().putFloat(KEY_ACC_Y, mCurAccelerometerVal[1]);
dataMap.getDataMap().putFloat(KEY_ACC_Z, mCurAccelerometerVal[2]);
dataMap.getDataMap().putFloat(KEY_GYRO_X, mCurGyroscopeVal[0]);
dataMap.getDataMap().putFloat(KEY_GYRO_Y, mCurGyroscopeVal[1]);
dataMap.getDataMap().putFloat(KEY_GYRO_Z, mCurGyroscopeVal[2]);
PutDataRequest request = dataMap.asPutDataRequest();
Wearable.DataApi.putDataItem(mGoogleApiClient, request);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mSensorManager.registerListener(this, mHeartRate, TIMEOUT_HEART_RATE);
mSensorManager.registerListener(this, mAccelerometer, TIMEOUT_ACCELEROMETER);
mSensorManager.registerListener(this, mGyroscope, TIMEOUT_GYROSCOPE);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
mGoogleApiClient.disconnect();
scheduler.shutdown();
mSensorManager.unregisterListener(this);
//mUpdateScheduler.shutdownNow();
super.onDestroy();
}
#Override
public void onSensorChanged(SensorEvent event) {
switch(event.sensor.getType()) {
case Sensor.TYPE_HEART_RATE:
if(event.values[0] <= 0) // HR sensor is being initialized
return;
mCurHeartRateVal = Float.valueOf(event.values[0]).intValue();
break;
case Sensor.TYPE_ACCELEROMETER:
mCurAccelerometerVal[0] = event.values[0];
mCurAccelerometerVal[1] = event.values[1];
mCurAccelerometerVal[2] = event.values[2];
break;
case Sensor.TYPE_GYROSCOPE: {
mCurGyroscopeVal[0] = event.values[0];
mCurGyroscopeVal[1] = event.values[1];
mCurGyroscopeVal[2] = event.values[2];
break;
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
#Override
public void onConnected(Bundle bundle) { Log.d(TAG, "onConnected"); }
#Override
public void onConnectionSuspended(int i) { Log.d(TAG, "onConnectionSuspended"); }
#Override
public void onConnectionFailed(ConnectionResult connectionResult) { Log.d(TAG, "onConnectionFailed"); }
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Try using the Message API instead of the Data API. Simply create a message containing your data and send it over to your other device : http://developer.android.com/reference/com/google/android/gms/wearable/MessageApi.html
Have you try with Teleport (data sync & messaging lib) by Mario Viviani
I have created a widget to display the slideshow.In firefox,everything is fine but in chrome nothing happens. After I refresh with many times, the slideshow is displayed. I don't know Why. Can you give me some ideas? Tks
This is my GWT client:
public SlideClient() {
super();
setStyleName("flexslider");
setHeight("100%");
setWidth("100%");
}
#Override
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
this.client = client;
this.paintableId = uidl.getId();
listImage = Arrays.asList(uidl.getStringArrayAttribute("listImage"));
listUrl = Arrays.asList(uidl.getStringArrayAttribute("listUrl"));
loadImage();
checkImagesLoadedTimer.run();
}
public void display() {
m.setStyleName("slides");
m.setHeight("100%");
m.setWidth("100%");
add(m);
}
public native void slideshow() /*-{
$wnd.$('.flexslider').flexslider({slideshowSpeed: 2000});
}-*/;
public native String getURL(String url)/*-{
return $wnd.open(url,
'target=_blank')
}-*/;
private Timer checkImagesLoadedTimer = new Timer() {
#Override
public void run() {
if (loadedImageElements.size() == toLoad) {
display();
} else {
add(new Label("đang load "+loadedImageElements.size()));
checkImagesLoadedTimer.schedule(2000);
}
}
};
private void loadImage() {
for (String tmp : listImage) {
AbsolutePanel panel = new AbsolutePanel();
final Image ima = new Image(tmp);
add(new Label("before put"));
ima.addLoadHandler(new LoadHandler() {
#Override
public void onLoad(LoadEvent event) {
loadedImageElements.put(toLoad+"", ima);
slideshow();
add(new Label("đang put "+loadedImageElements.size()));
}
});
add(new Label("after put"));
panel.add(ima);
m.add(panel);
if (toLoad != 0) {
panel.setVisible(false);
}
toLoad++;
}
}
}
Did you implement an Image Loader to prepare your images before they are displayed? A clean solution would be to add the image elements to your page root as an invisible istance, wait for them to load and then use them elsewhere.
You should check out the tutorials about ImageBundling as well: ImageResource
Here's a little extract from one of my image loader classes as you requested, altough there are different ways to realize that:
private HashMap<String,ImageElement> loadedImageElements = new HashMap<String,ImageElement>();
private int toLoad = 0;
private void loadImage(final String name, String url){
final Image tempImage = new Image(url);
RootPanel.get().add(tempImage);
++toLoad;
tempImage.addLoadHandler(new LoadHandler(){
public void onLoad(LoadEvent event) {
loadedImageElements.put(name,ImageElement.as(tempImage.getElement()));
tempImage.setVisible(false);
}
});
}
The image url is retrieved via a ClientBundle-Interface pointing towards the real positions of the images.
I also implemented a timer running in the background to check if all the images have been loaded:
private Timer checkImagesLoadedTimer = new Timer(){
public void run() {
System.out.println("Loaded " + loadedImageElements.size() + "/" + toLoad + " Images.");
if(loadedImageElements.size() == toLoad){
buildWidget();
}else{
checkImagesLoadedTimer.schedule(50);
}
}
};
After everythign is ready, the original widget/page is created.
But as I said there are many ways to implement image loaders. Try out different implementations and select one that suits your needs best.
Hi I'm trying to retrieve a linkedhashset from the Google datastore but nothing seems to happen. I want to display the results in a Grid using GWT on a page. I have put system.out.println() in all the classes to see where I go wrong but it only shows one and I don't recieve any errors. I use 6 classes 2 in the server package(ContactDAOJdo/ContactServiceImpl) and 4 in the client package(ContactService/ContactServiceAsync/ContactListDelegate/ContactListGui). I hope someone can explain why this isn't worken and point me in the right direction.
public class ContactDAOJdo implements ContactDAO {
#SuppressWarnings("unchecked")
#Override
public LinkedHashSet<Contact> listContacts() {
PersistenceManager pm = PmfSingleton.get().getPersistenceManager();
String query = "select from " + Contact.class.getName();
System.out.print("ContactDAOJdo: ");
return (LinkedHashSet<Contact>) pm.newQuery(query).execute();
}
}
public class ContactServiceImpl extends RemoteServiceServlet implements ContactService{
private static final long serialVersionUID = 1L;
private ContactDAO contactDAO = new ContactDAOJdo() {
#Override
public LinkedHashSet<Contact> listContacts() {
LinkedHashSet<Contact> contacts = contactDAO.listContacts();
System.out.println("service imp "+contacts);
return contacts;
}
}
#RemoteServiceRelativePath("contact")
public interface ContactService extends RemoteService {
LinkedHashSet<Contact> listContacts();
}
public interface ContactServiceAsync {
void listContacts(AsyncCallback<LinkedHashSet <Contact>> callback);
}
public class ListContactDelegate {
private ContactServiceAsync contactService = GWT.create(ContactService.class);
ListContactGUI gui;
void listContacts(){
contactService.listContacts(new AsyncCallback<LinkedHashSet<Contact>> () {
public void onFailure(Throwable caught) {
gui.service_eventListContactenFailed(caught);
System.out.println("delegate "+caught);
}
public void onSuccess(LinkedHashSet<Contact> result) {
gui.service_eventListRetrievedFromService(result);
System.out.println("delegate "+result);
}
});
}
}
public class ListContactGUI {
protected Grid contactlijst;
protected ListContactDelegate listContactService;
private Label status;
public void init() {
status = new Label();
contactlijst = new Grid();
contactlijst.setVisible(false);
status.setText("Contact list is being retrieved");
placeWidgets();
}
public void service_eventListRetrievedFromService(LinkedHashSet<Contact> result){
System.out.println("1 service eventListRetreivedFromService "+result);
status.setText("Retrieved contactlist list");
contactlijst.setVisible(true);
this.contactlijst.clear();
this.contactlijst.resizeRows(1 + result.size());
int row = 1;
this.contactlijst.setWidget(0, 0, new Label ("Voornaam"));
this.contactlijst.setWidget(0, 1, new Label ("Achternaam"));
for(Contact contact: result) {
this.contactlijst.setWidget(row, 0, new Label (contact.getVoornaam()));
this.contactlijst.setWidget(row, 1, new Label (contact.getVoornaam()));
row++;
System.out.println("voornaam: "+contact.getVoornaam());
}
System.out.println("2 service eventListRetreivedFromService "+result);
}
public void placeWidgets() {
System.out.println("placewidget inside listcontactgui" + contactlijst);
RootPanel.get("status").add(status);
RootPanel.get("contactlijst").add(contactlijst);
}
public void service_eventListContactenFailed(Throwable caught) {
status.setText("Unable to retrieve contact list from database.");
}
}
It could be the query returns a lazy list. Which means not all values are in the list at the moment the list is send to the client. I used a trick to just call size() on the list (not sure how I got to that solution, but seems to work):
public LinkedHashSet<Contact> listContacts() {
final PersistenceManager pm = PmfSingleton.get().getPersistenceManager();
try {
final LinkedHashSet<Contact> contacts =
(LinkedHashSet<Contact>) pm.newQuery(Contact.class).execute();
contacts.size(); // this triggers to get all values.
return contacts;
} finally {
pm.close();
}
}
But I'm not sure if this is the best practice...