Android Development & Technology
  • Using Threads and Handlers to make non-blocking web-requests

    Posted on March 3rd, 2009 chris 2 comments
    Here is a piece i've come across recently on Android: If you use a Handler to make a web-request (load the html of an url into a string), it will block the app. The proper way to do that is with Threads. Threads cannot interact with the GUI though, so they need to call a Handler which can do that. Using this method it's easy to download files in the background without blocking or annoying the user. Let's start with the code to fetch the html of a given url:
    try {
        URL updateURL = new URL("http://iconic.4feets.com/update");    
        URLConnection conn = updateURL.openConnection(); 
        InputStream is = conn.getInputStream();
        BufferedInputStream bis = new BufferedInputStream(is);
        ByteArrayBuffer baf = new ByteArrayBuffer(50);
        
        int current = 0;
        while((current = bis.read()) != -1){
            baf.append((byte)current);
        }
    
        /* Convert the Bytes read to a String. */
        final String s = new String(baf.toByteArray()); 		
    } catch (Exception e) {
    }
    As said, doing that in a Handler will block the UI and may open the ANR (app not responding) dialog (see Designing for Responsiveness). That's why we'll do the above in a Thread:
    private Thread checkUpdate = new Thread() {
        public void run() {
            /* Web-Request Code Here */
        }
    };
    
    We can start a Thread with start() and do the request in the background (non-blocking).
    checkUpdate.start()
    Now we've got the content from the url, and might display a dialog or do anything else with the GUI. We can't do that from within a Thread, but we'll simply use a Handler that we post from the Thread. This is the code of the Runnable, which can interact with the GUI:
    private Runnable showUpdate = new Runnable(){
        public void run(){
            showPopupDialog(); // Custom Dialog Function
        }
    };
    That's all the single pieces. Let's put it together: Here is a whole activity that downloads in the background and shows a Toast message when finished:
    public class Iconic extends Activity {
        private String html = "";
    	private Handler mHandler;
    
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
        	mHandler = new Handler();
        	checkUpdate.start();
        }
            
        private Thread checkUpdate = new Thread() {  
            public void run() {  
                try {
                    URL updateURL = new URL("http://iconic.4feets.com/update");    
                    URLConnection conn = updateURL.openConnection(); 
                    InputStream is = conn.getInputStream();
                    BufferedInputStream bis = new BufferedInputStream(is);
                    ByteArrayBuffer baf = new ByteArrayBuffer(50);
                    
                    int current = 0;
                    while((current = bis.read()) != -1){
                        baf.append((byte)current);
                    }
                
                    /* Convert the Bytes read to a String. */
                    html = new String(baf.toByteArray());
                    mHandler.post(showUpdate);
                } catch (Exception e) {
                }
            }
        };
        
        private Runnable showUpdate = new Runnable(){
           	public void run(){
        	    Toast.makeText(Iconic.this, "HTML Code: " + html, Toast.LENGTH_SHORT).show();       	
            }
        };
    }

    Fatal error: Call to undefined function wpx_whatsNext() in /var/www/4feets.com/htdocs/wp-content/plugins/exec-php/includes/runtime.php(42) : eval()'d code on line 84