Update UI in the main activity through handler in a thread (Android)

43,180

Solution 1

Make Handler handler non-final and init it inside onCreate().

Solution 2

Having the Handler final and declaring it in the class definition is perfectly fine. Moreover in your last snippet of code when you initialize your Handler in onCreate, you are actually "shadowing" the handler declared in your class, so not initializing it. I'm quite surprised you didn't had any NullPointerException.

But in ConnectionManager::updateProgressBar you really need to call sendMessage() because by calling handleMessage() directly, the handler gets called from the thread of ConnectionManager::updateProgressBar (which is probably not the UI thread).

I'm not sure what caused you the problem of having the progress bars updated only once, but it's surely a logic bug somewhere. Try to log at different steps of your app -ie. before sending the message, and while handling it-.

Share:
43,180
Hrk
Author by

Hrk

Android developer

Updated on March 09, 2020

Comments

  • Hrk
    Hrk about 4 years

    I try to make several connection in a class and update the multiple progressbar in the main screen.

    But I've got the following error trying to use thread in android : Code: 05-06 13:13:11.092: ERROR/ConnectionManager(22854): ERROR:Can't create handler inside thread that has not called Looper.prepare()

    Here is a small part of my code in the main Activity

    public class Act_Main extends ListActivity 
    { 
     private ConnectionManager cm; 
    
     public void onCreate(Bundle savedInstanceState) 
     { 
          super.onCreate(savedInstanceState); 
    
          // Set up the window layout 
          requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); 
          setContentView(R.layout.main); 
          getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title); 
     } 
    
     public void startConnection() 
     { 
          //open DB connection 
          db = new DBAdapter(getApplicationContext()); 
          db.open(); 
    
          cm = new ConnectionManager(handler, db); 
          showDialog(DIALOG_PROGRESS_LOGIN); 
     } 
    
     @Override 
     public void onStart() 
     { 
          super.onStart(); 
          startConnection(); 
     } 
    
     protected Dialog onCreateDialog(int id) 
     { 
          switch (id) 
          { 
          case DIALOG_PROGRESS_LOGIN: 
               progressDialog = new ProgressDialog(Act_Main.this); 
               progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 
               progressDialog.setMessage("Connecting.\nPlease wait..."); 
               progressThreadLogin = new ProgressThreadLogin(); 
               progressThreadLogin.start(); 
    
               return progressDialog; 
          case DIALOG_PROGRESS_NETWORK: 
               [b]progressDialog = new ProgressDialog(Act_Main.this);[/b] 
               progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 
               progressDialog.setMessage("Loading entire network.\nPlease wait..."); 
               progressThreadNetwork = new ProgressThreadNetwork(); 
               progressThreadNetwork.start(); 
    
               return progressDialog; 
          default: 
               return null; 
          } 
     } 
    
    
     // Define the Handler that receives messages from the thread and update the progress 
     final Handler handler = new Handler() 
     { 
          public void handleMessage(Message msg) 
          { 
               int total = msg.getData().getInt("total"); 
               int step = msg.getData().getInt("step"); 
    
               Log.d(TAG, "handleMessage:PROCESSBAR:"+total); 
               progressDialog.setProgress(total); 
    
               if (total >= 100) 
               { 
                    switch (step) 
                    { 
                         case UPDATE_NETWORK: 
                              dismissDialog(DIALOG_PROGRESS_LOGIN); 
                              showDialog(DIALOG_PROGRESS_NETWORK); 
                              cm.getNetwork(); 
                              break; 
                                        .... 
                         default: 
                              break; 
                    } 
               } 
          } 
     }; 
    
     private class ProgressThreadLogin extends Thread 
     { 
          ProgressThreadLogin() { } 
          public void run() { cm.login(); } 
     } 
    
     private class ProgressThreadNetwork extends Thread 
     { 
          ProgressThreadNetwork() { } 
          public void run() { cm.getNetwork(); } 
     } 
    }
    

    And my connectionManager class:

    public class ConnectionManager 
    { 
     public ConnectionManager(Handler handler, DBAdapter db) 
     { 
          this.handler = handler; 
          this.db = db; 
     } 
    
     public void updateProgressBar(int step, int value) 
     { 
          if (value == 0) 
               total = total+1; 
          else 
               total = value ; 
    
          Message msg = handler.obtainMessage(); 
                Bundle b = new Bundle(); 
                b.putInt("total", total); 
                b.putInt("step", step); 
                msg.setData(b); 
                handler.handleMessage(msg); 
     } 
    
     public void login() 
     { 
                //DO MY LOGIN TASK 
          updateProgressBar(Act_Main.UPDATE_NETWORK, 100); 
     }
    }
    

    The crash errors occurs on the first line of "case DIALOG_PROGRESS_NETWORK:". My first progressbar is hidden but the second one is not displayed.

    I think I've done somthing wrong using the threads and handlers but I dont' know why.

    I was first using handler.sendMessage in place of handler.handleMessage but when I had several task in my connectionManager, the progressbar was updated only at the end of all tasks.

    Thank you in advance for your help