I have a custom Chronometer which extends TextView and works as a stopwatch. The Activity that uses this Chronometer is listening for broadcasts from a Service. In this broadcast the Service tells the Activity (and thus the Chronometer) to stop counting. This works fine when keeping the application on foreground.
However, when the Activity is not active (like the user presses the home button), the Activity doesn't get the broadcast, and the Chronometer keeps counting. So when I open the Activity again, the Chronometer is still counting up, when it shouldn't be.
Who can provide me with a solution for this?
Note: the Service does not have any knowledge of the Activity nor the Chronometer. It just sends a broadcast "Hey, I'm done with whatever I was doing!".
Your service should be called with startForeground(int id, Notification notification);
See why...
By the way, your BroadcastReceiver shouldn't be unregistered within your activity. Add it to the manifest with a intent filter COUNTDOWN_STOP or whatever, to achieve this.
Related
My question is about: "when will my postbox be noticed by the postman", not "when will I be able to read any letters"?
I have an Activity which allows the user to edit a list. As soon as the user commits the edit, an IntentService is started which in turn calls a database helper to change the database entries as required.
As soon as the database is updated successfully (nothing crashed until then), the database helper writes "ok" to SharedPreferences and returns to the IntentService. The IntentService sends a message to a BroadcastReceiver which now causes the list to be reloaded from db with the current data.
The BroadcastReceiver is an inner class of the Activity and it is registered dynamically in onCreate():
mReceiver = new MyMessageReceiver();
IntentFilter iFilter = new IntentFilter();
iFilter.addAction("com.example.mycoolapp.LOCALINTENT");
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, iFilter);
If the user stayed in my Activity until the list could be reloaded, there would be no problem at all. But imagine the user moving around and somehow causing an orientation change... that's why I have the "ok" in SharedPeferences:
In onCreate(), after registering the receiver, I check whether there is an action pending:
If the database was updated successfully, I can load the data and just set a flag for my receiver to ignore the next message. Which will come, as the IntentService was configured with setIntentRedelivery(true).
If I find that the database is not yet updated, I decide to wait for the broadcast from the IntentService.
The one thing I'm extremely uncertain of is the following:
From which moment on will the system consider my receiver to be "up and running"? I know that onReceive() can only be called after onCreate() is finished.
Is it possible that while onCreate() is being executed, the IntentService fires the local Broadcast ("too soon") and my receiver will never get it?
Then that list would never be refreshed until the user left the Activity (which is quite likely) and returned once more (then not so likely).
The Broadcast Receiver is not registered in the Activity but in the main application thread. The registerReceiver method is defined in the Context class.
That means that your Broadcast receiver will remain registered until you un-register it or your application is destroyed (ie. not having the receiver in a Service)
Check the documentation
From which moment on will the system consider my receiver to be "up
and running"? I know that onReceive() can only be called after
onCreate() is finished.
From the moment registerReceiver() returns
Is it possible that while onCreate() is being executed, the
IntentService fires the local Broadcast ("too soon") and my receiver
will never get it?
You can avoid this by registering the receiver in the onCreate method of a class that extendsApplication. That's how you can make sure that the broadcast receiver is the first thing done.
I'm very new to Android and I need a little assistance here.
I have an activity and a broadcast receiver.
Broadcast receiver should listen SMS Intents and:
if Activity is visible and interacting - SMS should appear in activity
if no - broadcast receiver should create notification with SMS, so if user click on that notification, the activity will be shown
So, i read a lot of articles about broadcasts and i can implement one of these variant(1 - as a inner broadcastreceiver class and 2 - as global broadcast receiver declared in manifest) , but how i can have both? Could you please propose some idea?
Ok, so in that case i post my own solution.
I declare two broadcast receiver: one, declared in Manifest, and doing post to tray notification, and second - declared as an inner class of main activity and doing post to activity components. Also i have subclass of Application class to track main activity state (i.e. visible or not). And so global broadcast receiver post any notifications only if it see that activity is hide right now.
I think its reasonably solution.
I don't know if this is possible, but I would like to do the next:
Imagine an app with 2 activities: MenuActivity and OtherPurposeActivity.
So, on the onCreate method of Menu I had run the Service. In the same Activity (Menu), I can easily "connect"(Edit: communicate) with this Service with no problems.
Then, I click the only button there is on MenuActivity, which starts OtherPurposeActivity. Here comes the question:
How can I connect to the Service I had run on MenuActivity? Is it possible? (I hadn't called stopService).
Thanks in advance.
Edit: Code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
/* Execute service */
Log.d("SERVICE", "Launching service");
Intent msgIntent = new Intent(MenuActivity.this, ServerProcessingService.class);
msgIntent.setAction(ServerProcessingService.ACTION_STATUS);
startService(msgIntent);
/* Connection to the IntentService */
IntentFilter filter = new IntentFilter();
filter.addAction(ServerProcessingService.ACTION_STATUS);
//filter.addAction(ServerProcessingService.ACTION_CONTROL);
rcv = new ProgressReceiver();
registerReceiver(rcv, filter);
}
So I can handle the communication with the ProgressReceiver class. But, what if I open another activity, and this service still running? Can I access to it?
How can I connect to the Service I had run on MenuActivity?
Another activity that wants to communicate with the service can use exactly the same method as MenuActivity. startService() will only start the service if it is not already running, and then send the intent to onStartCommand() in all cases, so it is all right to call start service from multiple activities.
As a commenter pointed out, if your activity requires ongoing communication with a service, you should bind to it.
Is it possible? (I hadn't called stopService).
An IntentService will stop itself if it has no work to do, so it doesn't matter that you did not stop it explicitly. If the service needs to continue running, don't use an intent service.
To be on the same page I will describe briefly how I understood your dilemma.
You have an IntentService perfroming some operation which provides at the end some results. You are starting this process in one activity(asynchronously of course) and switch immediately to another one. Now, you are not sure whether service will finish the work before you switch to second Activity and result will be lost.
Basically, approach with BroadcastReceiver would be a good choice but if you won't register on time the data will be lost and service will end it's work. You could let the service to store the result before it ends, in DB, file or even in memory(depending on data type). When your second Activity start you can check if there is data waiting for you, if not you can wait for BroadcastReceiver to deliver it.
You could also use Otto library which is far more advanced solution than BroadcastReceiver. It allows to return to registered observer(Activity) the last result and what is more important it will allow your service to check if any observer received the message. If not you could only then store last result.
I have managed to get an Activity to start from my onReceive() methdod, but I really need to do a startActivityForResult();.
Is there any way I could do this?
On a side note, how would I make my app become a 'camera' app, as in it would appear when an app started the intent to take a picture?
The important thing to know about broadcast receivers is that you should not add long running processes in it, because after something like 5 seconds your app will crash.
The best thing to do in your case is to intent to other Activity from your broadcast receiver, and from that activity use startActivityForResult(), get the picture and continue from there...
startActivityForResult can only be called from an Activity since it is defined in the Activity class and require instance of activity.
You can only call startAcivity() from broadcast receiver since in onRecieve() you only have access to generic context object and it does not have startActivityForResult method defined in the class..
I am implementing a music player. The notifications allow the user to pause or skip a song.
I use
Intent i = new Intent("com.package.app");
mExpandedView.setOnClickPendingIntent(R.id.next_song, PendingIntent.getBroadcast(this, 0, i, 0));
In order to transmit this click to the MusicService that hosts the MediaPlayer and all the associated methods. I would like to directly call a method part of this service (playNextSong() for example) but getService() seems to only allow me to launch a new service, not to call a method in the service, or get some data. I don't even need to launch the service, since the music is playing, it is already running.
So is there a way to do this that I am not aware of ?, or is :
Notification broadcasts to BroadcastReceiver, then BroadcastReceiver broadcasts to the service the recommended way do accomplish this action ?
It looks like a convoluted way to do something simple...
Create PendingIntent for notification as broadcast message, custom one (use your own string like com.my.custom.broadcast.message.action). Create and register in AndroidManifest new broadcast receiver that will be fired by this custom action. OnReceive method of the Broadcast receiver, start your service with custom arguments/action or whatever, based on class of Service and context arguments passed into onReceive method.
Probably you can try to directly start service by creating PendingIntent for that, but I think it is better do it through middle-step: BroadcastReceiver
From the Notification you can start an Activity. That activity would do "bindService" and call the appropriate method in the service, then finish(). The activity doesn't need to have a UI, so the user won't see it. But that's even more code than a Broadcastreceiver.