Android Show AlertDialog from Timer thread - android

I have a background thread that is started from a Timer. The thread runs every 60 seconds and may detect a fatal problem that requires the app to exit immediately. Before exiting I want to show an alert dialog. Because the thread runs every 60 seconds I have no way of knowing which activity is currently running. Without an activity I can't call runOnUiThread to show the alert dialog. Below is some code that should illustrate what I'm trying to do. Without knowing the current activity how do I get an AlertDialog to show on the UI thread?
public class Foo {
private Timer mTimer;
public void startRefresh() {
if (mTimer == null) {
mTimer = new Timer(true);
mTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
boolean succeeded = true;
// Do something that fails
succeeded = false;
if (!succeeded) {
// Display alert dialog on UI thread before exiting application
}
}
}, 60000, 60000);
}
}
}

Pass the activity context to the Foo constructor
public class Foo {
Context mContext;
// constructor
public Foo(Context context){
this.mContext = context;
}
...
if (!succeeded) {
// Display alert dialog on UI thread before exiting application
}
}
public void displayAlert(Context context){
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
alertDialog.setTitle("Display alert");
alertDialog.setMessage("My Alerts");
// Showing Alert Message
alertDialog.show();
}
EDIT
Which activity? The whole problem is that the Activity that started
the timer may not be the current activity when the error is detected.
Then don't use the constructor just use getApplicationContext() instead:
public abstract Context getApplicationContext ()
Added in API level 1 Return the context of the single, global
Application object of the current process. This generally should only
be used if you need a Context whose lifecycle is separate from the
current context, that is tied to the lifetime of the process rather
than the current component.
runOnUiThread(new Runnable() {
#Override
public void run() {
// Your dialog code.
}
});

Related

How to call the handler from separate class in android?

In my application, am try to set an time out function i not able to call the handler method in separate class.
My Timeout Class
public class Timeout_function {
private Handler mHandler;
Activity activity;
public Timeout_function(Activity activity,Handler mHandler) {
super();
this.activity = activity;
this.mHandler = mHandler;
}
Runnable myTask = new Runnable() {
#Override
public void run() {
Toast.makeText(activity, "Test", 1000).show();
mHandler.postDelayed(this, 1000);
}
};
// just as an example, we'll start the task when the activity is started
public void onStart() {
mHandler.postDelayed(myTask, 1000);
}
// at some point in your program you will probably want the handler to stop
// (in onStop is a good place)
public void onStop() {
mHandler.removeCallbacks(myTask);
}
}
Main class
In main class i call the method in this way,but it shows error in run time,
Timeout_function timeout = new Timeout_function(this, mHandler);
timeout.onStart();
how to call the method in main class.can any one know please help me to solve this problem.
Instead of creating a seperate class why you are not using Service?
I would insist you to use Service and start your Runnable using Handler in onStartCommand() of Service by call startService(intent);
and you can stop the Runnable using Handler by placing it inside onDestroy() method of Service and calling by stopService(intent).
This is what I had done and it works like a charm!

BadTokenException when launching a dialog in asyncronous thread

I have an activity that makes an asynchronous connection, like this:
new Thread(new Runnable() {
public void run() {
try{
//Make Connection
}catch(Exception e){
runOnUiThread(new Runnable() { public void run() {
Dialogs.showErrorDialog(MyActivity.this); //I display an error dialog using this context
} });
}
}
}).start();
Imagine that the connection is really slow, and I leaved the activity that launched this thread. If the connection finally goes well, everything is fine, but if the connection fails, it crashes when launching the dialog, as the context does no longer exist. The error is:
android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy#4068a558 is not valid; is your activity running?
How to avoid this error? I would like to detect if my activity is still alive to either
1) show a dialog with this context (if I'm still on the screen)
2) show a Toast with ApplicationContext (if I'm outside the screen)
EDITED:
The dialog code is this:
static public void showErrorDialog(Context context){
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setTitle(R.string.error_title);
builder.setMessage(R.string.error_content);
builder.setPositiveButton(R.string.button_ok,null);
builder.show();
}
How to avoid this error?
I suggest you to use this:
runOnUiThread(new Runnable() {
public void run() {
if (!(((Activity) context).isFinishing())) { // you need to pass Context.
Dialogs.showErrorDialog(context);
}
}
});
Let me know if it works.
Note: If it won't works, i recommend to you use AsyncTask instead of runOnUiThread().
can't change UI in thread; you use RunOnUiThread, but the UiThread still in the thread.
You can use AsyncTask to do it.
class ConnectionTask extends AsyncTask<Void, Void, Boolean> {
protected Boolean doInBackground(Void... params) {
//Make Connection
boolean flag = connecting(); //flag is connect state: success or fail
return flag;
}
protected void onPostExecute(Boolean result) {
if (!result) {
Dialogs.showErrorDialog(MyActivity.this);
}
}
}
then, use as follows:
ConnectionTask task = new ConnectionTask();
task.execute();

Using a Service with A Timer to Update a View

I'm not sure if this is the correct way to go about but I will try and explain what I want to do.
I have an Activity which creates a fragment called TemporaryFragment with a label. What I want to do is create and start a service with a Timer in it and that Timer then updates the time in that TextView.
The way I am thinking of going is somehow, when the Service is started, passing the TextView from the Activity to the Service and then the Service keeping a reference to it.
Another possible way is to make the Activity become a listener of the Service and then calling a method in the Service to update the TextView.
Any thoughts would be great and maybe some options.
Thanks in advance.
ADDITION
I'm sorry, I should also specify that I need this timer to run in the background. So when the application is sent to the background, I need the timer to carry on and only stop when I tell it to.
Service is not ideal for such minor task like this, moreover, Service can be run independently of activity. Also spawning new thread or using timer which introduces new thread into the application is not ideal for this relatively minor reason if you are thinking in the terms of mobile applications.
Instead use Handler in your fragment.
create handler in your fragment
private Handler mHandler = new Handler();
to execute your defined task call
mHandler.postDelayed(mUpdateTask, 1000);
or
mHandler.post(mUpdateTask);
and define your task in the fragment
private Runnable mUpdateTask = new Runnable() {
public void run() {
Toast.makeText(getActivity(), "hello world", Toast.LENGTH_SHORT).show();
mHandler.postDelayed(this, 1000);
}
};
If you are showing time-like information instead of countdown-like one, use
mHandler.removeCallbacks(mUpdateTimeTask);
in onPause() method to stop executing your task if the activity is not visible as updating UI isn't relevant and it saves battery (you start task again in onResume() method)
Basically, the idea behind the timer is eventually I am going to add some tracking into my application and therefore need it to continue running even if the application isn't in the foreground – Disco S2
Based on this comment I suggest you to use a local service which resides in the background, doing it's stuff (start a thread from Service#onStart), until it gets stopped by stopService(..).
Activities on the other hand may bind and unbind to that service (see: bindService(..)) to get notified about updates or to communicate with the service in any way.
I would use a more simple approach by using a Thread:
public class MainActivity extends Activity implements Callback {
private static final int MSG_UPDATE = 1;
private static final long INTERVAL = 1000; // in ms
private final Handler handler = new Handler(this);
private Thread worker;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE:
updateView();
return true;
}
return false;
}
private void updateView() {
// TODO tbd
}
#Override
protected void onStart() {
super.onStart();
// start background thread
worker = new Thread(new Runnable() {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(INTERVAL);
} catch (InterruptedException e) {
break;
}
// send message to activity thread
handler.sendEmptyMessage(MSG_UPDATE);
}
}
});
worker.start();
}
#Override
protected void onStop() {
super.onStop();
// stop background thread
worker.interrupt();
try {
worker.join();
} catch (InterruptedException e) {
}
worker = null;
}
}
You can use the TimerTask Class for this. Override the TimerTask.run() method and then add that TimerTask to Timer class.
Also check this question: controlling a task with timer and timertask

Calling same dialog from different threads

I have an android application with different activities and they all pull data from a web source. This is done by implementing Runnable and creating a thread with the activity as object. The basic class looks like this:
public ActivityX extends Activity implements Runnable {
#Override
public onResume() {
super.onResume();
Thread someThread = new Thread(this);
someThread.start();
}
#Override
public run() {
try {
// pull web content
}
catch(TimeOutException e) {
// >>> create dialog here <<<
// go back to another activity
}
}
}
I tried to create a dialog helper class with a static method that returns the timeout dialog and then call show() like this:
HelperClass.getTimeOutDialog().show();
but the problem is, I can't call it from inside the run() method, as it's in a different thread. If I try to, I will get a runtime exception stating:
Can't create handler inside thread that has not called Looper.prepare()
I need to do this dialog for nearly a dozen of activities and I really want to get around using a Handler objects and sending a message to call the dialog every time. Isn't there an easier way to do this? I just can't think of any right now unfortunately.
My code would look something like this:
handler.handleEmptyMessage(1);
This is to call the handler. And the following would handle the message:
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if(msg.what == 1) {
// show dialog here
}
}
};
Cheers
#Override
public run() {
try {
// pull web content
}
catch(TimeOutException e) {
runOnUiThread(new Runnable(){
#Override
public void run() {
// >>> create dialog here <<<
// go back to another activity
}
}
}
}
Try the one above if you don't want to use Handler.
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if(msg.what == 1) {
// show dialog here
}
}
};
Is this code a part of your activity and not in a thread? If it is a part of your non Ui thread, it would give you the error message. Make sure the handler instance is created in your UI thread because a handler contains an implicit reference to the thread they get created in.

Show an Alert Builder from a non-activity

I'm trying to show an alert dialog with my application from a non-activity.
So the hard thing here is that I want to do it not in an activity but in my general application class.
public class AppName extends com.github.droidfu.DroidFuApplication {
public static long TIME_CONTENT_UPDATE = 60; //half hour
Handler mHandler = new Handler();
#Override
public void onCreate() {
super.onCreate();
intent = new Intent(this, VSSyncController.class);
setupTimer();
}
private void setupCatalogTimer() {
final Context con = this;
//A handler runs on a separate thread
mHandler = new Handler(new Handler.Callback() {
public boolean handleMessage(Message msg) {
showMyAlertDialog(con)
mHandler.sendEmptyMessageDelayed(0, TIME_CONTENT_UPDATE);
return true;
}
});
}
}
Basically I want to show an alert dialog from there, but I need to have a way to figure out which and IF there is any activity in the foreground, so I can call it from there.
How can I possible do it?
Thanks!
Keep track of this yourself via onPause() and onResume() in each of your activities. There is nothing built in that provides this data to you.
Thinking out of the box what I did was send a notification (when the dialog was suppose to pop) that takes the user back to the activity and there it shows the dialog!
This way we don't deal with the problem to check which activity is not in front.

Categories

Resources