I've written an android app which checks the network status by using a BroadcastReceiver inherited class:
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
Log.d("mylog", "NetworkChangeReceiver Hit");
}
}
which is registered in the manifest file like this:
<receiver
android:name="foo.NetworkChangeReceiver"
android:label="NetworkChangeReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
I needed to handle the internet connection whenever it connects or disconnects. Actually, it works perfectly in normal situations.
But the problem is that when the application is closed manually (by minimizing the app and then closing it by swiping out the app icon in the Recents button menu), it still receives the network status changes. This sometimes causes some exceptions.
Even I have included all the code in receiver function in try/catch block, but still sometimes a toast message containing an error message is shown. This sometimes happen even after some days after the closure of the app.
Please note that the code in the receiver function is more complicated than the code that is shown here and has some access to internal classes and variables.
Your app will still receive events, even if it isn't running. Before you do anything in onReceive(), you can check if the activity is running by:
Option 1: Use a static variable in your activity to check it's state for access from the receiver :
public class YourActivity extends Activity {
public static boolean isRunning = false;
#Overrride
public void onCreate(Bundle savedInstanceState){
isRunning = true;
....
}
//We need receiver to work when app is minimized
/*
#Override
public void onStart() {
super.onStart();
isRunning = true;
}
#Override
public void onStop() {
super.onStop();
isRunning = false;
}
*/
}
And in the receiver:
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
Log.d("mylog", "NetworkChangeReceiver Hit");
if(!YourActivity.isRunning)
return;
}
}
Option 2 : Using the ActivityManager
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
if (isAppForground(context))
return;
}
public boolean isAppForground(Context mContext) {
ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(mContext.getPackageName())) {
return false;
}
}
return true;
}
}
You'll need the permission:
<uses-permission android:name="android.permission.GET_TASKS" />
If you define receivers in your manifest, the app will receive events, even if it is not started.
http://developer.android.com/guide/topics/manifest/receiver-element.html
Broadcast receivers enable applications to receive intents that are broadcast by the system or by other applications, even when other components of the application are not running.
To fix this, just don't define the Receiver in the manifest, but do it programatically in onStart and unregister it again in onStop. The problem with this solution is, that you won't get messages if your app is in the background.
private BroadcastReceiver receiver;
#Overrride
public void onStart(){
super.onStart();
IntentFilter filter = new IntentFilter();
filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
filter.addAction("android.net.wifi.WIFI_STATE_CHANGED");
receiver = new NetworkChangeReceiver();
registerReceiver(receiver, filter);
}
#Override
protected void onStop() {
super.onStop();
//don't forget to unregister the receiver again
unregisterReceiver(receiver);
}
EDIT: onCreate and onDestroy won't work, as onDestroy will not be called in every instance the app is closed (e.g. if it is closed with the task manager)
Solution Found:
I found a perfect solution to my problem. Thanks to the correct answer in Android service crashes after app is swiped out of the recent apps list, I found out that when an app is closed via Recents list, the whole process will be created again and all the static variables will be freshed to their default values, and the onCreate and all other methods will not be called.
So the solution is something like:
public static boolean appStarted = false;
protected void onCreate(Bundle savedInstanceState) {
appStarted = true;
...
}
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
if (!MyActivity.appStarted)
return;
...
}
}
The key is to just keep track of when the app starts, and not when the app is closed (because the closing event of app is not dependable and in some situations doesn't work properly)
Related
I am trying to get actions performed on battery change. For that I have used the following code:
public class BatteryBroadcastReceiver extends
BroadcastReceiver {
DatabaseHelper db;
#Override
public void onReceive(Context context, Intent intent) {
db = new DatabaseHelper(context);
String cont1 = db.usercontact().toString();
String action = intent.getAction();
if (action != null && action.equals(Intent.ACTION_BATTERY_CHANGED)) {
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL,-1);
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE,-1);
int percentage = level * 100 / scale;
if(percentage <= 20){
// doing something like getting location
}
}
}
I have registered my broadcast in my activity:
public class Battery extends AppCompatActivity {
private BatteryBroadcastReceiver batteryReceiver = new BatteryBroadcastReceiver();
private IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_auto_location);
}
#Override
protected void onResume(){
super.onResume();
registerReceiver(batteryReceiver,intentFilter);
}
#Override
protected void onPause(){
unregisterReceiver(batteryReceiver);
super.onPause();
}
This general piece of code is working fine but it is restricting me to just this activity (may be because broadcast is registered in this activity). Like as long as this activity remains open I can perform some task but as I closes it, when battery gets low it perform no task. Now I don't know what to do. I have other activities too in my application and I want it to work even when I am not on this activity. Is there any way that I can register it in manifest so that it could work overall. I have tried doing that but then nothing happens on battery change. Thanks for help in advance :).
It is no longer possible to register for ACTION_BATTERY_CHANGED in the manifest. See https://developer.android.com/reference/android/content/Intent.html#ACTION_BATTERY_CHANGED
If you want to get triggered by this broadcast Intent in all of your activities, you can do this one of 2 ways:
Register and unregister the receiver in each and every one of your activities. You could simplify this by creating a BaseActivity that handles the register and unregister of the BroadcastReceiver and then extending all your activities from BaseActivity.
Register the receiver when your app starts in a custom Application class, or in onCreate() of your first Activity. Don't unregister the receiver. This causes a small memory leak, but I wouldn't worry about it.
I am checking Internet connectivity in my app using BroadcastReceiver and I show an alert dialog if the connection is lost. It works fine. But my problem is that BroadcastReceiver works even if my app is in backgroung. So dialog pops up when internet connection is lost even if user is in some other app. This is totally ruining my app.
Has anyone got any idea how to restrict Broadcast receiver in the app only?
Here is my BroadcastReceiver :
public class ConnectivityChangedReceiver extends BroadcastReceiver{
#Override
public void onReceive( Context context, Intent intent )
{
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE );
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
} else {
try{
Intent i=new Intent(context, InternetDialogActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
} catch(Exception e){
e.printStackTrace();
}
}
}
}
And the activity is:
public class InternetDialogActivity extends Activity implements OnClickListener{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.internet_dialog_box);
getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
Button retryButton = (Button) findViewById(R.id.retryInternetButton);
retryButton.setOnClickListener(this);
}
public boolean checkConnectivity(){
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo!=null && networkInfo.isConnected()) {
finish();
return true;
} else {
Intent intent = getIntent();
finish();
startActivity(intent);
return false;
}
}
#Override
public void onClick(View view) {
switch(view.getId()){
case R.id.retryInternetButton:
try{
checkConnectivity();
} catch(Exception e){
e.printStackTrace();
}
break;
}
}
}
Here is how I declared receiver and activity in manifest:
<receiver android:name="com.lisnx.service.ConnectivityChangedReceiver"
android:label="NetworkConnection">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
<activity android:name="com.lisnx.activity.InternetDialogActivity"
android:configChanges="orientation|keyboardHidden"
android:theme="#android:style/Theme.Dialog" />
I have read that we can restrict BroadcastReceiver to work within the app by not declaring it in the manifest. But I don't know how will receiver work then? Please help me. I am stuck on it badly. Thanx in advance.
A BroadcastReceiver works when the app is in the background because the event that the receiver picks up are sent globally, and each app is registered to listen in on these, regardless of whether or not it is running.
To deal with this, in your BroadcastReceiver's onReceive code, check if your app is in the foreground.
There is one--and only one that I know of--consistently effective method to do this. You need to keep track of your pause/resume actions for your application. Ensure that you check this in every activity.
There is some sample code in this answer (solution #1). In your case, you would want to check MyApplication.isActivityVisible() == true as a validation before doing anything from your BroadcastReceiver.
Have you tried to remove the Intent filter from the manifest and register/unregister it in activity? So you can try to register Intent filter in onStart() and unregister it on onStop() methods. The code goes somethink like this:
static final String ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
IntentFilter filter = new IntentFilter(ACTION);
this.registerReceiver(ConnectivityChangedReceiver, filter);
unregisterReceiver(ConnectivityChangedReceiver);
You should also learn about Activity Lifecycle, if it's not familiar yet.
You should register/unregister your BroadcastReceiver in onPause() and onResume() of each activity. Then you know that the receiver is only "listening" when your app is in the foreground. You can easily do that by creating your own BaseActivity that extends Activity and overrides onPause() and onResume() and registers/unregisters your receiver. Just have all your activities extend BaseActivity and have them call through to super.onResume() and super.onPause() as usual. Here's example code:
public class BaseActivity extends Activity {
// Create an IntentFilter to listen for connectivity change events
static IntentFilter filter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
// Create an instance of our BroadcastReceiver
static ConnectivityChangedReceiver receiver = new ConnectivityChangedReceiver();
#Override
protected void onPause() {
super.onPause();
// Stop listening for connectivity change events
unregisterReceiver(receiver);
}
#Override
protected void onResume() {
super.onResume();
// Listen for connectivity change events
registerReceiver(receiver, filter);
}
}
All your activities should extend BaseActivity and if they need to do anything special in onResume() or onPause() just make sure to call through to super.onXXXXX() like this:
public MyActivity extends BaseActivity {
#Override
protected void onResume() {
super.onResume();
// Here you do whatever you need to do in onResume() of your activity
...
}
#Override
protected void onPause() {
super.onPause();
// Here you do whatever you need to do in onPause() of your activity
...
}
}
I didn't run the code through a compiler so I apologize if there's a typo or I missed something.
I think you will have to make sure that you are not using the receiver when app is in background. For that you will have to use every activities onPause() and onResume() methods.
As far as I know, if Broadcast receiver is registered inside manifest.xml then broadcast receiver exists as long as application exists. Also, Dynamically registered receivers (that means, Register your BroadcastReceiver programmatically) are called on the UI thread. This means that your receivers blocks any UI handling and thus the onReceive() method should be as fast as possible.
However, I will try to discuss information about Broadcast Receiver. But, first should know some information. Firstly, Broadcast receiver is a standalone application component which means it will continue running even when other application component are not running. That's why we unregister broadcast receiver in onPause on the activity. Also, Developer should register this in Activity.onResume() implementation.
Secondly, Developer should not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back in the history stack. I have put that information from BroadcastReceiver documentation.
Another point is that a BroadcastReceiver object is only valid for the duration of the call to onReceive(). As soon as the onReceive() method is finished, your BroadcastReceiver terminates.
Now, how to register your receiver programmatically:
public abstract Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter)
Here, BroadcastReceiver- receiver will be call when any broadcast intent match with filter.
And IntentFilter- Intent specifies which event your receiver should listen to.
Register:
YourConnectionListener receiver;
this.reciever = new YourConnectionListener();
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(this.reciever, filter);
Sent your Broadcast Info:
Intent intent = new Intent();
intent.putExtra("Message", "Your connectivity info has Changed!!");
this.sendBroadcast(intent);
Receiver:
Now, need to receive the Broadcast. Android calls the onReceive() method on all registered broadcast receivers whenever the event occurs. Say you want to be notified whenever the connection is changed.
public class YourConnectionListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent){
// your Code
}
}
onReceive() has two arguments:
context: The Context object you can use to access additional information or to start services or activities.
intent: Intent used to register your receiver. This object contains additional information that you can use in your implementation.
Additionally, Developer should avoid any long-lasting tasks in your BroadcastReceiver. So, In statically and dynamically registered receivers, Developer should do minor tasks in the receiver itself.For any longer tasks you should start a service from within your receiver.
To make a Broadcast Receiver that fires only when you app is running follow the below code.
1. Create your Broadcast Receiver like this:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class InternetStatusNotifier extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//Recieve notification here
}
}
2. Make an activity or fragment where you want the Broadcast Receiver to work like this:
import android.app.Activity;
import android.content.IntentFilter;
import android.os.Bundle;
public class MainActivity extends Activity {
private InternetStatusNotifier mInternetStatusNotifier;
#Override
protected void onCreate(Bundle savedInstanceState) {
mInternetStatusNotifier = new InternetStatusNotifier();
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
registerReceiver(mInternetStatusNotifier, new IntentFilter(
"android.net.conn.CONNECTIVITY_CHANGE"));
super.onResume();
}
#Override
protected void onPause() {
unregisterReceiver(mInternetStatusNotifier);
super.onPause();
}
Note: That is how you use broadcasts receiver in a screen specific manner. Only the screen displaying will receive broadcasts in this way. When you register broadcast using manifest file then they are even received when app is closed
That is the way broadcast receivers work in Android. If you register for a broadcast in the manifest and your app is not running, Android will start a new process to handle the broadcast. It is generally a bad idea to directly show a UI from a broadcast receiver, because this may interrupt other apps. I'm also not convinced that a universal 'connection lost' dialog is a good idea either. This should probably be handled by each activity that uses network access.
As for the original question, you need to disable your receiver when your activity goes in the background (onPause(), etc.) and enable it when you come to the foreground (onResume(), etc). Put enabled=false in your manifest and then use something like this in your code to toggle it as necessary:
public static void toggle(Context context, boolean enable) {
int flag = enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
ComponentName receiver = new ComponentName(context,
ConnectivityMonitor.class);
context.getPackageManager().setComponentEnabledSetting(receiver, flag,
PackageManager.DONT_KILL_APP);
}
A simple way of finding whether the app is in foreground or not
if((mContext.getPackageName().equalsIgnoreCase(
((ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE))
.getRunningTasks(1).get(0).topActivity.getPackageName())))
{
//app is in foreground;
}
I better suggest you to check the internet setting from the application when someone opens it, here is the piece of code how i do it.
public static boolean isNetworkConnected(Context ctx) {
ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni == null) {
return false; // There are no active networks.
} else
return true;
}
I'm using C2DM, my BroadcastReceivers propagate the C2DM events to a local service. the service complete the registration by sending the id to my webserver pus it's responsible for letting the device know about new messages, however if the application (one of the activities) is up we want to send an intent to that activity with the new data so it can be updated, if not than the NotificationManager is used to notify the user.
The issue is, how to know the activity is running ? the Application object is not an option since the Service is part of the application it's obviously going to be present. unregister in the onDesroy of each application is also not an option since it may occur in orientation change...
Any standard way to get it done ?
Solution 1:
You can use ActivityManager for Checking if Activity is Running or not:
public boolean isActivityRunning() {
ActivityManager activityManager = (ActivityManager)Monitor.this.getSystemService (Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> activitys = activityManager.getRunningTasks(Integer.MAX_VALUE);
isActivityFound = false;
for (int i = 0; i < activitys.size(); i++) {
if (activitys.get(i).topActivity.toString().equalsIgnoreCase("ComponentInfo{com.example.testapp/com.example.testapp.Your_Activity_Name}")) {
isActivityFound = true;
}
}
return isActivityFound;
}
need to add the permission to your manifest..
<uses-permission android:name="android.permission.GET_TASKS"/>
Solution 2:
Your can use an static variable in your activity for which you want to check it's running or not and store it some where for access from your service or broadcast receiver as:
static boolean CurrentlyRunning= false;
public void onStart() {
CurrentlyRunning= true; //Store status of Activity somewhere like in shared //preference
}
public void onStop() {
CurrentlyRunning= false;//Store status of Activity somewhere like in shared //preference
}
I hope this was helpful!
The next approach would work well if you want to handle incoming Google Cloud message (C2DM) by your activity (if any is running) or issue a notification if no activities are running.
Register one BroadcastReceiver in the manifest file. This receiver will handle C2D messages whenever application not running. Register another BroadcastReceiver programmatically in your activity. This receiver will handle C2D messages whenever activity is running.
AndoroidManifest.xml
<receiver
android:name=".StaticReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.mypackage" />
</intent-filter>
</receiver>
MyReceiver.java
public class StaticReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Trigger a Notification
}
}
MyActivity.java
public class MyActivity extends ActionBarActivity {
#Override
protected void onResume() {
super.onResume();
final IntentFilter filter = new
IntentFilter("com.google.android.c2dm.intent.RECEIVE");
filter.addCategory("com.mypackage");
filter.setPriority(1);
registerReceiver(dynamicReceiver, filter,
"com.google.android.c2dm.permission.SEND", null);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(dynamicReceiver);
}
private final BroadcastReceiver dynamicReceiver
= new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent) {
// TODO Handle C2DM
// blocks passing broadcast to StaticReceiver instance
abortBroadcast();
}
};
}
Note! To catch broadcasts first, the priority of dynamicReceiver IntentFilter must be higher than priority of StaticReceiver instance IntentFilter (default priority is '0').
PS. It looks like broadcasts issued by Google Cloud Messaging Service are ordered broadcasts. Original idea author: CommonsWare
Copied from here.
you can use a static variable within the activity.
class MyActivity extends Activity {
static boolean active = false;
public void onStart() {
active = true;
}
public void onStop() {
active = false;
}
}
Easiest way to check that whether an Activity is running or not is:
Context context = MyActivity.this;
if (! ((Activity) context).isFinishing()) {
// Activity is running
} else {
// Activity has been finished
}
Note: If activity is not running you should not perform any UI related operation.
I'd like to know what is the best practice/way of programmatically register a broadcast receiver. I want to register specific receivers according to user choice.
As the registration is done through the manifest file, I'm wondering if there's a proper way to achieve this in code.
In your onCreate method you can register a receiver like this:
private BroadcastReceiver receiver;
#Override
public void onCreate(Bundle savedInstanceState){
// your oncreate code should be
IntentFilter filter = new IntentFilter();
filter.addAction("SOME_ACTION");
filter.addAction("SOME_OTHER_ACTION");
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//do something based on the intent's action
}
};
registerReceiver(receiver, filter);
}
Remember to run this in the onDestroy method:
#Override
protected void onDestroy() {
if (receiver != null) {
unregisterReceiver(receiver);
receiver = null;
}
super.onDestroy();
}
One important point that people forget to mention is the life time of the Broadcast Receiver. The difference of programmatically registering it from registering in AndroidManifest.xml is that. In the manifest file, it doesn't depend on application life time. While when programmatically registering it it does depend on the application life time. This means that if you register in AndroidManifest.xml, you can catch the broadcasted intents even when your application is not running.
Edit: The mentioned note is no longer true as of Android 3.1, the Android system excludes all receiver from receiving intents by default if the corresponding application has never been started by the user or if the user explicitly stopped the application via the Android menu (in Manage → Application). https://developer.android.com/about/versions/android-3.1.html
This is an additional security feature as the user can be sure that only the applications he started will receive broadcast intents.
So it can be understood as receivers programmatically registered in Application's onCreate() would have same effect with ones declared in AndroidManifest.xml from Android 3.1 above.
It sounds like you want to control whether components published in your manifest are active, not dynamically register a receiver (via Context.registerReceiver()) while running.
If so, you can use PackageManager.setComponentEnabledSetting() to control whether these components are active:
http://developer.android.com/reference/android/content/pm/PackageManager.html#setComponentEnabledSetting(android.content.ComponentName, int, int)
Note if you are only interested in receiving a broadcast while you are running, it is better to use registerReceiver(). A receiver component is primarily useful for when you need to make sure your app is launched every time the broadcast is sent.
Define a broadcast receiver anywhere in Activity/Fragment like this:
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG," onRecieve"); //do something with intent
}
};
Define IntentFilter in onCreate()
mIntentFilter=new IntentFilter("action_name");
Now register the BroadcastReciever in onResume() and Unregister it in onPause() [because there is no use of broadcast if the activity is paused].
#Override
protected void onResume() {
super.onResume();
registerReceiver(mReceiver, mIntentFilter);
}
#Override
protected void onPause() {
if(mReceiver != null) {
unregisterReceiver(mReceiver);
mReceiver = null;
}
super.onPause();
}
For detail tutorial, have a look at broadcast receiver-two ways to implement.
package com.example.broadcastreceiver;
import android.app.Activity;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
UserDefinedBroadcastReceiver broadCastReceiver = new UserDefinedBroadcastReceiver();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
/**
* This method enables the Broadcast receiver for
* "android.intent.action.TIME_TICK" intent. This intent get
* broadcasted every minute.
*
* #param view
*/
public void registerBroadcastReceiver(View view) {
this.registerReceiver(broadCastReceiver, new IntentFilter(
"android.intent.action.TIME_TICK"));
Toast.makeText(this, "Registered broadcast receiver", Toast.LENGTH_SHORT)
.show();
}
/**
* This method disables the Broadcast receiver
*
* #param view
*/
public void unregisterBroadcastReceiver(View view) {
this.unregisterReceiver(broadCastReceiver);
Toast.makeText(this, "unregistered broadcst receiver", Toast.LENGTH_SHORT)
.show();
}
}
Two choices
1) If you want to read Broadcast only when the Activity is visible
then,
registerReceiver(...) in onStart() and unregisterReceiver(...) in onStop()
2) If you want to read Broadcast even if Activity is in Background
then,
registerReceiver(...) in onCreate(...) and unregisterReceiver(...) in onDestroy()
Bonus:
If you are lazy
If you don't want to write boilerplate code for registering and unregistering a BroadcastReceiver again and again in each Activity then,
Create an abstract Activity
Write boilerplate code in Activity
Leave the implementation as abstract methods
Here is the code snippet:
Abstract Activity
public abstract class BasicActivity extends AppCompatActivity {
private BroadcastReceiver broadcastReceiver;
private IntentFilter filter;
private static final String TAG = "BasicActivity";
/**********************************************************************
* Boilerplate code
**********************************************************************/
#Override
public void onCreate(Bundle sis){
super.onCreate(sis);
broadcastReceiver = getBroadcastReceiver();
filter = getFilter();
}
#Override
public void onStart(){
super.onStart();
register();
}
#Override
public void onStop(){
super.onStop();
unregister();
}
private void register(){
registerReceiver(broadcastReceiver,filter);
}
private void unregister(){
unregisterReceiver(broadcastReceiver);
}
/**********************************************************************
* Abstract methods
**********************************************************************/
public abstract BroadcastReceiver getBroadcastReceiver();
public abstract IntentFilter getFilter();
}
Using this approach you can write more boilerplate code such as
writing common animations, binding to a service, etc.
See full code:
HERE
According to Listening For and Broadcasting Global Messages, and Setting Alarms in Common Tasks and How to Do Them in Android:
If the receiving class is not
registered using in its
manifest, you can dynamically
instantiate and register a receiver by
calling Context.registerReceiver().
Take a look at registerReceiver (BroadcastReceiver receiver, IntentFilter filter) for more info.
It is best practice to always supply the permission when registering the receiver, otherwise you will receive for any application that sends a matching intent. This can allow malicious apps to broadcast to your receiver.
for LocalBroadcastManager
Intent intent = new Intent("any.action.string");
LocalBroadcastManager.getInstance(context).
sendBroadcast(intent);
and register in onResume
LocalBroadcastManager.getInstance(
ActivityName.this).registerReceiver(chatCountBroadcastReceiver, filter);
and Unregister it onStop
LocalBroadcastManager.getInstance(
ActivityName.this).unregisterReceiver(chatCountBroadcastReceiver);
and recieve it ..
mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("mBroadcastReceiver", "onReceive");
}
};
where IntentFilter is
new IntentFilter("any.action.string")
Create a broadcast receiver
[BroadcastReceiver(Enabled = true, Exported = false)]
public class BCReceiver : BroadcastReceiver
{
BCReceiver receiver;
public override void OnReceive(Context context, Intent intent)
{
//Do something here
}
}
From your activity add this code:
LocalBroadcastManager.getInstance(ApplicationContext)
.registerReceiver(receiver, filter);
I'm writing a Widget that will display a countdown timer. I have the widget working the way I want it until I flip the phone from landscape to portrait. My widget does not update and goes to it's initial state at start of the widget until an onupdate is called by my recurring alarm. I would like to call an onupdate manually once the orientation changes to update my widget I've been researching this for a while now and I've found out that I need to use a Service which will monitor the orientation changes and call my onupdate for my widget.
My problem is I can't find a straight answer as to how to use a service to monitor the change. I've seen that with an activity I can add android:configChanges="orientation|keyboardHidden" to the manifest for an activity and use a onConfigurationChanged, but can I do this for a service. If so how? Is there a better way to monitor the orientation change? I've also read on the internet that a service isn't the best way to do this either.
I've seen tutorials for creating orientation listeners but they seem to use depreciated function calls.
Thanks in Advance
Service#onConfigurationChanged(Configuration newConfig) works for me. No need to register Receivers for my opinion. I also did not add any filter to AndroidManifest. Did I miss something in the discussion since nobody suggested this solution? My Service is running on foreground.
Just place inside your service:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//Your handling
}
Please find below an example which does what you ask for, hope this helps.
public class ScreenOrientationListener extends Activity {
private static final String TAG = "ScreenOrientationListener";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
setContentView(R.layout.main);
startService( new Intent(this, MyService.class) );
}
}
and here comes MyService class
public class MyService extends Service {
private static final String TAG = "MyService";
private static final String BCAST_CONFIGCHANGED = "android.intent.action.CONFIGURATION_CHANGED";
private static Context mContext;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Log.d(TAG, "onCreate()");
mContext = this;
IntentFilter filter = new IntentFilter();
filter.addAction(BCAST_CONFIGCHANGED);
this.registerReceiver(mBroadcastReceiver, filter);
}
#Override
public void onDestroy() {
Log.d(TAG, "onDestroy()");
//Unregister receiver to avoid memory leaks
mContext.unregisterReceiver(mBroadcastReceiver);
}
#Override
public void onStart(Intent intent, int startid) {
Log.d(TAG, "onStart()");
}
public BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent myIntent) {
if ( myIntent.getAction().equals( BCAST_CONFIGCHANGED ) ) {
Log.d(TAG, "received->" + BCAST_CONFIGCHANGED);
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
// it's Landscape
Log.d(TAG, "LANDSCAPE");
}
else {
Log.d(TAG, "PORTRAIT");
}
}
}
};
}
and here is the part to define MyService in manifest file
<!-- Services -->
<service android:enabled="true" android:name="com.wareninja.android.external.screenorientationlistener.services.MyService">
<intent-filter>
<action android:name="android.intent.action.CONFIGURATION_CHANGED"/>
</intent-filter>
</service>
You could create a BroadcastReceiver that listens for Intent.ACTION_CONFIGURATION_CHANGED (android.intent.action.CONFIGURATION_CHANGED)
Note that it does say:
You can not receive this through
components declared in manifests, only
by explicitly registering for it with
Context.registerReceiver().
Which means you can't register your reciever in the manifest file. You would have to register it in code.
then get the configuration and check what the orientation is as Floern stated.
I would suggest you use an OrientationEventListener object. It does exactly what you are looking for and it is not deprecated. It's been around since API level 3.