I have a application that has just two activities, the main activity and a PreferenceActivity. When there is a change in states (Aeroplane mode being turned on or off, the GPS being turned on and off, etc ), I want to update both activities.
I need to update some variables and the UI only when the app is active so I guess it is better to register the receivers in code rather than in the application manifest.
As I dont want to replicate code in each activity, I tried putting the BroadcastReceiver in its own class. However then I find I am not able to register the BroadcastReceiver. Is there a way around this problem?
Thankyou, Mel
public class melsBigListener {
IntentFilter intentFilter = new IntentFilter("android.intent.action.SERVICE_STATE");
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//TO DO Update both my main activity and the preference activity
//TO DO deal with different intents via switch statement...
}
};
//registering as receiver(like below) can not work
//registerReceiver(receiver, intentFilter);}
Relevant post:RegisterBroadcastReceiver in Manifest.xml setting or by implement source code
registerReceiver(receiver, intentFilter); should be in some method.
melsBigListener should extends activity or you need to pass Activity Context to this class and use it for registerReceiver.
Instead of doing this silly stuff it is better to write register receiver in menifest file.
I suggest registering the receiver in the manifest and use it to alter variables stored in a preferences file (whether the app is running or not) and then query the preferences for state when needed.
But you could extend Application and register the receiver in code in the Application.onCreate() method.
BroadcastReceivers should work as an extended class that is registered to the phone using the manifest file. I'm not too sure how it will work as an instantiated class inside an activity. judging by your code so far, the intent will never even be received by the Activity and your BigListener class because the intent filter was never declared in the manifest.
To solve your problem:
1. create a myBroadcastReceiver, extending from BroadcastReceiver, declaring the necessary intents in the manifest
2. create a myApplication, extending from Application
3. use your Activities' onCreate, onDestroy, onStartCmd, onPause etc to manage the "only when the app is active" part, by toggling a variable in myApplication.
4. use myBroadcastReceiver to read off the variable in (3) whenever the intent is received, to decide if you "need to update some variables" and update accordingly. Since these variables are shared by your 2 Activities, the variables should be put inside the myApplication class
Related
Is it possible to send an intent from a service to an Application class? Not Activity?
I wouldn't know what activity would be running at a particular time, so I am adding a boolean flag in the activity class that detects the activity and sends the appropriate data based on the broadcast received.
If your Service is active, then your Application class is active as well.
Otherwise you wouldn't be able to use getApplicationContext().
Although I'm skeptic about a service that runs forever there is a very clean way to make the Service communicate with a certain Activity, should the last one be currently active.
Such clean way is called LocalBroadcastManager.
The Activity meant to receive the data should register a BroadcastReceiver in onResume() and unregister it in onPause().
You instantiate your BroadcastReceiver in your Activity's onCreate()
this.localBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Do what you have to do here if you receive data from the Service.
}
}
You create a Filter so your Activity only listens to a certain type of signals.
private IntentFilter notifIntentFilter new IntentFilter("com.you.yourapp.MY_SIGNAL");
in onResume()
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, notifIntentFilter);
in onPause()
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
Now whenever you want to send data to your Activity, your Service can call:
final Intent intent = new Intent();
intent.setAction("com.you.yourapp.MY_SIGNAL");
// put your data in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
If your Activity is awake, it will respond to the signal. Otherwise, if it's in the background, or it is not instantiated it won't.
You can apply this pattern to as many Activities as you wish.
Still, I have never used this inside the Application class. But you can try to register your receiver there. It might work, since if the Application class is destroyed, the BroadcastReceiver is destroyed too and thus probably unregistered as well.
The point is, if your Application gets destroyed, your Service will be killed as well. Unless you launched it in another process. But then it will have it's own instance of Application; and this is a complex thing you probably do not want to get into details now...
Important: since the Application class is not tied to any UI component, you can do whatever you need directly inside your service. If you need to manipulate the UI, then the pattern described above will work for you.
Please read about new Android's background limitations.
Edit:
Oh yeah right, if you need your Service to call a function declared in your Application class, you can just do
((MyApplication) getApplication()).myFunctionToHandleData(Intent intent);
I didn't really understand your question though, but either of the methods described above should work for you.
I have a BroadcastReceiver, and the onReceive is called from two different postExecute methods in two different asyncTasks, in two different Activities.
I have a third activity that is running all the time called HomeActivity, and I want to publish some text to the HomeActivity's UI from the onReceive method.
Is it possible? I know that the context parameter is the context of the activity who raised the onReceive, but I want to access the HomeActivity's UI.
Here is the code
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// here I want to publish some text to the HomeActivity
}
}
any ideas? thanks in advance
You want to change text in your running activity based on what you receive in the onReceive of the BroadcastReceiver? Right? One way is that you can use LocalBroadcast. See LocalBroadcast Manager.
For how to implement is, there is a great example on how to use LocalBroadcastManager?.
LocalBroadcast Manager is a helper to register for and send broadcasts of Intents to local objects within your process. The data you are broadcasting won't leave your app, so don't need to worry about leaking private data.`
Your HomeActivity can registers for this local broadcast. From the MyBroadcastReceiver you send a LocalBroadcast from within the onReceive (saying that hey, I received a message. Do you want to do something now activity). Then inside your Activity you can listen to the broadcast. This way if the activity is in the forefront/is active, it will receive the broadcast otherwise it won't. So, whenever you receive that local broadcast, you may change the text etc, if activity is open.
I am new in Android so I hope you can excuse my ignorance
I made an activity to control some bluetooth devices with my telephone, now that everything is working I would like to generate a new class from this activity, a class to take care of all bluetooth communication.
I have some questions:
First: In my activty I employed one broadcast receiver to listen to some actions of the Bluetooth Adapter like STATE_ON, BOND_BONDED... Using this actions I update my views, I call some methods and so on.
So, it is possible to keep listening to this broadcast receiver inside my class and then send the changes to my main activity to update the views and so on?
Second: I really need to send information from my bluetooth class to my main activity, information that I read from my devices, information from the broadcast receiver... so, which is the best way to pass information between a class and the main activity?
Well, thanks a lot for your help :)
The onReceive() method of your BroadcastReceiver is called from the main thread:
"This method is always called within the main thread of its process" (http://developer.android.com/reference/android/content/BroadcastReceiver.html#onReceive(android.content.Context, android.content.Intent)).
That means you can update your ui from the onReceive() method. All you need to do is use a local class like so:
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// update the ui
}
};
Register this receiver programmatically (instead of defining it in the manifest) and you're good to go:
Context.registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter)
I have an application that get/send data from/to a remote DB on internet.
I need to get my application working in background mode, then i supose that i have to put all the send/get remote data in a service.....
but.... How can this service change values of variables and UI textfields of my activities?
i can't find any information about this, all the tutorials i am finding are of simple services that doesn't do something like that
can someone explain me how to do it please?
Use a BroadcastReceiver
In your Activity place the following code:
private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
#Override
public void onReceive(Context ctxt, Intent i) {
// do stuff to the UI
}
};
Register the receiver in your onResume():
registerReceiver(onBroadcast, new IntentFilter("mymessage"));
Be sure to unregister in onPause():
unregisterReceiver(onBroadcast);
In your Service, you can post the message to the Application, which will be heard by your Activity:
getApplicationContext().sendBroadcast(new Intent("mymessage"));
If you need to, you can add data to the Intent's bundle to pass to your Activity as well.
my suggestion to you is, create a handler for the UI part which updates the text field or UI components.
Secondly, have notifications from the service to the activity by way of interface class.
I currently have a Service in Android that is a sample VOIP client so it listens out for SIP messages and if it recieves one it starts up an Activity screen with UI components.
Then the following SIP messages determine what the Activity is to display on the screen.
For example if its an incoming call it will display Answer or Reject or an outgoing call it will show a dialling screen.
At the minute I use Intents to let the Activity know what state it should display.
An example is as follows:
Intent i = new Intent();
i.setAction(SIPEngine.SIP_TRYING_INTENT);
i.putExtra("com.net.INCOMING", true);
sendBroadcast(i);
Intent x = new Intent();
x.setAction(CallManager.SIP_INCOMING_CALL_INTENT);
sendBroadcast(x);
Log.d("INTENT SENT", "INTENT SENT INCOMING CALL AFTER PROCESSINVITE");
So the activity will have a broadcast reciever registered for these intents and will switch its state according to the last intent it received.
Sample code as follows:
SipCallListener = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(SIPEngine.SIP_RINGING_INTENT.equals(action)){
Log.d("cda ", "Got RINGING action SIPENGINE");
ringingSetup();
}
if(CallManager.SIP_INCOMING_CALL_INTENT.equals(action)){
Log.d("cda ", "Got PHONE RINGING action");
incomingCallSetup();
}
}
};
IntentFilter filter = new IntentFilter(CallManager.SIP_INCOMING_CALL_INTENT);
filter.addAction(CallManager.SIP_RINGING_CALL_INTENT);
registerReceiver(SipCallListener, filter);
This works however it seems like it is not very efficient, the Intents will get broadcast system wide and Intents having to fire for different states seems like it could become inefficient the more I have to include as well as adding complexity.
So I was wondering if there is a different more efficient and cleaner way to do this?
Is there a way to keep Intents broadcasting only inside an application?
Would callbacks be a better idea? If so why and in what way should they be implemented?
UPDATE 2015:
This question/answer still gets a little bit of activity, but it is over 5 yrs old and things have changed quite a bit. 5 years ago, the answer below was how I would have handled it. Later I wrote a very lightweight dependency injection solution that I was using for a while (which I mentioned in the comments). Nowadays, I would answer this question using Dagger and RxAndroid. Dagger to inject a "mediator" class into both the Service and all Activities that need to be notified, the Service would push the status update to the mediator class, and the mediator class would expose an observable for the activities to consume the status update (in place of the OP's broadcast receiver).
Original answer
I usually subclass Application and let my in-app communication go through this class (or have a mediator owned by the Application do the work...regardless, the Application being the entry point for the service to communicate with). I have a bound service that needs to update the UI as well (much simpler than yours, but the same idea) and it basically tells the app its new state and the app can then pass this information along in one way or another to the currently active activity. You can also maintain a pointer to the currently active activity (if there is more than one), and make decisions whether or not to simply update the current activity, broadcast the intent to launch a different activity, ignore the message, etc. I would also subclass Activity and have your new activity base class tell the Application that it is currently the active one in onResume and that it is being paused in onPause (for cases where your service is running in the background and the activities are all paused).
EDIT:
In response to the comment, here's more specifics.
Your application currently consists of Activity-derived and Service-derived classes for the most part. Inherently, you get functionality from an instance of the android.app.Application class. This is declared in your manifest (by default) with the following line:
<application android:icon="#drawable/icon" android:label="#string/app_name">
The application element in your manifest doesn't use the android:name attribute, so it just creates an instance of the default android.app.Application class to represent your global application context.
In my apps, I create a subclass of Application (ApplicationEx, for example) and I tell my app through the manifest that this is the class to instantiate as MY global application context. For example:
<application
android:name="com.mycompany.myapp.app.ApplicationEx"
android:icon="#drawable/app_icon"
android:label="#string/app_name">
I can now add methods to ApplicationEx for activities and services to use to communicate. There is always a single instance of your global application context, so this is your starting point if anything needs to be global for your app.
A second piece of this is that instead of deriving my services and activities from Service and Activity, I create a subclass of each with a getAppContext method that casts the return value of getApplicationContext (which exists already in both of these classes because they derive from Context) to my ApplicationEx class.
So........
All that being said, you add a CurrentActivity property to your ApplicationEx class of type Activity (or ActivityBase if you subclass it as I do). In ActivityBase's onResume method, you pass yourself to ApplicationEx for it to set CurrentActivity to that activity. Now, you can expose methods on ApplicationEx to pass information directly to the current activity instead of relying on the Intent mechanisms.
That's about as clear as I can make it
You can send broadcast intents just to your own application and not system wide with LocalBroadcastManager:
Helper to register for and send broadcasts of Intents to local objects within your process. This is has a number of advantages over sending global broadcasts with sendBroadcast(Intent):
You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.
It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes they can exploit.
It is more efficient than sending a global broadcast through the system.
However, I'd still recommend going with the Service approach and locally binding and talking through Handler when necessary to update UI components for efficiency.