Hey all - this code might be a bit messy in the way I'm trying to clean up the handler as I've been trying to track down where the crash happens...
I've got a dialog activity that is showing a password entry with a progressbar being animated by a thread and handler...
It seems that when I'm attempting to see if the progressbar is done, and trying to kill the thread, the way I'm doing this is messing something up when I try to go to a new activity - ie in a way calling a function and not having anything to return to or something...
public class RMO_Dialog extends Activity {
private ProgressBar progbar;
private Button dialogOK;
private EditText dialogPass;
private SharedPreferences prefs;
private String pass;
private int increment=10;
private Thread background;
private Boolean commCalled=false;
public void callCommunications(){
progbar.setVisibility(0);
progbar.setProgress(0);
background.stop();
Toast.makeText(getApplicationContext(), "Call communication should happen once.", Toast.LENGTH_LONG).show();
// Intent i = new Intent();
// i.setClass(RMO_Dialog.this, RMO_Comm.class);
// i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// startActivity(i);
// finish();
}
public void buzzUser(){
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
int dot = 200;
int dash = 500;
int short_gap = 200;
int medium_gap = 500;
int long_gap = 1000;
long[] pattern = {0,dot, short_gap, dot, short_gap, dot, medium_gap, dash, short_gap, dash, short_gap, dash, medium_gap, dot, short_gap,
dot, short_gap, dot, long_gap};
v.vibrate(pattern, -1);
}
public void killCountdown(){
progbar.setVisibility(0);
progbar.setProgress(0);
background.stop();
}
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.dialogpassword);
buzzUser();
prefs = this.getSharedPreferences("RMO", MODE_WORLD_READABLE);
pass = prefs.getString("password", "");
dialogOK = (Button) findViewById(R.id.dialogOK);
dialogPass = (EditText) findViewById(R.id.dialogPass);
progbar = (ProgressBar) findViewById(R.id.progress);
progbar.setProgress(0);
background = new Thread(new Runnable(){
@Override
public void run() {
try{
while(progbar.getProgress()<=progbar.getMax()){
Thread.sleep(300);
progressHandler.sendMessage(progressHandler.obtainMessage());
}
}catch(java.lang.InterruptedException e){
Toast.makeText(getApplicationContext(), "Error thrown.", Toast.LENGTH_LONG).show();
}
}
});
background.start();
dialogOK.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(dialogPass.getText().toString().equals(pass.toString())){
killCountdown();
Toast.makeText(getApplicationContext(), "Guardian Angel next alert has been disengaged.", Toast.LENGTH_LONG).show();
Intent intent = new Intent();
intent.setClass(RMO_Dialog.this, RMO.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
}else{
callCommunications();
}
}
});
}
Handler progressHandler = new Handler(){
public void handleMessage(Message msg){
progbar.incrementProgressBy(increment);
if(progbar.getProgress()==progbar.getMax()){
Toast.makeText(getApplicationContext(), "commcalled: "+ commCalled, Toast.LENGTH_LONG).show();
if(commCalled==false){
commCalle开发者_如何学Pythond=true;
callCommunications();
}
}
}
};
}
Thread.stop is deprecated call, instead you should use the Thread.interrupt method.
public void killCountdown(int waitTime){
progbar.setVisibility(0);
progbar.setProgress(0);
// deprecated: background.stop();
background.interrupt(); // <-- OK
background.join(waitTime); // optionally wait for the thread to exit
}
Thread.Interrupt
will cause a ThreadInterruptedException
next time your thread blocks or sleeps and you're already handling in your thread body so that's good. Additionally, you might want to include a volatile
flag that will allow you to stop the thread when it's not blocking or sleeping, but that's optional.
You might consider using an AsyncTask instance instead of a runnable and a handler.
If you need to cancel an AsycnTask instance just call .cancel(true)
on your AsyncTask object reference. This will take care of both the background method (doInBackground()
) and the progress updater (onProgressUpdate()
).
I generally find AsyncTask easier to use than trying to handle all the details myself.
So, inside RMO_Dialog, use call execute()
on an instance of a class you create that extends AsyncTask.
public class RMO_Dialog extends Activity {
...
// Get ref to your bg task for easily cancellation if needed
PassWordEntry background = new PassWordEntry();
// Start bg task
background.execute([PARAMS]);
...
// Cancel task
background.cancel(true);
...
// AsyncTask lets you encapsulate both your runnable and handler in it
private static class PassWordEntry() extends AsyncTask<[PARAMS], [PROGRESS], [RESULT]> {
protected [RESULT] doInBackground() {
... // Runnable stuff here
return [RESULT];
}
protected void onProgressUpdate([PROGRESS]... progress) {
... // progressHandler stuff here
}
protected void onPostExecute([RESULT]) {
// Clean up return data when all done w BG here
}
}
}
精彩评论