So I'm using this code to show the message "Installing..." while the database is setup with the function 'setUpDB' and is then removed when the database function has completed. This works fine in Gingerbread and honeycomb, but causes the application to crash in ICS
final ProgressDialog pd=ProgressDialog.show(this,"","Installing...");
final Handler handler = new Handler()
{
public void handleMessage(Message msg)
{
if(msg.what==0)
{
pd.dismiss();
}
}
};
//have subcategory heading???
Thread thread = new Thread()
{
#Override
public void run() {
setUpDB();
handler.sendEmptyMessage(0);
}
};
thread.start();
Without dismissing the message, the app will continue to run in ICS (but you can't do anything), and without displaying the message if the user does anything that accesses the database before it is finished being setup it will crash (thus why I need the installing message)..
Okay, here is the code using AsyncTask
final ProgressDialog pd=ProgressDialog.show(this,"","Installing...");
final Handler handler = new Handler()
{
public void handleMessage(Message msg)
{
if(msg.what==0)
{
pd.dismiss();
}
}
};
new databaseInstallTask().execute(handler);
And
private class databaseInstallTask extends AsyncTask<Handler, Void, Handler>
{
#Override
protected Handler doInBackground(Handler... params) {
setUpDB();
return params[0];
}
protected void onPostExecute(Handler handler) {
handler.sendEmptyMessage(0);
}
}
Why don't you try using Asynctask which I suppose is the most appropriate way to handle your case.
Related
I use AsyncTask in combination with a ProgressDialog.
See my code, I have a problem in onPostExecute.
If the task is running for the first time it get a Null Poiter Exception for progressDialog in handleMessage but calling dismiss() direct would work.
When I turn the phone before onPostExecute is reached, progressDialog.dismiss() does not work. why does the handler not always work?
public class UpdateTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog progressDialog;
private Handler handler;
public UpdateTask(Act activity) {
progressDialog = ProgressDialog.show(Activity.this, "Wait",
"Wait");
progressDialog.dismiss();
handler = new Handler(){
#Override
public void handleMessage(Message msg) {
//run on UI Thread
switch( msg.what ){
case MSG:
progressDialog.show();
break;
case DETACH:
progressDialog.dismiss();
break;
}
}
};
}
void detach() {
activity=null;
//problematic
//progressDialog.dismiss();
//handler.sendEmptyMessage(DETACH);
}
#Override
protected Void doInBackground(Void... params) {
handler.sendEmptyMessage(MSG);;
return null;
}
protected void onPostExecute(Void result) {
if (activity==null) {
Log.w("RotationAsync", "onPostExecute() skipped -- no activity");
}
else {
//problematic
// progressDialog.dismiss();
handler.sendEmptyMessage(MSG);
progressDialog = null;
}
}
};
Any reason why you need the Handler inside the AsyncTask? If you want to control your progress dialogue from an AsyncTask using a Handler is the correct way, however, your current Handler would get created and destroyed each time you start a new UpdateTask. If you define your handler outside your AsyncTask, something like:
private Handler handler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
switch( msg.what ){
case MSG:
progressDialog.show();
break;
case DETACH:
progressDialog.dismiss();
break;
}
return false;
}
});
Now you can call handler.sendEmptyMessage(what) from any background thread safely, and the progressDialog will update on the UI thread only. Not a complete fix, and I don't know what int values you have defined for DETACH and MSG. But hopefully it will help. This is the method I use to update any UI element from a background task. Just do a bit more reading about the AsyncTask and updating UI elements.
See https://stackoverflow.com/a/4538370/719212
And you should read about onPreExecute() in Android documentation.
I am new to Android dev, and am trying to solve this problem that has been giving me some frustration. I am trying to close this progressDialog. When I run the app, it displays, the information is fetched, and the UI is updated. However, the dialog is never dismissed.
progDialog = ProgressDialog.show(HomeActivity.this, "", "Fetching info...", true, false);
new Thread(new Runnable() {
public void run() {
fetchInfomation(userID); //fetches information - Works
runOnUiThread(new Runnable() {
public void run() {
setLayoutList(); //updates UI - Works
progDialog.dismiss(); //doesn't seem to close progress dialog
firstView(); //displays prompt - Works
}
});
progDialog.dismiss(); //doesn't close dialog either
}
}).start();
Any ideas?
You can't interact with UI inside an external thread. There is some techniques to do that but it's not necessary.
You can use Handler.
For example:
...
private Handler mHandler;
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mHandler = new Handler() {
#Override
public void handleMessage (Message msg) {
switch (msg.what) {
case 0: ...
case 1: ...
}
}
}
}
And:
....
new Thread() {
#Override
public void run() {
... // do your background jobs here
mHandler.sendEmptyMessage(...); // interact with UI
});
}
}.start();
It will be good practice if you do any GUI updates on UI thread. Inside any thread you can run your UI thread where you can do the UI stuffs or else you can go for message handler also which will do the same for you.
Runnable run_in_ui = new Runnable() {
#Override
public void run() {
// do your UI stuffs here
}
};
runOnUiThread(run_in_ui);
final ProgressDialog Pdialog = ProgressDialog.show(SpinnerClass.this, "",
"Loading. Please wait...", true);
Thread ProgressThread = new Thread() {
#Override
public void run() {
try {
sleep(3000);
Pdialog.dismiss();
} catch(InterruptedException e) {
// do nothing
} finally {
}
}
};
ProgressThread.start();
TabHost1 TabHost1Object2 = new TabHost1();
TabHost1Object2.tabHost.setCurrentTab(2);
The problem I have with this thread is that it sets the current tab before the progress dialog starts. What have i done wrong ?
I want the dialog to run and dismiss, and after thread is done set tab.
use AsyncTask for this
some hints:
public class BackgroundAsyncTask extends AsyncTask<Void, Integer, Void> {
int myProgress;
#Override
protected void onPostExecute(Void result) {
TabHost1 tab = new TabHost1();
tab.tabHost.setCurrentTab(2);
progressBar.dismiss();
}
#Override
protected Void doInBackground(Void... params) {
while(myProgress<100){
myProgress++;
publishProgress(myProgress);
SystemClock.sleep(100);
}
return null;
}
#Override
protected void onProgressUpdate(Integer p) {
progressBar.setProgress(p);
}
}
The thing is that,you are starting a thread which will not affect your main UI. So what eventually happens is that, your thread will run separately which will now allow the next lines of your code to be executed. So in your case,
TabHost1 TabHost1Object2 = new TabHost1();
TabHost1Object2.tabHost.setCurrentTab(2);
these lines will be executed irrespective to your thread which is also getting executed simultaneously. So what you can do here is you can either go for AsyncTask or create handlers to handle this part of your code. You have to change your code like this.
Do this in your onCreate()
Handler handler;
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.what == 0) {
Pdialog.dismiss();
TabHost1 TabHost1Object2 = new TabHost1();
TabHost1Object2.tabHost.setCurrentTab(2);
}
};
And now in your thread,call the handler like this,
final ProgressDialog Pdialog = ProgressDialog.show(SpinnerClass.this, "",
"Loading. Please wait...", true);
Thread ProgressThread = new Thread() {
#Override
public void run() {
try {
sleep(3000);
} catch(InterruptedException e) {
// do nothing
} finally {
handler.sendEmptyMessage(0);
}
}
};
this will allow your tabhost to wait until the thread gets executed and will come into view after thread finishes execution.
I have the following:-
public class resApp extends MapActivity implements Runnable {
public void run() {
searchImage.setVisibility(View.GONE);
}
}
I also have a background thread that runs before this but that seems to run ok.
When i run the app the run() never gets called.
Can you help?
This code did work about 6 months ago but the device was 2.1.
Thanks
Chris
edit
I had already implemented
private Handler handler;
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.toString().equalsIgnoreCase("1")) {
ad.dismiss();
} else {
pd.dismiss();
}
}
};
as an example and I already have an asynchronous task that runs in the back ground and in 2.1 I could have getters and setters in there. I have now had to pull these out and put them into the run() method as 2.2 doesn't like setting onclicklistener in an async task.
All I need to do is call the run() method on post execute but have tried everything:-
protected void onPostExecute(Object result) {
// Pass the result data back to the main activity
if (dialog != null) {
resApp.this.dialog.dismiss();
}
}
Could I just do:-
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
this.resApp.run();
}
};
You can call the run() method by using Handler.
Handler myHandler = new Handler();
resApp myObj;
And call it by using myHandler.post(myObj);
public class Connection extends Activity implements Runnable {
public static final int CONNECTION_ERROR = 1;
public static final int CONNECTION_DONE = 3;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
createConnection();
}
public void createConnection() {
m_ProgressDialog = ProgressDialog.show(this, "Please wait...","Connection ...", true, false);
thread = new Thread(this);
thread.start();
}
public void run() {
int i = connecTion();
handler.sendEmptyMessage(i);
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.what == CONNECTION_ERROR) {
m_ProgressDialog.dismiss();
AlertDialog.Builder alt_bld = new AlertDialog.Builder(thisA);
alt_bld.setMessage("Failed to connect to the server");
alt_bld.setCancelable(false);
alt_bld.setNegativeButton("Quit",new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int id) {finish();}});
alt_bld.setPositiveButton("Try Again",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//HERE IS THE PROBLEM
/*m_ProgressDialog.show(thisA, "Please wait...", "Connection ...", true, false);
connecTion();*/
}
});
AlertDialog alert = alt_bld.create();
alert.setTitle("ChatApp");
alert.setIcon(R.drawable.icon);
alert.show();
}
else {
m_ProgressDialog.dismiss();
finish();
}
}
};
private int connecTion() {
/** Create a connection */
try {
//Function to create the connection (throwing error if there is a pb)
} catch (Exception e) {
Log.e("App","Failed to connect");
return CONNECTION_ERROR;
}
//If no error left, everything is OK
return CONNECTION_DONE;
}
I want to realize a "Try Again" button which launch again the thread to create the connection and the ProgressDialog in parallel.
How can I kill the "old" thread and create the new one properly?
Is it better to keep the same thread alive and just dealing with Handler and Messages? Use service?
Thank you !
You could setup a pipeline thread; I've detailed how you can do this on my blog (Threading 5). Also note that once a thread completes, it cannot be restarted again. You can however, keep a single thread alive and schedule work to it.
Another approach is to instantiate a single thread each time you offload the background task; it'll complete and expire - this is the simpler way of going about it. It might be worth looking into AsyncTask.
The way I usually handle this is through a helper Class that extends Thread so:
public class DoAyncStuff extends Thread
{
protected Handler mHandler;
public DoAyncStuff(Handler handler)
{
mHandler = handler;
}
public void run()
{
// Do async stuff here
// send message back once done
Message msg = Message.obtain(mHandler, CONNECTION_ERROR_OR_OTHER_MESSAGE);
mHandler.sendMessage(msg);
}
}
// to use
DoAyncStuff asyncTask = new DoAyncStuff(mContext, mHandler)
asyncTask.start();
// Then in your handler you can check to async task results and restart if needed
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.what == CONNECTION_ERROR_OR_OTHER_MESSAGE) {
// prompt to try again
// if trying again
DoAyncStuff asyncTask = new DoAyncStuff(handler)
asyncTask.start();
}
}