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();
}
}
Related
I am calling a Handler class from a background thread. In the Handler class, I am trying to display a toast. Theoratically it should work flawlessly because Handler is the Queue that forwards the UI tasks to the main UI thread. However, in my case the I am getting exception.
private void firstTimeLogin() {
final LoginUiThreadHandler loginHandler = new LoginUiThreadHandler();
new Thread(new Runnable() {
#Override
public void run() {
Message m = loginHandler.obtainMessage();
Bundle bund = new Bundle();
bund.putInt("loginResult", 1);
m.setData(bund);
loginHandler.handleMessage(m);
}
}).start();
}
private class LoginUiThreadHandler extends Handler {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int loginResult = msg.getData().getInt("loginResult");
if(loginResult == 0)
Toast.makeText(getActivity().getApplicationContext(), "Login success", Toast.LENGTH_SHORT).show();
}
}
What am I doing wrong?
Replace with -
LoginUiThreadHandler loginHandler = new LoginUiThreadHandler(Looper.getMainLooper());
instead of-
LoginUiThreadHandler loginHandler = new LoginUiThreadHandler();
I want to show this dialog, while the thread tries to build up a connection, but the dialog will not show up when I press the button which starts this method.
public void add_mpd(View view) {
dialog = ProgressDialog.show(MainActivity.this, "", "Trying to connect...");
new Thread(new Runnable() {
public void run() {
try {
String child;
EditText new_mpd = (EditText) findViewById(R.id.new_mpd);
child = new_mpd.getText().toString();
mpd = new MPD(child);
children.get(1).add(child);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (MPDConnectionException e) {
e.printStackTrace();
}
}
}
).start();
adapter.notifyDataSetChanged();
dialog.dismiss();
}
It will not show up because the (blocking) work is done in another thread. That means, the start()-method of the Thread-class will not block.
Ergo, you show the Dialog, the Thread is started and the dialog is immediately dismissed (and therefore closed).
Put the call to dismiss() at the end of your run()-method and it should work just fine.
The above might be working for you, but you should not use the Thread-class directly. There are wrappers around it which are way more comfortable to use.
In Android, if you want to do long-term work off the UI-Thread, you should use an AsyncTask.
Additionaly, to build up on what Lukas said, you can look at this example.
http://www.helloandroid.com/tutorials/using-threads-and-progressdialog
public class ProgressDialogExample extends Activity implements Runnable {
private String pi_string;
private TextView tv;
private ProgressDialog pd;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
tv = (TextView) this.findViewById(R.id.main);
tv.setText("Press any key to start calculation");
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
pd = ProgressDialog.show(this, "Working..", "Calculating Pi", true,
false);
Thread thread = new Thread(this);
thread.start();
return super.onKeyDown(keyCode, event);
}
public void run() {
pi_string = Pi.computePi(800).toString();
handler.sendEmptyMessage(0);
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
pd.dismiss();
tv.setText(pi_string);
}
};
}
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.
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 got thread exception in android , what i intend to do is, while clicking a button i started a thread going to dynamically invoke the handler ,handler update the text view with integer value , while reaching integer 10, i going to stop the thread and have to show an alert ,but it will cause an error, what i possibly doing is shown below
public class sample extends Activity implements Runnable{
public Camcorder()
{
try{
counterThread = new Thread(this);
}catch(Exception ee)
{
}
}
public void run()
{
try{
while(counterFlag)
{
System.out.println("The time starts at : "+counter);
Thread.sleep(1000);
calculate(counter);
counter++;
}
}catch(Exception ee){
System.out.println("Err in ee : "+ee);
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
c=this.getApplicationContext();
requestWindowFeature(Window.FEATURE_NO_TITLE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setContentView(R.layout.main);
authalert3 = new AlertDialog.Builder(this);
authalert3.setTitle("Save Video");
authalert3.setMessage("Do you want to save this Video?");
authalert3.setPositiveButton("Yes", null);
Button test = (Button) findViewById(R.id.widget33);
test.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
counter = 0;
counterFlag = true;
counterThread.start();
}
});
public void calculate(int counter2) {
// TODO Auto-generated method stub
if(counter2<60){
if(counter2<10)
{
smin="0"+counter2;
}
else{
smin=""+counter2;
}
}
else{
hours++;
counter=0;
smin="00";
if(hours<10){
shours="0"+hours;
}
else{
shours=""+hours;
}
}
handler.sendEmptyMessage(0);
}
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
String tes=shours+":"+smin;
time.setText(tes);
test();
};
};
public void test(){
duration=1;
if(duration==hours){
counterFlag = false;
videoPath=camcorderView.stopRecording();
authalert3.create().show();
counterThread.stop();
}
}
the error is thrown at counterThread.stop();
Anyone suggest me , how to solve this error.
You don't stop threads by calling counterThread.stop. This method is deprecated. In your case, by setting counterFlag = false; your thread should be stopping itself.
You will also be getting an exception if you click twice on your button: you cannot call start on a Thread that has already been started. You must create a new instance of that Thread and start that new instance (stop the old instance before if necessary).
You can see that SO answer for some sample code on how to create/stop threads: Android thread in service issue. I suggest that you also read some tutorial on Java Threads (this is not specific to Android).
Additionally I think that you don't need a thread at all, you are doing nothing complicated and thus you could simply use the handler to do all the work:
private static final int MSG_REFRESH_UI = 0;
private static final int MSG_UPDATE_COUNTER = 1;
private int counter = 0;
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
if (msg.what==MSG_REFRESH_UI) {
String tes=shours+":"+smin;
time.setText(tes);
test();
} else if (msg.what==MSG_UPDATE_COUNTER) {
counter++;
if (counter<10) {
calculate(counter);
handler.sendEmptyMessageDelayed(MSG_UPDATE_COUNTER, 1000);
handler.sendEmptyMessage(MSG_REFRESH_UI);
}
}
};
};
public void onResume() {
handler.sendEmptyMessage(MSG_UPDATE_COUNTER);
}
public void calculate(int counter2) {
if (counter2<10) {
smin = "0"+counter2;
} else if (counter2<60) {
smin = ""+counter2;
} else{
hours++;
counter=0;
smin="00";
if(hours<10){
shours="0"+hours;
} else {
shours=""+hours;
}
}
}
This will stop the thread at 10
while(counterFlag)
{
System.out.println("The time starts at : "+counter);
Thread.sleep(1000);
calculate(counter);
counter++;
if(counter == 10) counterFlag = false;
}