StockTracker演示了当数据改变时,如何使用Java把改变的数据显示到用户界面上。
这是一个非常实用的例子,其中数据的改变使用了Java多线程技术,并且无需用户操作,更新后的数据会自动显示在界面上。
知识点:
1. 列表功能的实现
<amx:listView var="row" value="#{bindings.stocks.collectionModel}" id="listView1">
<amx:listItem id="listItem1" action="#{viewScope.StockBean.GetAction}">
<amx:tableLayout id="tl1" width="100%">
<amx:rowLayout id="rl1">
<amx:cellFormat id="cf1" width="10px" rowSpan="2"/>
<amx:cellFormat id="cf2" width="60%" height="28px">
<amx:outputText value="#{row.ticker}" id="outputText2"/>
</amx:cellFormat>
<amx:cellFormat id="cf3" width="10px" rowSpan="2"/>
<amx:cellFormat id="cf4" width="40%" halign="end">
<amx:outputText value="#{row.price}" id="outputText4"
styleClass="adfmf-listItem-highlightText" inlineStyle="#{row.change}"
rendered="#{row.ticker ne bindings.deleteTicker.inputValue}">
<amx:convertNumber groupingUsed="true" currencySymbol="$" minFractionDigits="2"
maxFractionDigits="2"/>
</amx:outputText>
</amx:cellFormat>
</amx:rowLayout>
<amx:rowLayout id="rla2">
<amx:cellFormat id="cf5" width="60%" height="12px">
<amx:outputText value="#{row.company}" id="outputText3"
styleClass="adfmf-listItem-captionText"/>
</amx:cellFormat>
<amx:cellFormat id="cf6" width="40%" halign="end">
<amx:outputText value="#{row.volume}" id="outputText5"
styleClass="adfmf-listItem-captionText"
rendered="#{row.ticker ne bindings.deleteTicker.inputValue}">
<amx:convertNumber groupingUsed="true" integerOnly="true"/>
</amx:outputText>
</amx:cellFormat>
</amx:rowLayout>
</amx:tableLayout>
<amx:actionListener binding="#{bindings.StopRefresher.execute}"/>
<amx:commandButton id="commandButton1" text="Delete" styleClass="adfmf-commandButton-alert"
rendered="#{row.ticker eq bindings.deleteTicker.inputValue}"
actionListener="#{bindings.RemoveStock.execute}"
inlineStyle="position:absolute;margin:5px;right:0;top:0;"/>
<amx:setPropertyListener from="#{row.rowKey}" to="#{pageFlowScope.ticker}"/>
<amx:setPropertyListener from="#{row.ticker}" to="#{bindings.deleteTicker.inputValue}"
type="swipeRight"/>
</amx:listItem>
</amx:listView>
可以看出:
(1)集合数据是来自Portfolio.java中的stocks对象,即getStocks()返回的对象。
(2)inlineStyle="#{row.change}",来自Stock.java的getChange()方法,它会根据新旧价格的对比,显示红色或绿色。
(3)使用amx:convertNumber,转换数字格式。
(4)点击某一项,会调用setPropertyListener,把#{row.rowKey}传递给#{pageFlowScope.ticker}。
(5)向右滑动某一项,会调用setPropertyListener,把#{row.ticker} 传递给#{bindings.deleteTicker.inputValue}。
(6)当#{row.ticker eq bindings.deleteTicker.inputValue}时,会显示Delete按钮,隐藏原来的股票价格和数量。
2. 删除功能的实现
点击Delete按钮,会调用Portfolio.java中的RemoveStock()方法,删除完数据之后,使用providerChangeSupport.fireProviderDelete()来告诉界面发生了Delete事件,这样才能刷新界面。
3. 增加功能的实现
页面代码
<amx:commandButton id="addbutton" text="Add">
<amx:actionListener binding="#{bindings.StopRefresher.execute}"/>
<amx:actionListener binding="#{bindings.InitNewStock.execute}"/>
<amx:showPopupBehavior popupId="add" align="overlapTop" alignId="listView1"/>
</amx:commandButton>
点击Add按钮时做了三件事:
(1)调用Portfolio.java中的StopRefresher,停止多线程
(2)调用Portfolio.java中的InitNewStock,初始化一个新股票。
(3)弹出一个popup窗口。
添加完毕后,点击Save按钮时,调用Portfolio.java中的AddNewStock,增加一个新股票之后,使用providerChangeSupport.fireProviderCreate()来告诉界面发生了Create事件,这样才能刷新界面。
点击Change按钮,会调用Portfolio.java中的DoChange()方法,注意该方法的描述符有synchronized,说明这个方法会被多线程调用。
5. 多线程的启动与停止
(1)点击Start按钮,会调用Portfolio.java中的StartRefresher()方法,其中设置属性go=true。
(2)点击Stop按钮,会调用Portfolio.java中的StopRefresher()方法,其中设置属性go=false。
多线程的定义是在Refresher.java中,当属性go=true时,每隔1秒钟会调用Portfolio.java中的DoChange()方法,然后调用AdfmfJavaUtilities.flushDataChangeEvent()刷新界面。
6. Portfolio.java 代码
package Portfolio;
import com.sun.util.logging.Level;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import oracle.adfmf.java.beans.PropertyChangeListener;
import oracle.adfmf.java.beans.PropertyChangeSupport;
import oracle.adfmf.java.beans.ProviderChangeListener;
import oracle.adfmf.java.beans.ProviderChangeSupport;
import oracle.adfmf.util.Utility;
import oracle.adfmf.util.logging.Trace;
public class Portfolio {
protected transient ProviderChangeSupport providerChangeSupport = new ProviderChangeSupport(this);
private static List s_stocks = null;
private Stock newStock = new Stock(0, "", "", new Double(1.0), new Double(1.0), new Long(1000));
private Refresher refresher = new Refresher(this);
private Thread worker = new Thread(refresher);
private String deleteTicker = "";
private boolean threadStarted = false;
private transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
public void addProviderChangeListener(ProviderChangeListener l) {
providerChangeSupport.addProviderChangeListener(l);
}
public void removeProviderChangeListener(ProviderChangeListener l) {
providerChangeSupport.removeProviderChangeListener(l);
}
public Portfolio() {
if (s_stocks == null) {
s_stocks = new ArrayList();
}
ResetStocks();
}
public synchronized void ResetStocks() {
s_stocks.clear();
s_stocks.add((new Stock(0, "ORCL", "Oracle Corp.", new Double(28.55), new Double(27.15), new Long(9919000))));
s_stocks.add((new Stock(1, "MSFT", "Microsoft Corp", new Double(32.29), new Double(34.00),
new Long(22454330))));
s_stocks.add((new Stock(2, "AAPL", "Apple Inc.", new Double(392.51), new Double(389.30), new Long(6559023))));
s_stocks.add((new Stock(3, "RIMM", "Research In Motion Limited", new Double(30.02), new Double(30.72),
new Long(7340100))));
s_stocks.add((new Stock(4, "GOOG", "Google Inc.", new Double(537.93), new Double(532.07), new Long(908766))));
providerChangeSupport.fireProviderRefresh("stocks");
}
public synchronized Stock[] getStocks() {
Stock s[] = null;
s = (Stock[])s_stocks.toArray(new Stock[s_stocks.size()]);
return s;
}
public synchronized void DoChange() {
Random r = new Random(new Random().nextInt(1000));
int i = 0;
while (i < s_stocks.size()) {
Stock s = (Stock)s_stocks.get(i);
int ran = r.nextInt(1000);
double change = ((double)ran - 500) / 10000 + 1;
s.setPrice(new Double(s.getPrice().doubleValue() * change));
s_stocks.set(i, s);
i++;
}
}
public void setNewStock(Stock newStock) {
Trace.log(Utility.ApplicationLogger, Level.INFO, Portfolio.class, "setNewStock",
"##################Inside setNewStock!!!");
this.newStock = newStock;
}
public Stock getNewStock() {
return newStock;
}
public void InitNewStock() {
Trace.log(Utility.ApplicationLogger, Level.INFO, Portfolio.class, "InitNewStock",
"##################Inside InitNewStock!!!");
newStock.setId(0);
newStock.setTicker("");
newStock.setCompany("");
newStock.setPrice(new Double(1.0));
newStock.setPrevious(new Double(1.0));
newStock.setVolume(new Long(1000));
}
public synchronized void AddNewStock() {
Trace.log(Utility.ApplicationLogger, Level.INFO, Portfolio.class, "AddNewStock",
"##################Inside AddNewStock!!!");
int newId = 0;
int size = s_stocks.size();
for (int i = 0; i < size; i++) {
Stock s = (Stock)s_stocks.get(i);
if (s.getId() > newId) {
newId = s.getId() + 1;
}
}
Stock stock =
new Stock(newId, newStock.getTicker(), newStock.getCompany(), newStock.getPrice(), newStock.getPrevious(),
newStock.getVolume());
s_stocks.add(stock);
providerChangeSupport.fireProviderCreate("stocks", stock.getTicker(), stock);
}
public synchronized void RemoveStock(String ticker) {
Stock stock = null;
int size = s_stocks.size();
for (int i = 0; i < size; i++) {
Stock s = (Stock)s_stocks.get(i);
if (s.getTicker().compareTo(ticker) == 0) {
setDeleteTicker("");
stock = (Stock)s_stocks.remove(i);
providerChangeSupport.fireProviderDelete("stocks", stock.getTicker());
break;
}
}
}
public void StartRefresher() {
setThreadStarted(true);
refresher.go = true;
if (!worker.isAlive()) {
worker.start();
}
setThreadStarted(refresher.go);
}
public void StopRefresher() {
if (refresher.go == true) {
refresher.go = false;
setThreadStarted(false);
}
}
public void setDeleteTicker(String deleteTicker) {
String oldDeleteTicker = this.deleteTicker;
this.deleteTicker = deleteTicker;
propertyChangeSupport.firePropertyChange("deleteTicker", oldDeleteTicker, deleteTicker);
}
public void addPropertyChangeListener(PropertyChangeListener l) {
propertyChangeSupport.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
propertyChangeSupport.removePropertyChangeListener(l);
}
public String getDeleteTicker() {
return deleteTicker;
}
public void setThreadStarted(boolean threadStarted) {
boolean oldThreadStarted = this.threadStarted;
this.threadStarted = threadStarted;
propertyChangeSupport.firePropertyChange("threadStarted", oldThreadStarted, threadStarted);
}
public boolean getThreadStarted() {
return threadStarted;
}
}
7. StockBean.java 代码
package Portfolio;
import javax.el.ValueExpression;
import oracle.adfmf.framework.api.AdfmfJavaUtilities;
public class StockBean {
public StockBean() {
}
public String GetAction() {
String outcome = "";
ValueExpression ve = AdfmfJavaUtilities.getValueExpression("#{bindings.deleteTicker.inputValue}", String.class);
String deleteTicker = (String)ve.getValue(AdfmfJavaUtilities.getAdfELContext());
if (deleteTicker.length() == 0) {
outcome = "details";
} else {
ve.setValue(AdfmfJavaUtilities.getAdfELContext(), "");
}
return outcome;
}
}
8. Stock.java 部分代码
public String getChange() {
String c = "color:green";
if( price.doubleValue() < previous.doubleValue() ) {
c = "color:red";
}
return c;
}
9. Refresher.java 代码
package Portfolio;
import oracle.adfmf.framework.api.AdfmfJavaUtilities;
public class Refresher implements Runnable {
public Refresher() {
super();
}
Portfolio p = null;
public Refresher(Portfolio p) {
this.p = p;
}
boolean go = false;
public void run() {
while (true) {
if (go) {
p.DoChange();
AdfmfJavaUtilities.flushDataChangeEvent();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
没有评论:
发表评论