Updating the UI in native mode with an on-stream handler (Android)
I am trying to make multiple connections in a classroom and update multiple progress bars on the main screen.
But I have the following error when trying to use thread in android: Code: 05-06 13: 13: 11.092: ERROR / ConnectionManager (22854): ERROR: Cannot create a handler inside a thread that did not call Looper.prepare ()
Here is a small section 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);
}
}
Failure errors occur on the first line "case DIALOG_PROGRESS_NETWORK:". My first progress bar is hidden, but the second is not visible.
I think I did something wrong using streams and handlers, but I don't know why.
At first I used handler.sendMessage instead of handler.handleMessage, but when I had multiple tasks in my connection manager, the progress indicator only updated at the end of all tasks.
Thanks in advance for your help
a source to share
Having a final handler and declaring it in the class definition is great. Also, in your last piece of code, when you initialize a handler in onCreate, you are actually "shadowing" the handler declared in your class, so you don't initialize it. I'm very surprised that you didn't have a NullPointerException.
But in ConnectionManager :: updateProgressBar, you really need to call sendMessage (), because by calling handleMessage () directly, the handler is called from the ConnectionManager :: updateProgressBar thread (which is probably not the UI thread).
I'm not sure what caused you problems with updating the progress bars only once, but this is definitely a logic error somewhere. Try registering at different stages of your application. before sending a message and while processing it -.
a source to share
Hrk, the shadow part is when you declare a local variable inside a method with the same name as the field:
Handler handler = ...
To use this field, omit the type:
handler = ...
As for the exception, just create the objects ProgressDialog
on the main thread (for example in the onCreate () method) and call one of the show () methods later.
a source to share