LWUIT的List運用系列(七) List的終極運用(下篇)

LWUIT的List運用系列(六) List的終極使用(上篇)中我介紹了LWUIT_MakeOver項目,雖然有部分代碼看不懂,但這並不阻礙我去模仿它的形式去應用List。這一篇我按照作者的思想寫了一個簡單的Demo,希望那些跟我一樣不理解源代碼的同胞們能夠加深一下理解。
如果你現在還沒有這個項目的源代碼,可以到這裏下載(不要資源分的)。

既然是模仿別人的程序,在自己動手之前,我們首先要明白源代碼的基本含義,至少要能保證大半代碼我們能夠理解,我先對源代碼做一個簡單的分析和說明。
我把顯示詳細信息的showDetail()方法和顯示地圖的showMap()方法去掉了。

    //創建Form,主要是把Menu前的默認數字給去掉
    private Form createForm(String title) {
        Form f = new Form(title);
        f.getTitleComponent().setAlignment(Component.LEFT);
        f.setMenuCellRenderer(new DefaultListCellRenderer(false));
        return f;
    }
 //主界面,就是表單界面,我們不用理會那些字段的含義
    private void showMainForm() {
        Form mainForm = createForm("Local Search");
        mainForm.setTransitionInAnimator(Transition3D.createCube(500, false));
        mainForm.setTransitionOutAnimator(Transition3D.createCube(500, true));
        mainForm.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
        mainForm.addComponent(new Label("search for:"));
        final TextField searchFor = new TextField("coffee", 50);
        mainForm.addComponent(searchFor);
        mainForm.addComponent(new Label("location:"));
        final TextField location = new TextField("95054", 50);
        mainForm.addComponent(location);
        mainForm.addComponent(new Label("street:"));
        final TextField street = new TextField(50);
        mainForm.addComponent(street);
        mainForm.addComponent(new Label("sort results by:"));
        final ComboBox sortResults = new ComboBox(new String[] {"Distance", "Title", "Rating", "Relevance"});
        mainForm.addComponent(sortResults);
        mainForm.addCommand(exitCommand);
        mainForm.addCommand(defaultThemeCommand);
        mainForm.addCommand(javaThemeCommand);
        mainForm.addCommand(new Command("Search") {
            public void actionPerformed(ActionEvent ev) {
                showSearchResultForm(searchFor.getText(), location.getText(), street.getText(), (String) sortResults.getSelectedItem());
            }
        });
        mainForm.show();
    }
    //報告異常信息的對話框,網絡連接異常或者中斷時會報此異常
    private void exception(Exception ex) {
        ex.printStackTrace();
        Dialog.show("Error", "Error connecting to search service - Turning on DEMO MODE", "OK", null);
        demoMode = true;
        showMainForm();
    }

//顯示搜索結果頁面,傳的那些值都來自於MainForm的文本框,這個頁面時用來顯示List的
    //測試時有雖然有396條數據,結果卻顯示的非常流暢
    private void showSearchResultForm(String searchFor, String location, String street, String sortOrder) {
        final Form resultForm = createForm("result list");
        resultForm.setScrollable(false);
        resultForm.setLayout(new BorderLayout());
        InfiniteProgressIndicator tempIndicator = null;
        try {
            tempIndicator = new InfiniteProgressIndicator(Image.createImage("/wait-circle.png"));
        } catch (IOException ex) {
            tempIndicator = null;
            ex.printStackTrace();
        }
        final InfiniteProgressIndicator indicator = tempIndicator;
        final List resultList = new List(new LocalResultModel(searchFor, location, sortOrder, street)) {
            public boolean animate() {
                boolean val = super.animate();

                // return true of animate only if there is data loading, this saves battery and CPU
                if(indicator.animate()) {
                    int index = getSelectedIndex();
                    index = Math.max(0, index - 4);
                    ListModel model = getModel();
                    int dest = Math.min(index + 4, model.getSize());
                    for(int iter = index ; iter < dest ; iter++) {
                        if(model.getItemAt(index) == LOADING_MARKER) {
                            return true;
                        }
                    }
                }
                return val;
            }
        };
        Links pro = new Links();
        pro.title = "prototype";
        pro.tel = "9999999999";
        pro.distance = "9999999";
        pro.address = "Long address string";
        pro.rating = "5";
        resultList.setRenderingPrototype(pro);
        resultList.setFixedSelection(List.FIXED_NONE_CYCLIC);
        resultList.getStyle().setBorder(null);

        //這一部分屬於關鍵代碼,還是比較容易懂的,作爲Controller控制界面的顯示
        //我一直理解ListCellaRenderer爲Controller,不知道理解有沒有錯。
        resultList.setListCellRenderer(new DefaultListCellRenderer(false) {
            private Label focus;
            private Container selected;
            private Label firstLine;
            private Label secondLine;
            private boolean loading;

            //代碼塊,會在構造方法執行時一起執行
            {
                selected = new Container(new BoxLayout(BoxLayout.Y_AXIS));
                firstLine = new Label("First Line");
                secondLine = new Label("Second Line");
                int iconWidth = 20;
                firstLine.getStyle().setMargin(LEFT, iconWidth);
                secondLine.getStyle().setMargin(LEFT, iconWidth);
                selected.addComponent(firstLine);
                selected.addComponent(secondLine);
            }

            public Component getListCellRendererComponent(List list, Object value, int index, boolean isSelected) {
                if(value == null || value == LOADING_MARKER) {
                    loading = true;
                    if(isSelected) {
                        firstLine.setText("Loading...");
                        secondLine.setText("Loading...");
                        return selected;
                    }
                    return indicator;
                }
                loading = false;
                //如果爲選中狀態就顯示Label爲白色
                if(isSelected) {
                    int listSelectionColor = list.getStyle().getFgSelectionColor();
                    firstLine.getStyle().setFgColor(0xffffff);
                    secondLine.getStyle().setFgColor(0xffffff);
                    firstLine.getStyle().setBgTransparency(0);
                    secondLine.getStyle().setBgTransparency(0);
                    Links l = (Links)value;
                    firstLine.setText(l.address + " " + l.tel);
                    secondLine.setText(l.distance + " miles " + ("".equals(l.rating) ? "" : ", " + l.rating + "*"));
                    return selected;
                }
                //如果爲未選中狀態,恢復Label的默認顯示
                super.getListCellRendererComponent(list, ((Links)value).title, index, isSelected);
                return this;
            }

            public void paint(Graphics g) {
                if(loading) {
                    indicator.setX(getX());
                    indicator.setY(getY());
                    indicator.setWidth(getWidth());
                    indicator.setHeight(getHeight());
                    indicator.paint(g);
                } else {
                    super.paint(g);
                }
            }

            //在List的選中項前添加一個箭頭圖標
            public Component getListFocusComponent(List list) {
                if(focus == null) {
                    try {
                        focus = new Label(Image.createImage("/svgSelectionMarker.png"));
                        focus.getStyle().setBgTransparency(0);
                    } catch (IOException ex1) {
                        ex1.printStackTrace();
                    }
                }
                return focus;
            }
        });
        resultForm.addComponent(BorderLayout.CENTER, resultList);
        resultForm.addCommand(new Command("Map") {
            public void actionPerformed(ActionEvent ev) {
                showMap(resultForm, resultList.getSelectedItem());
            }
        });
        resultForm.addCommand(new Command("Details") {
            public void actionPerformed(ActionEvent ev) {
                showDetails(resultForm, resultList.getSelectedItem());
            }
        });
        resultForm.addCommand(new Command("Back") {
            public void actionPerformed(ActionEvent ev) {
                showMainForm();
            }
        });
        resultForm.addCommand(exitCommand);
        resultForm.show();
    }

 /**
     * A list model that lazily fetches a result over the web if its unavailable
     * 這個類就非常關鍵了,它是整個List動態加載數據的核心
     */
    class LocalResultModel implements ListModel {
        private Vector cache;
        private Arg[] args;
        private boolean fetching;
        private Vector fetchQueue = new Vector();
        private Vector dataListeners = new Vector();

        private Vector selectionListeners = new Vector();

        private int selectedIndex = 0;
        private boolean firstTime = true;

        public LocalResultModel(String searchFor, String location, String sortOrder, String street) {
            cache = new Vector();
            cache.setSize(1);
            args = new Arg[]{
                new Arg("output", "json"),
                new Arg("appid", APPID),
                new Arg("query", searchFor),
                new Arg("location", location),
                new Arg("sort", sortOrder.toLowerCase()),
                null,
                null
            };
            final String str = street;
            if (!"".equals(str)) {
                args[6] = new Arg("street", str);
            }
        }

        /**
         * 這裏就是它動態加載的強大之處了,startOffset相當於一個索引值,
         * 396條數據並不是1次性的加載,手機屏幕就那麼大,滿屏也只能顯示幾條數據,
         * 作者就讓它只加載10條數據,如果用戶想瀏覽後面的數據,它會根據這個startOffset值
         * 請求服務器,返回10條數據。比如第一次請求startOffset = 1,那麼第二次就是11,
         * 每次只請求10條數據。
         * @param startOffset
         */
        private void fetch(final int startOffset) {
            int count = Math.min(cache.size(), startOffset + 9);
            for(int iter = startOffset - 1 ; iter < count ; iter++) {
                if(cache.elementAt(iter) == null) {
                    cache.setElementAt(LOADING_MARKER, iter);
                }
            }
            if(!fetching) {
                fetching = true;
                new Thread() {
                    public void run() {
                        if(firstTime) {
                            firstTime = false;
                            try {
                                // yield a bit CPU the first time around since the model
                                // call might occur before the display is refreshed
                                Thread.sleep(400);
                            } catch (InterruptedException ex) {
                                ex.printStackTrace();
                            }
                        }
                        fetchThread(startOffset);
                        while(fetchQueue.size() > 0) {
                            int i = ((Integer)fetchQueue.elementAt(0)).intValue();
                            fetchQueue.removeElementAt(0);
                            fetchThread(i);
                        }
                        fetching = false;
                    }
                }.start();
            } else {
                fetchQueue.addElement(new Integer(startOffset));
            }
        }

        //這個方法就是根據startOffset進行請求,然後返回相應的數據
        private void fetchThread(int startOffset) {
            try {
                Response response;
                args[5] = new Arg("start", Integer.toString(startOffset));
                if (!demoMode) {
                    response = Request.get(LOCAL_BASE, args, null, null);
                } else {
                    response = Request.get(Request.DEMO_URL, args, null, null);
                }
                final Exception ex = response.getException();
                if (ex != null || response.getCode() != HttpConnection.HTTP_OK) {
                    Dialog.show("Error", "Error connecting to search service - Turning on DEMO MODE", "OK", null);
                    demoMode = true;
                    showMainForm();
                    return;
                }

                Result result = response.getResult();
                //String mapAllLink = result.getAsString("ResultSet.ResultSetMapUrl");
                int totalResultsAvailable = result.getAsInteger("ResultSet.totalResultsAvailable");
                final int resultCount = result.getSizeOfArray("ResultSet.Result");

                // this is the first time... set the size of the vector to match the results!
                if(startOffset == 1) {
                    cache.setSize(totalResultsAvailable);
                }

                for(int i = 0 ; i < resultCount ; i++) {
                    String title = result.getAsString("ResultSet.Result["+i+"].Title");

                    Links link = new Links();
                    link.title = title;
                    link.address = result.getAsString("ResultSet.Result["+i+"].Address");
                    link.map = result.getAsString("ResultSet.Result["+i+"].MapUrl");
                    link.listing = result.getAsString("ResultSet.Result["+i+"].ClickUrl");
                    link.business = result.getAsString("ResultSet.Result["+i+"].BusinessClickUrl");
                    link.tel = result.getAsString("ResultSet.Result["+i+"].Phone");
                    link.latitude = result.getAsString("ResultSet.Result["+i+"].Latitude");
                    link.longitude = result.getAsString("ResultSet.Result["+i+"].Longitude");
                    link.rating = result.getAsString("ResultSet.Result["+i+"].Rating.AverageRating");
                    link.distance = result.getAsString("ResultSet.Result["+i+"].Distance");
                    cache.setElementAt(link, startOffset + i - 1);
                    fireDataChangedEvent(DataChangedListener.CHANGED, startOffset + i - 1);
                }
            } catch (Exception ex) {
                exception(ex);
            }
        }

        public Object getItemAt(int index) {
            Object val = cache.elementAt(index);
            if(val == null) {
                fetch(index + 1);
                return LOADING_MARKER;
            }
            return val;
        }

        public int getSize() {
            return cache.size();
        }

        public void setSelectedIndex(int index) {
            int oldIndex = selectedIndex;
            this.selectedIndex = index;
            fireSelectionEvent(oldIndex, selectedIndex);
        }

        public void addDataChangedListener(DataChangedListener l) {
            dataListeners.addElement(l);
        }

        public void removeDataChangedListener(DataChangedListener l) {
            dataListeners.removeElement(l);
        }

        private void fireDataChangedEvent(final int status, final int index){
            if(!Display.getInstance().isEdt()) {
                Display.getInstance().callSeriallyAndWait(new Runnable() {
                    public void run() {
                        fireDataChangedEvent(status, index);
                    }
                });
                return;
            }
            // we query size with every iteration and avoid an Enumeration since a data
            // changed event can remove a listener instance thus break the enum...
            for(int iter = 0 ; iter < dataListeners.size() ; iter++) {
                DataChangedListener l = (DataChangedListener)dataListeners.elementAt(iter);
                l.dataChanged(status, index);
            }
        }

        public void addSelectionListener(SelectionListener l) {
            selectionListeners.addElement(l);
        }

        public void removeSelectionListener(SelectionListener l) {
            selectionListeners.removeElement(l);
        }

        private void fireSelectionEvent(int oldIndex, int newIndex){
            Enumeration listenersEnum = selectionListeners.elements();
            while(listenersEnum.hasMoreElements()){
                SelectionListener l = (SelectionListener)listenersEnum.nextElement();
                l.selectionChanged(oldIndex, newIndex);
            }
        }

        public void addItem(Object item) {
        }

        public void removeItem(int index) {
        }

        public int getSelectedIndex() {
            return selectedIndex;
        }
    }

注意一點:private void fetch(final int startOffset)方法在我實際的測試中,第一次請求startOffset = 1,第二次請求startOffset = 2,至今我還不明白爲什麼第一次請求的時候那個線程沒有運行,從第三次請求開始startoffSet = 12,以後的請求都很正常,都是返回10條數據。

可能我對以上代碼解釋的不夠清楚,但現在又了一個大概的瞭解,我對實現這種List做了一個簡要的需求:

1、手機在首次獲取數據或者刷新數據時,將從服務器發起請求,如果有很多條數據,並不是一次性返回給手機端供手機接收。
2、在手機端用List顯示數據時需要按時間降序來顯示,所以服務器端返回的數據也是按時間降序的形式返回xml或者json。
3、請求的方式按照這種方式來進行:第一次請求時返回10條數據,如果用戶瀏覽完這10條數據,想繼續瀏覽更多的數據,這再次發送請求,依次類推,每次請求只返回10條數據。
4、服務器端對數據要做分頁處理,根據請求的起始索引和請求的數據條數(最後一次請求可能沒有10條數據),返回相應的數據。進行web請求時,至少要提供startOffset和resultCount這兩個參數。
5、List在顯示時,不能用默認的List的MVC寫法,其中Model部分和Controller部分需要自己進行構造。這樣做的作用:一是能夠節約內存並加快數據加載速度,二是能夠比較靈活的構造List中的View部分。(目前最後一點我還不是很確信,但是感覺上比我用原有的List快一些,原有的List的Model部分是不用像這樣繼承幾口然後,接口裏面有一堆方法要實現,如果這個確實能夠加快速度,多寫點代碼也不爲過,畢竟大量的數據顯示性能非常重要)。

下面是我刪減後的代碼,有了上面的基礎,理解起來應該更輕鬆了!

/**
 *
 * @author 水貨程序員
 */
public class MembersForm extends Form {

    static final Object LOADING_MARKER = new Object();
    //InfiniteProgressIndicator這個類在LWUIT_MakeOver中有,是用來顯示動畫的。
    //我在http://blog.csdn.net/pjw100/archive/2009/12/14/5006882.aspx解釋了這個類
    InfiniteProgressIndicator indicator = null;
    InfiniteProgressIndicator tempIndicator = null;

    //構造方法
    public MembersForm() {
        setScrollable(false);
        setLayout(new BorderLayout());
        try {
            tempIndicator = new InfiniteProgressIndicator(Image.createImage("/wait-circle.png"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        indicator = tempIndicator;
        showSearchResultForm();
    }

    private void showSearchResultForm() {
        final List resultList = new List(new LocalResultModel()) {

            public boolean animate() {
                boolean val = super.animate();
                // return true of animate only if there is data loading, this saves battery and CPU
                if (indicator.animate()) {
                    int index = getSelectedIndex();
                    index = Math.max(0, index - 4);
                    ListModel model = getModel();
                    int dest = Math.min(index + 4, model.getSize());
                    for (int iter = index; iter < dest; iter++) {
                        if (model.getItemAt(iter) == LOADING_MARKER) {
                            return true;
                        }
                    }
                }
                return val;
            }
        };

        Person pro = new Person();

        pro.photo = null;
        pro.name = "Sunny";
        pro.sex = "male";
        pro.address = "Long address string";
        resultList.setRenderingPrototype(pro);
        resultList.setFixedSelection(List.FIXED_NONE_CYCLIC);
        resultList.getStyle().setBorder(null);

        resultList.setListCellRenderer(new DefaultListCellRenderer(false) {

            private Label focus;
            private Container selected;
            private Container selectedInfo;
            private Label selectedPhoto;
            private Label selectedName;
            private Label selectedSex;
            private Label selectedAddress;
            private boolean loading;


            {
                selected = new Container(new BoxLayout(BoxLayout.X_AXIS));
                selectedInfo = new Container(new BoxLayout(BoxLayout.Y_AXIS));

                selectedPhoto = new Label();
                selectedName = new Label();
                selectedSex = new Label();
                selectedAddress = new Label();

                int iconWidth = 20;
                selectedPhoto.getStyle().setMargin(LEFT, iconWidth);

                selectedInfo.addComponent(selectedName);
                //selectedInfo.addComponent(selectedSex);
                selectedInfo.addComponent(selectedAddress);
                selected.addComponent(selectedPhoto);
                selected.addComponent(selectedInfo);


            }

            public Component getListCellRendererComponent(List list, Object value, int index, boolean isSelected) {
                if (value == null || value == LOADING_MARKER) {
                    loading = true;
                    if (isSelected) {
                        //unselectedPhoto.setText("Loading...");
                        return selected;
                    }
                    return indicator;
                }
                loading = false;

                if (isSelected) {
                    int listSelectionColor = list.getStyle().getFgSelectionColor();
                    selectedName.getStyle().setFgColor(listSelectionColor);
                    selectedSex.getStyle().setFgColor(listSelectionColor);
                    selectedAddress.getStyle().setFgColor(listSelectionColor);
                    selectedName.getStyle().setBgTransparency(0);
                    selectedSex.getStyle().setBgTransparency(0);
                    selectedAddress.getStyle().setBgTransparency(0);

                    Person person = (Person) value;
                    selectedPhoto.setIcon(person.photo);
                    selectedName.setText(person.name);
                    selectedSex.setText(person.sex);
                    selectedAddress.setText(person.address);

                    return selected;
                }

                super.getListCellRendererComponent(list, ((Person) value).name, index, isSelected);
                return this;
            }

            public void paint(Graphics g) {
                if (loading) {
                    indicator.setX(getX());
                    indicator.setY(getY());
                    indicator.setWidth(getWidth());
                    indicator.setHeight(getHeight());
                    indicator.paint(g);
                } else {
                    super.paint(g);
                }
            }

            public Component getListFocusComponent(List list) {
                if (focus == null) {
                    try {
                        focus = new Label(Image.createImage("/svgSelectionMarker.png"));
                        focus.getStyle().setBgTransparency(0);
                    } catch (IOException ex1) {
                        ex1.printStackTrace();
                    }
                }
                return focus;
            }
        });

        this.addComponent(BorderLayout.CENTER, resultList);
    }

    private void exception(Exception ex) {
        ex.printStackTrace();
        Dialog.show("Error", "Error connecting to search service - Turning on DEMO MODE", "OK", null);
    }

    class LocalResultModel implements ListModel {

        private Vector cache;
        //private Arg[] args;
        private boolean fetching;
        private Vector fetchQueue = new Vector();
        private Vector dataListeners = new Vector();
        private Vector selectionListeners = new Vector();
        private int selectedIndex = 0;
        private boolean firstTime = true;

        public LocalResultModel() {
            cache = new Vector();
            cache.setSize(1);
        }

        private void fetch(final int startOffset) {
            int count = Math.min(cache.size(), startOffset + 9);
            for (int iter = startOffset - 1; iter < count; iter++) {
                if (cache.elementAt(iter) == null) {
                    cache.setElementAt(LOADING_MARKER, iter);
                }
            }
            if (!fetching) {
                fetching = true;
                new Thread() {

                    public void run() {
                        if (firstTime) {
                            firstTime = false;
                            try {
                                // yield a bit CPU the first time around since the model
                                // call might occur before the display is refreshed
                                Thread.sleep(400);
                            } catch (InterruptedException ex) {
                                ex.printStackTrace();
                            }
                        }
                        fetchThread(startOffset);
                        while (fetchQueue.size() > 0) {
                            int i = ((Integer) fetchQueue.elementAt(0)).intValue();
                            fetchQueue.removeElementAt(0);
                            fetchThread(i);
                        }
                        fetching = false;
                    }
                }.start();
            } else {
                fetchQueue.addElement(new Integer(startOffset));
            }
        }

        private void fetchThread(final int startOffset) {
            System.out.println("startOffset:" + startOffset);
            try {
                //下面這兩個變量都是進行模擬使用的,totalResultsAvailable代表記錄總數
                int totalResultsAvailable = 26;
                int resultCount = 10;
                //cache集合用來盛裝數據,第一次請求時設置cache的大小
                if (startOffset == 1) {
                    cache.setSize(totalResultsAvailable);
                }

                //並不是每次請求都能夠返回10條數據,比如最後一次請求可能只有5條數據,resultCount就不等於10了。
                if (totalResultsAvailable - startOffset < 10) {
                    resultCount = totalResultsAvailable - startOffset + 1;
                }

                Image pic = null;
                try {
                    pic = Image.createImage("/smallphoto.jpg");
                } catch (Exception ex) {
                    ex.printStackTrace();
                }

                //模擬從服務器端請求的數據,返回一個對象數組,然後遍歷數組,把數據添加到cache中,緩存起來。
                Person[] personArr = getPersons(startOffset, resultCount);

                for (int i = 0; i < resultCount; i++) {
                    cache.setElementAt(personArr[i], startOffset + i - 1);
                    fireDataChangedEvent(DataChangedListener.CHANGED, startOffset + i - 1);
                }
            } catch (Exception ex) {
                exception(ex);
            }
        }

        //由於自己的Demo沒有服務端,我在這裏做了模擬數據,startOffset爲索引值,count爲每次請求的記錄條數
        private Person[] getPersons(int startOffset, int count) {
            Image pic = null;
            try {
                pic = Image.createImage("/smallphoto.jpg");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            Person[] personArr = new Person[26];
            for (int i = 0; i < 26; i++) {
                char  c= (char)(65+i);
                String sname = String.valueOf(c);
                personArr[i] = new Person();
                personArr[i].name = sname;
                personArr[i].sex = "";
                personArr[i].address = "深圳";
                personArr[i].photo = pic;
            }
            Person[] datas = new Person[count];
            for(int i = 0;inew Person();
                datas[i] = personArr[startOffset + i -1];
            }
            return datas;
        }

        public Object getItemAt(int index) {
            Object val = cache.elementAt(index);
            if (val == null) {
                fetch(index + 1);
                return LOADING_MARKER;
            }
            return val;
        }

        public int getSize() {
            return cache.size();
        }

        public void setSelectedIndex(int index) {
            int oldIndex = selectedIndex;
            this.selectedIndex = index;
            fireSelectionEvent(oldIndex, selectedIndex);
        }

        public void addDataChangedListener(DataChangedListener l) {
            dataListeners.addElement(l);
        }

        public void removeDataChangedListener(DataChangedListener l) {
            dataListeners.removeElement(l);
        }

        private void fireDataChangedEvent(final int status, final int index) {
            if (!Display.getInstance().isEdt()) {
                Display.getInstance().callSeriallyAndWait(new Runnable() {

                    public void run() {
                        fireDataChangedEvent(status, index);
                    }
                });
                return;
            }
            // we query size with every iteration and avoid an Enumeration since a data
            // changed event can remove a listener instance thus break the enum...
            for (int iter = 0; iter < dataListeners.size(); iter++) {
                DataChangedListener l = (DataChangedListener) dataListeners.elementAt(iter);
                l.dataChanged(status, index);
            }
        }

        public void addSelectionListener(SelectionListener l) {
            selectionListeners.addElement(l);
        }

        public void removeSelectionListener(SelectionListener l) {
            selectionListeners.removeElement(l);
        }

        private void fireSelectionEvent(int oldIndex, int newIndex) {
            Enumeration listenersEnum = selectionListeners.elements();
            while (listenersEnum.hasMoreElements()) {
                SelectionListener l = (SelectionListener) listenersEnum.nextElement();
                l.selectionChanged(oldIndex, newIndex);
            }
        }

        public void addItem(Object item) {
        }

        public void removeItem(int index) {
        }

        public int getSelectedIndex() {
            return selectedIndex;
        }
    }

    //實體類
    private static class Person {

        Image photo;
        String name;
        String sex;
        String address;
    }
}

附上效果截圖:

Technorati 標籤: LWUIT的List運用


第一張:加載Form
第二張:首次加載時的效果
第三張:滑動滾動條時,動態加載的效果,加載時間1秒都不到,很流暢!

0 1 2

發佈了52 篇原創文章 · 獲贊 0 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章