You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

gwt-shared-state.asciidoc 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. ---
  2. title: Shared State
  3. order: 5
  4. layout: page
  5. ---
  6. [[gwt.shared-state]]
  7. = Shared State
  8. The basic communication from a server-side component to its the client-side
  9. widget counterpart is handled using a __shared state__. The shared state is
  10. serialized transparently. It should be considered read-only on the client-side,
  11. as it is not serialized back to the server-side.
  12. A shared state object simply needs to extend the
  13. [classname]#AbstractComponentState#. The member variables should normally be
  14. declared as public.
  15. [source, java]
  16. ----
  17. public class MyComponentState extends AbstractComponentState {
  18. public String text;
  19. }
  20. ----
  21. A shared state should never contain any logic. If the members have private
  22. visibility for some reason, you can also use public setters and getters, in
  23. which case the property must not be public.
  24. [[gwt.shared-state.location]]
  25. == Location of Shared-State Classes
  26. The shared-state classes are used by both server- and client-side classes, but
  27. widget set compilation requires that they must be located in a client-side
  28. source package. The default location is under a [filename]#client# package under
  29. the package of the [filename]#.gwt.xml# descriptor. If you wish to organize the
  30. shared classes separately from other client-side code, you can define separate
  31. client-side source packages for pure client-side classes and any shared classes.
  32. In addition to shared state classes, shared classes could include enumerations
  33. and other classes needed by shared-state or RPC communication.
  34. For example, you could have the following definitions in the
  35. [filename]#.gwt.xml# descriptor:
  36. [source, xml]
  37. ----
  38. <source path="client" />
  39. <source path="shared" />
  40. ----
  41. The paths are relative to the package containing the descriptor.
  42. [[gwt.shared-state.component]]
  43. == Accessing Shared State on Server-Side
  44. A server-side component can access the shared state with the
  45. [methodname]#getState()# method. It is required that you override the base
  46. implementation with one that returns the shared state object cast to the proper
  47. type, as follows:
  48. [source, java]
  49. ----
  50. @Override
  51. public MyComponentState getState() {
  52. return (MyComponentState) super.getState();
  53. }
  54. ----
  55. You can then use the [methodname]#getState()# to access the shared state object
  56. with the proper type.
  57. [source, java]
  58. ----
  59. public MyComponent() {
  60. getState().setText("This is the initial state");
  61. ....
  62. }
  63. ----
  64. [[gwt.shared-state.connector]]
  65. == Handling Shared State in a Connector
  66. A connector can access a shared state with the [methodname]#getState()# method.
  67. The access should be read-only. It is required that you override the base
  68. implementation with one that returns the proper shared state type, as follows:
  69. [source, java]
  70. ----
  71. @Override
  72. public MyComponentState getState() {
  73. return (MyComponentState) super.getState();
  74. }
  75. ----
  76. State changes made on the server-side are communicated transparently to the
  77. client-side. When a state change occurs, the [methodname]#onStateChanged()#
  78. method in the connector is called. You should always call the superclass
  79. method before anything else to handle changes to common component properties.
  80. [source, java]
  81. ----
  82. @Override
  83. public void onStateChanged(StateChangeEvent stateChangeEvent) {
  84. super.onStateChanged(stateChangeEvent);
  85. // Copy the state properties to the widget properties
  86. final String text = getState().getText();
  87. getWidget().setText(text);
  88. }
  89. ----
  90. The crude [methodname]#onStateChanged()# method is called when any of the state
  91. properties is changed, allowing you to have even complex logic in how you
  92. manipulate the widget according to the state changes. In most cases, however,
  93. you can handle the property changes more easily and also more efficiently by
  94. using instead the [classname]#@OnStateChange# annotation on the handler methods
  95. for each property, as described next in <<gwt.shared-state.onstatechange>>, or
  96. by delegating the property value directly to the widget, as described in
  97. <<gwt.shared-state.delegatetowidget>>.
  98. ifdef::web[]
  99. The processing phases of state changes are described in more detail in
  100. <<dummy/../../../framework/gwt/gwt-advanced#gwt.advanced.phases,"Client-Side
  101. Processing Phases">>.
  102. endif::web[]
  103. [[gwt.shared-state.onstatechange]]
  104. == Handling Property State Changes with [classname]#@OnStateChange#
  105. The [classname]#@OnStateChange# annotation can be used to mark a connector
  106. method that handles state change on a particular property, given as parameter
  107. for the annotation. In addition to higher clarity, this avoids handling all
  108. property changes if a state change occurs in only one or some of them. However,
  109. if a state change can occur in multiple properties, you can only use this
  110. technique if the properties do not have interaction that prevents handling them
  111. separately in arbitrary order.
  112. We can replace the [methodname]#onStateChange()# method in the earlier connector
  113. example with the following:
  114. [source, java]
  115. ----
  116. @OnStateChange("text")
  117. void updateText() {
  118. getWidget().setText(getState().text);
  119. }
  120. ----
  121. If the shared state property and the widget property have same name and do not
  122. require any type conversion, as is the case in the above example, you could
  123. simplify this even further by using the [classname]#@DelegateToWidget#
  124. annotation for the shared state property, as described in
  125. <<gwt.shared-state.delegatetowidget>>.
  126. [[gwt.shared-state.delegatetowidget]]
  127. == Delegating State Properties to Widget
  128. The [classname]#@DelegateToWidget# annotation for a shared state property
  129. defines automatic delegation of the property value to the corresponding widget
  130. property of the same name and type, by calling the respective setter for the
  131. property in the widget.
  132. [source, java]
  133. ----
  134. public class MyComponentState extends AbstractComponentState {
  135. @DelegateToWidget
  136. public String text;
  137. }
  138. ----
  139. This is equivalent to handling the state change in the connector, as done in the
  140. example in <<gwt.shared-state.onstatechange>>.
  141. If you want to delegate a shared state property to a widget property of another
  142. name, you can give the property name as a string parameter for the annotation.
  143. [source, java]
  144. ----
  145. public class MyComponentState extends AbstractComponentState {
  146. @DelegateToWidget("description")
  147. public String text;
  148. }
  149. ----
  150. [[gwt.shared-state.referring]]
  151. == Referring to Components in Shared State
  152. While you can pass any regular Java objects through a shared state, referring to
  153. another component requires special handling because on the server-side you can
  154. only refer to a server-side component, while on the client-side you only have
  155. widgets. References to components can be made by referring to their connectors
  156. (all server-side components implement the [interfacename]#Connector# interface).
  157. [source, java]
  158. ----
  159. public class MyComponentState extends AbstractComponentState {
  160. public Connector otherComponent;
  161. }
  162. ----
  163. You could then access the component on the server-side as follows:
  164. [source, java]
  165. ----
  166. public class MyComponent {
  167. public void MyComponent(Component otherComponent) {
  168. getState().otherComponent = otherComponent;
  169. }
  170. public Component getOtherComponent() {
  171. return (Component)getState().otherComponent;
  172. }
  173. // And the cast method
  174. @Override
  175. public MyComponentState getState() {
  176. return (MyComponentState) super.getState();
  177. }
  178. }
  179. ----
  180. On the client-side, you should cast it in a similar fashion to a
  181. [classname]#ComponentConnector#, or possibly to the specific connector type if
  182. it is known.
  183. [[gwt.shared-state.resource]]
  184. == Sharing Resources
  185. Resources, which commonly are references to icons or other images, are another
  186. case of objects that require special handling. A [interfacename]#Resource#
  187. object exists only on the server-side and on the client-side you have an URL to
  188. the resource. You need to use the [methodname]#setResource()# and
  189. [methodname]#getResource()# on the server-side to access a resource, which is
  190. serialized to the client-side separately.
  191. Let us begin with the server-side API:
  192. [source, java]
  193. ----
  194. public class MyComponent extends AbstractComponent {
  195. ...
  196. public void setMyIcon(Resource myIcon) {
  197. setResource("myIcon", myIcon);
  198. }
  199. public Resource getMyIcon() {
  200. return getResource("myIcon");
  201. }
  202. }
  203. ----
  204. On the client-side, you can then get the URL of the resource with
  205. [methodname]#getResourceUrl()#.
  206. [source, java]
  207. ----
  208. @Override
  209. public void onStateChanged(StateChangeEvent stateChangeEvent) {
  210. super.onStateChanged(stateChangeEvent);
  211. ...
  212. // Get the resource URL for the icon
  213. getWidget().setMyIcon(getResourceUrl("myIcon"));
  214. }
  215. ----
  216. The widget could then use the URL, for example, as follows:
  217. [source, java]
  218. ----
  219. public class MyWidget extends Label {
  220. ...
  221. Element imgElement = null;
  222. public void setMyIcon(String url) {
  223. if (imgElement == null) {
  224. imgElement = DOM.createImg();
  225. getElement().appendChild(imgElement);
  226. }
  227. DOM.setElementAttribute(imgElement, "src", url);
  228. }
  229. }
  230. ----