Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Reply
Contributor
Posts: 14
Registered: ‎03-30-2010
My Device: BlackBerry Curve 8300
My Carrier: No Idea

Interrupting a thread (timeout or from cancel button)

I have used the sample from Peter Strange to make the "please wait window" work.

peter's example

Before I implement this my thread timeout was working and it was interrupting the thread from the event thread dispatcher. Now, I really don't know what is the problem. Maybe you could help me resolve this question???

 

Here's a part of my code...cannot give it all cause it's kind of too heavy(2000 lines+)

 

private class ConnectionThread extends Thread
    {
        private ObserverInterface _ourObserver;
        private String _theUrl;
        boolean willFail = false;

        public ConnectionThread(ObserverInterface observer) {
            super();
            _ourObserver = observer;
        }
        
        public synchronized String getUrl() {
            return _theUrl;
        }

        public synchronized void start(String url) {
            synchronized(this) {
                _theUrl = url;
            }
            super.start();
        }
        
        public void stop() {
            this.interrupt();
        }
        
        private void observerStatusUpdate(final int status, final String statusString) {
            _ourObserver.processStatusUpdate(status, statusString);
        }

        private void observerError(int errorCode, String errorMessage) {
            _ourObserver.processError(errorCode, errorMessage);
        }
        
        public void observerResponse(String strContent) {
            _ourObserver.processResponse(strContent);
        }
        
        public void run() {
            processing = true;
            observerStatusUpdate(1, "Started");
            StreamConnection s = null;
            try{
                String url = getUrl();
                StringBuffer bufUrl = new StringBuffer();
                // Replacing spaces in the url for a "%20"
                while (url.indexOf(" ") != -1){
                    int index = url.indexOf(" ");
                    bufUrl.append(url);
                    bufUrl.deleteCharAt(index);
                    bufUrl.insert(index, "%20");
                    url = bufUrl.toString();
                }
                observerStatusUpdate(100, "Processing...");
                s = (StreamConnection)Connector.open(url, Connector.READ, true);
                    
                HttpConnection httpConn = (HttpConnection)s;

                int status = httpConn.getResponseCode();
                
                if (status == HttpConnection.HTTP_OK){
                    // Lecture des données
                    InputStream input = s.openInputStream();
                    byte[] data = new byte[256];
                    int len = 0;
                    int size = 0;
                    StringBuffer raw = new StringBuffer();
                    while ( -1 != (len = input.read(data)) ){
                        raw.append(new String(data, 0, len));
                        size += len;
                        
                    }
                    
                    String strContent = raw.toString();
                    if (strContent.equalsIgnoreCase("END-OF-FILE;")) {
                        noContent = true;
                    } else {
                        noContent = false;
                    }
                    //System.out.println(strContent);
                    strHttpData = strContent;
                    observerStatusUpdate(100, "Finished");
                    if ( willFail ) {
                        observerError(ObserverInterface.ERROR, "Failed");
                    } else {
                        observerResponse(strContent);
                    }
                    input.close();
                } else {
                    System.out.println("Error status:"+status);
                }
                s.close();
                _ourObserver = null;
            }
            catch (IOException e){
                System.err.println(e.toString());
            }
            processing = false;
        }
    }

    public void httpRequest(String url) {
        PleaseWaitPopupScreen _waitScreen = new PleaseWaitPopupScreen("Message", "Traitement en cours...", url);
        _waitScreen.show();
    }
    
    public class PleaseWaitPopupScreen extends PopupScreen
        implements ObserverInterface {

        String _title;

        private GaugeField _gaugeField = null;
        private ButtonField _cancelButton = null;
        private LabelField _statusText = null;
    
        private ConnectionThread _connectionThread = null;
        String _requestURL = null;
        byte [] response;
        private int _returnCode = ObserverInterface.CANCELLED;

        public PleaseWaitPopupScreen(String title, String text, String requestURL) {
            super(new VerticalFieldManager());
            this.add(new LabelField(title, LabelField.FIELD_HCENTER));
            this.add(new SeparatorField());
            this.add(new RichTextField(text, Field.READONLY));
            _gaugeField = new GaugeField(null, 1, 100, 1, GaugeField.NO_TEXT);
            this.add(_gaugeField);
            this.add(new SeparatorField());
            _cancelButton = new ButtonField("Cancel", ButtonField.FIELD_HCENTER | ButtonField.CONSUME_CLICK);
            
            _cancelButton.setChangeListener( new FieldChangeListener() {
            public void fieldChanged(Field field, int context) {
                if ( _connectionThread != null ) {
                    if ( processing ) {
                        _connectionThread.stop();
                        processing = false;
                    }
                } else {
                    throw new RuntimeException("Oppsss");
                }
            }
            });
            this.add(_cancelButton);
            _cancelButton.setFocus();
            _statusText = new LabelField("Starting");
            this.add(_statusText);
            _requestURL = requestURL;
        }

        public int show() {
            _connectionThread = new ConnectionThread(this);
            _connectionThread.start(_requestURL);
            UiApplication.getUiApplication().pushModalScreen(this);
            long startTime = System.currentTimeMillis();
            while ( _connectionThread.isAlive() ){
                long current_time = System.currentTimeMillis();
                long max_time = startTime + TIMEOUT;
                if ( current_time < max_time ) {
                    _connectionThread.interrupt();
                    processing = false;
                    break;
                }
            }
            return _returnCode;    
        }
        
        public void processStatusUpdate(final int status, final String statusString) {
            UiApplication.getUiApplication().invokeLater(new Runnable() {
                public void run () {
                    _statusText.setText(statusString);
                    if ( status > 0 ) {
                        _gaugeField.setValue(status);
                    }
                    PleaseWaitPopupScreen.this.invalidate();
                }
            });
        }

        public void processResponse(final String response) {
            _returnCode = ObserverInterface.OK;
            
            UiApplication.getUiApplication().invokeLater(new Runnable() {
                public void run () {
                    UiApplication.getUiApplication().popScreen(PleaseWaitPopupScreen.this);
                }
            });
        }
        
        public void processError(int errorCode, final String errorMessage) {
            _returnCode = errorCode;
            
            UiApplication.getUiApplication().invokeLater(new Runnable() {
                public void run () {
                    Dialog.alert("Error:!\n" + errorMessage);
                    UiApplication.getUiApplication().popScreen(PleaseWaitPopupScreen.this);
                }
            });
        }
    }
    
    public interface ObserverInterface {

        public void processStatusUpdate(int status, String statusString);
        
        public void processResponse(String strContent);
        
        public void processError(int errorCode, String errorMessage);
        
        public static int CANCELLED = -1;
        public static int ERROR = -2;
        public static int OK = 0;
        
    }

Developer
Posts: 19,623
Registered: ‎07-14-2008
My Device: Not Specified

Re: Interrupting a thread (timeout or from cancel button)

I'm actually updating that Thread using the new Resource Centre.  Turned out to be a bigger job that I expected, and I've just finished the coding for part 3 but have yet to write the text...

 

Here are part 1 and part 2:

http://supportforums.blackberry.com/t5/Java-Development/Sample-quot-Please-Wait-quot-screen-part-1/t...

http://supportforums.blackberry.com/t5/Java-Development/Sample-quot-Please-Wait-quot-screen-part-2/t...

 

I hope these are better explanation that the Thread you have already used.  So have a look.  However if I'm honest, I'm still not happy with my example or the explanations.  Think I need to write a book.....

 

Anyway, I'm not sure what your question is.  Can you tell us again?

 

You say your Thread timeout was interrupting it.  How was it doing that?

 

I presume that you have debugged this and the this.interrupt() is executed?  Also I would put a try catch around that, and check that the Thread is actually active. 

 

Other people have suggested closing the connection to kill the Thread.  In your case it would mean finding and closing httpConn in the stop method. 

Developer
Posts: 1,305
Registered: ‎01-21-2009
My Device: Not Specified

Re: Interrupting a thread (timeout or from cancel button)

Sun's recommended approach to stopping a worker thread is to set a variable that the thread can test periodically. When the worker thread notices that the variable has been set, it can quietly exit in a controlled way. The variable should be declared volatile or else have all access synchronized.

 

The strategy I use is to test a "please stop" variable just before any operation that will communicate to the rest of my program (just before a call-back or before invokeLater, for instance) and also just before and/or after any blocking operation.

 

Using interrupt (like Peter did in his earlier example) is ok, sort of, but requires some careful considerations, as Sun describes here. Furthermore, since interrupting a thread doesn't necessarily clean up pending network traffic (see RIM's API docs on Thread.interrupt), I think that Sun's recommended approach is the way to go. In particular, I think that interrupt does not necessarily close connections and may even leave the Connection object in a state where calling it's close method will fail.

 

Sun also suggests that closing a socket can work in situations where a thread won't even respond to a call to interrupt. So that's a third alternative for network I/O threads.




Solved? click "Accept as solution". Helpful? give kudos by clicking on the star.
Contributor
Posts: 14
Registered: ‎03-30-2010
My Device: BlackBerry Curve 8300
My Carrier: No Idea

Re: Interrupting a thread (timeout or from cancel button)

Peter, i'm sorry to say that but the two links that you've put in this thread are broken...

 

Could you plz check make them work?

Developer
Posts: 1,305
Registered: ‎01-21-2009
My Device: Not Specified

Re: Interrupting a thread (timeout or from cancel button)

They worked for me.




Solved? click "Accept as solution". Helpful? give kudos by clicking on the star.