I guess this is a question straight to Mark, but I can't for the life of me get a Toast notification to work from inside the doWakefulWork method of WakefulIntentService. It works from the onCreate, but I need to use some data I am getting through the intent within the toast message.
I've tried to instantiate the handler from within the OnCreate but this doesn't seem to do anything. I've tried everything I can think of. The Toast just doesn't seem to run on the main thread. Any help?
In general, WakefulIntentService is not designed for scenarios where a Toast would make any sense, since the user may or may not be around. Moreover, services should not be directly affecting the UI this way, since if the user is around the user may not appreciate your Toast in the middle of their game, their navigation, their movie, etc. I would rather you use something else (e.g., ordered broadcast to update a foreground activity or display a Notification if there is no such activity).
If you are really certain that you want to use a Toast from a service, your problem should have nothing to do with WakefulIntentService -- you would have the same problems with a regular IntentService. This SO question has some answers demonstrating the use of a Toast from a service's background thread using a Handler, which may help indicate where your Handler implementation is going wrong.
private boolean showToast = false;
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (showToast) {
Toast.makeText(this,"YourText",Toast.LENGTH_LONG).show();
showToast = false;
}
}
Just set showToast = true; from anywhere to showing you toast notification.
Related
I have a fairly complex app which in many cases calls post or postDelayed methods on Handler. Everything is working fine as of now.
But, I am worried that when Android decides to pause/kill the activity I may still have some very important tasks pending to be executed. Just ignoring them will affect integrity of the data.
I am aware of onPause and onDestroy calls on Activity class and I am already using them for normal cleanups. But I am not sure how I should handle the pending stuff in the Handler object.
Am I supposed to somehow get all the pending ones from Handler and call their run method explicitly, by sitting in a loop inside the onPause/onDestroy?
or
Does Android has a standard way of handling this scenario?
I am deeply in need of some guidance on this subject.
Please help.
-Androbean
No other way. LifeCycle methods (onPause/Stop/Destroy) is a standard scenario. There you can clear callbacks for all your runnable objects:
Runnable runnable = new Runnable() {
#Override
public void run() {
}
};
handler.postDelayed(runnable, 100);
handler.removeCallbacks(runnable);
So, it will never called (if it still waiting for run).
First of all you must learn how is the activity lifecyle.
http://developer.android.com/intl/es/training/basics/activity-lifecycle/starting.html
Don't look for a magic trick, just assume what system gives you and choose a proper design.
I'm writing a library that uses a Timer to perform scheduled background processing. One key feature is to conserve battery life, so I'd like to have my library pause the background processing when the app isn't actively used.
Ideally, it would be great if equivalents to Activity.onPause() and Activity.onResume() could be received by my library without having to create an API for it. I don't want to have to rely on the dev, who's implementing my library, to have to call MyLibrary.onPause() and MyLibrary.onResume() throughout the various activities of their app.
Are there any other solutions apart from API's ? I thought maybe there is a broadcast that my library could register for - but I haven't found anything useful at the moment... looking for suggestions...
Thanks !!
You can use registerActivityLifecycleCallbacks() to set up a listener for Activity life cycle events. It's API 14+ but this should not be a big deal nowadays.
There are many misconceptions in your questions so it's hard to answer but I can give you a few advices.
First you should never use a Timer to schedule work on Android. You should use Handler to schedule UI events and AlarmManager with a Service (like IntentService) for background work which is independent from Activities.
If the work is directly tied to your Activities, you should not schedule the work using AlarmManager but use a bound Service. This kind of service automatically stops when no Activity is connected to it.
If the work is independent from your Activities, then the best way to save battery is to choose an appropriate running frequency in AlarmManager and use inexact repeating. This way the system will likely run all pending tasks in a single batch to save power.
I invite you to read the documentation of all the components I mentioned.
You can use some few Hacks
View.isShown()
by taking in an Activity as a context, in your library, and continuously checking for isShown() on its DecorView
MyLibrary(Context context){
if(context instanceof Activity){
boolean activityStatus = ((Activity)c).getWindow().getDecorView().isShown();
//true means it is shown, and you start your loop and keep checking something like this
Thread t = new Thread(new Runnable() {
#Override
public void run() {
for(;;){
boolean tempStatus = ((Activity)c).getWindow().getDecorView().isShown()
&& activityStatus && /*((Activity)c).getWindow().
getDecorView().isLaidOut() if api 19+*/;
if(tempStatus){
//it is still showing or its previous value is being maintained
}else{
//it has been changed..
}}}});}//ending braces
some limitations will be that, when a DialogFragment is shown it might check out true, maybe or maybe not, but you can check if the current focus on a View is on that Window by doing getWindow().getCurrentFocus() which will return a non-null; you can try this and see
Activity.hasWindowFocus()
which will always return false on onPause() and true when your Activity is on
Inside onCreate of Application class, I set its instance to a static field, then show all application Toasts through this context. All works good except one thing, in some places a Toast can be shown before first activity can even appear but Toast never appears or sometimes just flashes. I think its because Activity not shown or drawn yet ? Or I'm missing something.
Edit:
More like showing toast from onCreate of Application class
Edit 2 :
public class TestApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Test from App", Toast.LENGTH_LONG).show();
}
}
If you want to show a Toast without the application even started manually by the user you can register a BroadcastReceiver which listens to the BOOT_COMPLETED system broadcast and then start a Service which will handle your Toasts.
You'll find many examples on how to do this.
To make a Toast before drawing your layout resources, just do this following.
//put this code before your setContentView(R.layout.your_layout);
Toast.makeText(yourclassName.this,"your text here",5000).show();
Well, consider one thing. If you want this toast to be shown before loading your activity and notify users some message. Then it might not be possible always. Because, The time Toast is shown with fraction of nano/mili seconds your layout is being loaded as-well.Moreover, scenario is totally different when you are on a real device and on a emulator.This might be the cause you got a flash of your Toast message. Just run it on a real device and you will see the differences.
Hope that helps
I noticed that sometimes Async task does not work properly , Actually its doInBackground() method does not get called , this happens mostly when any service run in background for that activity.
For Example , when music runs in background with service, the Async task does not parse XML in background as its doInBackground does not work that time and the progress Dialog or progressBar kept spinning.
I read in few articles that AsyncTask.THREAD_POOL_EXECUTOR can help in these issues like :
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
new Test().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
new Test().execute();
}
but that did not help in my case. Having the same issue after the above implmentation.
Here I am giving just a bit of my sample code to understand what I am doing::
public class TestAct extends Activity {
ImageButton play,forward,backward;
private ListView mList;
// many more variables
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_layout);
//binding the service here
// start service is called
init();
}
private void init(){
play=(ImageButton)findViewById(R.id.playBtn);
forward=(ImageButton)findViewById(R.id.forward);
backward=(ImageButton)findViewById(R.id.backward);
mList=(ListView)findViewById(R.id.list);
new GetData().execute();
play.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// calling the play() method of ServiceConnection here
}
});
// adding header to Listview
// other code and click listeners
}
class GetData extends AsyncTask<Void, Void, Void>{
#Override
protected void onPreExecute() {
super.onPreExecute();
// starting the progress Bar
// initializing the Arraylist,Maps etc
}
#Override
protected Void doInBackground(Void... params) {
//parsing the XML here
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// stop the ProgressBar
// Updating my UI here
// setting Adapter for ListView
}
}
}
This works fine generally but hangs when Service runs in backgound (I mean when music is playing in back).
I am not getting the exact reason behind this problem of Async task.
Will mannual thread implementation help in this case ...??
Well, I think the problem is because "Service runs in main thread so when it runs, it blocks my AsyncTask to run"... So I think If we can run Service in background thread then that can help . Thats why I tried IntentService for running service in separate thread but I am in doubt... if IntentService can run for indefinite time similar to Service ... and Also IntentService blocks AsyncTask few times.
So I dont't think its 100% perfect solutions for this kind of problem.
Can anyone help me to sort out this problem and understand the complete scenario.
Thanks in advance.
Sometimes you will want more control over your service's lifecycle than what IntentService gives you, in those cases you can just create a thread in the service and run your background code in that. Actually, to be more specific, create a HandlerThread which includes a Looper so you can use the standard android method for communication (messages) between your main thread and the background thread.
Answered here
I think the problem is starting another GetData AsyncTask before the previous one has been finished. Before executing another task make sure that previous one is complete. To do this use following code:
// make sure we don't collide with another pending AsyncTask
if (getDataTask == null || getDataTask.getStatus() == AsyncTask.Status.FINISHED || getDataTask.isCancelled()) {
getDataTask= new GetData();
getDataTask.execute();
}
Also make sure that you have a reference for running tasks. You can use subclass of Application class for doing this while your application is running or override onSaveInstanceState(Bundle outState)
and receive a reference to it in onCreate(Bundle savedInstanceState).
Read all the problem and Answers which has been posted here. correct me if i am wrong your scenario is you are parsing the xml and getting the list of songs and when user select any song you want that to be played with service right?
if the Scenario is correct then we can implement it in the much simpler way.
In the Activity, onResume() method parse the XML file and get the list of songs and update the list view(do not start anything related to service here)
when user click on the song then pass the particular key/string to the service with intent and start the service
In the service's OnStartCommand() method get the identifier and start the song as with normal media APIs
That will actually do the work for you.
Regarding the problem of
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
new Test().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
new Test().execute();
}
This is for different behavior of the AsyncTask on Different version of the Android.
Looking at your code what is being done is in the Activity you are initializing the service hence the service is running in the background without doing anything fruitful.
and when user click on play you are calling play function of service which created problme here.
so to call the function of service from Activity you should right AIDL which you have not mentioned. and if you have wrote so it should be perfect.
but here recommendation is pass the song id to service and it should play from service should not call Service's function in activity.
if you want to update the Song List in the onResume of the activity then you must write AIDL and accomplish the scenario
Hope this will help.
I noticed that sometimes Async task does not work properly , Actually
its doInBackground() method does not get called , this happens mostly
You know that there is a limit of AsyncTasks that can be executed at a time? I had once an issue where a task did't start/work properly and this was because I exceeded that number. Check Android AsyncTask threads limits? for more on that topic.
when any service run in background for that activity. For Example ,
when music runs in background with service, the Async task does not
parse XML in background as its doInBackground does not work that time
and the progress Dialog or progressBar kept spinning.
Have you checked the possibilities of dead locks (in particular, if you're using wait() and notify())?
Well, I think the problem is because "Service runs in main thread so
when it runs, it blocks my AsyncTask to run"... So I think If we can
run Service in background thread then that can help . Thats why I
The things you are going to do in a service should run in an own thread anyway. That way you can be sure that nothing is going to be blocked. If you have something to populate you could use a receiver, for instance.
Hope I could help a bit ...
Here is a hint, How I finally solved my Problem ::
1) I used IntentService instead of Service as Service runs in mainThread while IntentService runs in a separate Thread than mainThread to make sure that my background Service does not effect my current task . Also , I am using AIDL for communication between my UI and background Thread (this was already working for Service , so nothing new in this part).
2) I used painless thread instead of AsyncTask, I interrupt the thread in onDestroy() method to make sure that the Thread does continue indefinitely.
App seems to perform much better than Earlier now.
Hope this will help others too :)
Per the Threading Rules section of the Android Developer AsyncTask document, the AsyncTask has to be created and launched on the UI thread, so if you are launching it from a background thread in a Service, that would account for the faulty behavior.
http://developer.android.com/reference/android/os/AsyncTask.html
You really shouldn't be using AsyncTasks in general :) There is a pretty good explanation here . Think about what will happen if the user rotates the device, while your task is running. The Activity is recreated, but the task runs in the background and holds a reference to the "old" activity. There are ways to get around this, and they are surely still some cases where an AsyncTasks is the correct approach.
However, your really should consider switching to a Loader or (if you feel adventurous) try RoboSpice :)
I have a problem that causes me some problems when a user (or another app, like the phone-application) pushes my application to the background.
My application does following:
A User can enter some information that is supposed to be pushed to a server.
When the user clicks "Send" i open a managed ProgressDialog and start an AsyncTask that performs the server communication.
When server communication is complete the AsyncTask reports back to my Activity where i perform a dismissDialog().
Directly after dismissDialog(), I will show another managed dialog using showDialog() that will inform the user about whether the submission was ok or if it failed.
This all works perfectly without any issues; however, when a call happens to come while the AsyncTask is running I get (seemingly random) one of these results:
The activity holding the managed dialog is dismissed completely and the previous view from the stack is presented when I come back.
The activity holding the managed dialog is still on screen, but it is grayed out without showing a dialog. The only way to fix this is to rotate the phone at which point it shows the "Submission sent"-dialog exactly the way it should and everything is ok after that.
All this happens without any warning messages so I get absolutely no clues as to why Android is behaving this way.
I know a way around this and that is to cancel the AsyncTask (so no dialogs are shown at the end). However, in this very use-case the requirements are that the app has to try to complete the server transaction so that there is as little confusion as possible (i.e. the user wondering if it was really sent or not).
Has anybody else had this issue and knows a way around?
I see recommendations to hold a reference to the asynch task in onRetainNonConfigurationInstance
What to do with AsyncTask in onPause()?
Or implement a bus:
https://github.com/commonsguy/cwac-bus/tree
EDIT: The complexity of your challenge is two fold:
1) saving and restoring state of your app on a kill such as when there is an incoming phone call
https://sites.google.com/site/jalcomputing/home/mac-osx-android-programming-tutorial/saving-instance-state
2) somehow continuing the asyncTask on kill instead of canceling it onPause
https://sites.google.com/site/jalcomputing/home/mac-osx-android-programming-tutorial/asynch
Both of these are significant challenges alone, and trying to fix both at the same time would give me a headache. In fact, I am getting a headache just thinking on it :) One clue is that you say the dialog returns on orientation change. This MAY be due to the fact that using the standard architecture for dialogs, the OS handles saving and restoring the state of dialogs for you on orientation change.
[EDIT] See CommonsWare
#Override
public Object onRetainNonConfigurationInstance() {
task.detach();
return(task);
}
and
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bar=(ProgressBar)findViewById(R.id.progress);
task=(RotationAwareTask)getLastNonConfigurationInstance();
if (task==null) {
task=new RotationAwareTask(this);
task.execute();
}
else {
task.attach(this);
updateProgress(task.getProgress());
if (task.getProgress()>=100) {
markAsDone();
}
}
}
where task is an instance of
static class RotationAwareTask extends AsyncTask<Void, Void, Void> {
I see no reason why this would not work for all types of soft kills, but on a hard kill, well, you get killed. Dead is dead :)
Without looking at your code it is slightly difficult to say what the problem is. However, here is something you could use to help get around the problem. You can override the onPause() method of your Activity.
This is taken directly from the Android Acitivy javadoc:
onPause() is where you deal with the user leaving your activity. Most importantly, any changes made by the user should at this point be committed (usually to the ContentProvider holding the data)