I have an Activity with 2 buttons. A play and a pause button.
When this activity gets in the background, which means when the onStop() method has bean called, this creates a permanent notification that is only destroyed when the activity is resumed.
The notification does provide the play and pause buttons too. How do I call the activity's play() and pause() methods when the notification's buttons are clicked?
I really have no clue on how to address that issue.
I'm using a RemoteViews to construct a custom layout. And I know you can call
setOnClickPendingIntent() to bind an Intent to a view.
big thanks.
Instead of calling activity methods, you can use a service to initialize a media player instance and play or pause by passing intent extras. This way you would have more and easier control over the player.
I followed your advise by writting a Service that receives all input from The Notification. I then use the LocalBroadcastManager to send appropriate message to a BroadcastReceiver, which is responsible for updating the notification. The Activity also has a inner BroadcastReceiver. That way both receivers receive intent from the Service and can update their UIs independently.
Related
For example, I started an activity, there is a button in the activity
And then I start the background service, this service will check whether the target activity is on foreground, then trigger the click event of that button.
Is it possible to do this?
Why would you trigger a click event of an activity rather than notifying the activity about its results? Try to use local broadcasts which are sent from the service to the activity. The activity registers for that broadcast and in its onReceive of the BroadcastReceiver you'll trigger your onClick method or any other method of your choice. The Receiver is registered in onResume and unregistered in onPause to guarantee that the activity is actually visible.
I would not recommend to use a direct dependency on your activity as this might cause IllegalStateExceptions if in any circumstance your activity is not started or visible at all.
I can strongly recommend you to use eventbus concept like "otto by square" in this case.
you will subscribe to event from the activity this will keep to modularity and will let you do this function
What I did:
startService in MainActivity's onCreate().
implement button onBindServiceClicked(View v) in MainActivity. So when the button is clicked, an intent with data will be sent to the service.
However, I found this only work once. When I clicked the button the second time, it seems the onBind() was not invoked.
Do I need to call something like unbindService, so that the onBind() will be invoked many times?
If you want to keep sending data via Intent, you should use Activity.startService(intent) instead. Each time your service will have it's onStartCommand() callback invoked.
As it doesn't appear to be possible to put an EditText in an AppWidget, I would like to open a PopUpWindow with an EditText when I click on it.
I know how to open an Activity from an AppWidget and I also know how open a PopUpWindow from an Activity. I don't, however, know how to open a PopUpWindow from an AppWidget. I've looked into many classes in the javadoc (Intent, RemoteViews, PendingIntent, etc.), but I can't find how to start this PopUpWindow. Any help would be appreciated.
You know that AppWidgetProvider is a BroadcastReceiver.Android Doc says:
A BroadcastReceiver object is only valid for the duration of the call
to onReceive(Context, Intent). Once your code returns from this
function, the system considers the object to be finished and no longer
active.
This has important repercussions to what you can do in an
onReceive(Context, Intent) implementation: anything that requires
asynchronous operation is not available, because you will need to
return from the function to handle the asynchronous operation, but at
that point the BroadcastReceiver is no longer active and thus the
system is free to kill its process before the asynchronous operation
completes.
In particular, you may not show a dialog or bind to a service from
within a BroadcastReceiver. For the former, you should instead use the
NotificationManager API. For the latter, you can use
Context.startService() to send a command to the service.
It seems you have three ways:
Use a service to show popup(see How to display alert diaolog(popup) from backgroung running service?)
Use notification manager(see AlarmManager never calling onRecieve in AlarmReceiver/BroadcastReceiver).
Create an activity whit dialog theme(so it looks like a popup) and display it when user click your AppWidget.
You could have the appWidget open an activity which then shows a dialog fragment, or make the activity look like a dialog using a dialog style.
I have to publish the progress from a background service on the UI continuously on a progress bar. Any ideas on how to go about it. Intents won't work I guess coz they can only send the data once the activity is started. Ant other suggestions?
Update : The progress on the UI happens on a progress Bar
Extend Application, which is created once for entire application.
When Activity starts, store its reference to a field in your Application object. (Note that you can access Application using Activity.getApplication). Set this field to Activity reference or null in onPause/onResume calls.
Then in Service, you have also access to your Application by Service.getApplication. So look if your Activity reference is non-null, meaning that your Activity is shown to user, and update UI as needed in such case, by calling methods on your Activity.
Thanks for the help mice, but since I needed to update progress bars on different activities in my app depending on which one was visible, I found it easier to implement through Broadcast Intents and Recievers and Intent Filters. All I had to do was to Broadcast the progress in my service wrapped up in a bundle via a broadcast Intent (with a custom Intent Filter applied) and register (in onResume()) an inner subclass of BroadcastReciever in the activities which needed the progress (having the same intent filter). One can also unregister these recievers in the onPause() method of the activity to save memory headspace.
I have a Service which tracks the location of the user. Currently, the Service boots when the application starts and stops when the application terminates. Unfortunately, if users keep the application in the background, the Service never stops and drains battery.
I would like the Service to stop when my application is not in the foreground. I was hoping the Application class would let me Override onPause and onResume handlers, but it does not have them. Is there another way I can accomplish this?
I haven't tested this yet, but it looks like if you use Context#bindService() (instead of Context#startService()), the service should stop when no more activities are bound to it. (see Service lifecycle).
Then use onPause()/onResume() in each activity to bind/unbind from the service.
Alternatively, you could add a pair of methods on your service which tell it to start/stop listening for location updates and call it from each activity's onResume()/onPause(). The service would still be running, but the location updates wouldn't be draining the battery.
Reading all the above answers I would suggest Simply add a boolean global flag for each activity & put it in your onResume & onPause & also while launching an Activity Something like this
public void onPause()
{
super.onPause();
activity1IsResumed = true;
}
&same for onResume
& similarly when launching a new Activity
startActivityForResult(myintent ,0);
activity2IsResumed = true;
activity1IsResumed = false;
then in your Service simply check
if(activity1IsResumed || activity2IsResumed || activity3IsResumed)
{
//your logic
}
else
{
//another logic
//or dont run location tracker
}
& you are done!
You should override the onPause and onResume methods on your Activity. If you have multiple activities you may want to have a common base class for them and put the start/stop logic into the base class.
I have not tried this approach but I think you can override the home key of android device by using KeyEvent.KEYCODE_HOME and you can use stopService(Intent) to stop your service and when again application resumes, you can write startService(Intent) in the onResume() method of your Activity.
This way I think your service will only stop when user explicitly presses home button to take application in the background and not when he switches from one activity to another.
What I would suggest is overriding the onPause/onReume methods as others have said. Without knowing more about the flow of your application and interactions between Activities, I can't give much more information beyond guesswork.
If your Activities are persistent, however, my recommendation would be to utilize the Intents better when switching between Activities.
For instance, each Activity should have a boolean "transition" flag. So, when you move from one Activity to the next, you set up an Intent extra:
intent.putExtra("transition",true);
Followed in the receiving Activity by: (in onCreate)
intent.getBooleanExtra("transition",false);
This way, for each Activity that launches, you can know whether it has come from another Activity, or if it has been launched from a home screen launcher. Thus, if it gets a true transition, then onPause should NOT stop the service--that means you will be returning to the previous Activity after it returns. If it receives no "transition" extra, or a false transition, then you can safely assume there is no Activity underneath it waiting to take over for the current one.
On the first Activity, you will simply need to stop the service if you are switching to another Activity, which you should be able to figure out programmatically if one Activity is started from another.
It sounds like the real problem is how to only stop the service when you go to an activity that isn't one of your own? One way would be to in your onPause method to stop the activity. Do this for all your activities. Then override your startActivity method. And in here do a conditional test to confirm that you are purposefully navigating to one of your own. If your are set a flag to true.
Now go back to your on pause overridden method. And only stop your service if the flag is not equal to true. Set the flag to false.
All events that navigate away will close your service. Navigating to your own will leave it intact.
Do the overriding in a base class that all your activities extend.
Writeen in my andolroid. Will post ezaple later.
Try using the Bound Services technique to accomplish this.
Bound Services | Android Developers
You can use bound services in a way such that the service will stop when no activities are bound to it. This way, when the app is not in the foreground, the service will not be running. When the user brings the app back to the foreground, the Activity will bind to the service and the service will resume.
Create methods registerActivity() and unRegisterActivity() in your Application object and implement first method in all you acts onResume() and second in acts onPause().
First method add activity to List<Activity> instance in your app object, unRegisterActivity() checks size of list in every call if==0 stopService();.