Implement Broadcast receiver inside a Service - android

I want to check Internet connection throughout the run time of my Android application. I tried using services but seems like it is not the best option. Is there any possible way for me to implement a broadcast receiver with in a service? Or do I have to give up the service and use broadcast receivers alone?

I will show you how to create SMS receiver in a service:
public class MyService extends Service {
#Override
public void onCreate() {
BwlLog.begin(TAG);
super.onCreate();
SMSreceiver mSmsReceiver = new SMSreceiver();
IntentFilter filter = new IntentFilter();
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
filter.addAction(SMS_RECEIVE_ACTION); // SMS
filter.addAction(WAP_PUSH_RECEIVED_ACTION); // MMS
this.registerReceiver(mSmsReceiver, filter);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
/**
* This class used to monitor SMS
*/
class SMSreceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (TextUtils.equals(intent.getAction(), SMS_RECEIVE_ACTION)) {
//handle sms receive
}
}
}

It wouldn't be wise to check for the connectivity every second. Alternatively you can listen to the action (ConnectivityManager.CONNECTIVITY_ACTION) and identify if you are connected to an active network or not.
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
Additionally you can check the network Type that is currently active(Type_WIFI, Type_MOBILE)
This way, you don't need a service that keeps checking the connectivity every second.

You need not to use Service or BroadCastReceiver for this purpose. Just check Connection status everyTime you need to ping the server.
you can write a method which checks this and returns a boolean(true/false) according to connection status.
Below method does the same.
public static boolean isNetworkAvailable(Context mContext) {
try {
final ConnectivityManager conn_manager = (ConnectivityManager) mContext
.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo network_info = conn_manager
.getActiveNetworkInfo();
if (network_info != null && network_info.isConnected()) {
if (network_info.getType() == ConnectivityManager.TYPE_WIFI)
return true;
else if (network_info.getType() == ConnectivityManager.TYPE_MOBILE)
return true;
}
} catch (Exception e) {
// TODO: handle exception
}
return false;
}

Related

Handle Connection state at boot of device in android

I am making dynamic Register Receiver for Listening connection of internet in android 7.1 and it is starting correctly When internet connection is changed, I handled in OnReceive() method in NetworkChngeReceiver but When I boot device I can't handle connection of internet, my application is started at startup When device is booted, how can I listen connection of internet at boot time of device?
private BroadcastReceiver mNetworkReceiver;
#Override
protected void onCreate((Bundle savedInstanceState)){
mNetworkReceiver = new NetworkChangeReceiver(context, this);
}
#Override
public void onResume() {
super.onResume();
// Register mMessageReceiver to receive messages.
registerReceiver(mNetworkReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
public NetworkChangeReceiver(Context context,Activity a){
try {
c = context;
activity = a;
wifiScanReceiver = new WifiScanReceiver(context);
wifiManager = (WifiManager) c.getSystemService(Context.WIFI_SERVICE);
}catch (Exception e){
e.printStackTrace();
}
}
#Override
public void onReceive(Context context, Intent intent)
{}
}
When device booting there won't be happening any change of network connection status so won't trigger NetworkChangeReceiver. We can get a connection status by ConnectivityManager.

Getting notified about change in state of WiFi on android device?

I am aiming to build a android app which record everything going on with devices WiFi adapter. For example WiFi being turned on/off, device getting connected/moving out of range of a WiFi router, etc.
My app should be able to record these events as soon as the device is turned on. Clearing the app from RECENTS should not affect the ability of the app to record these events.
I have gone through BroadcastReceiver. It gets tied to the life cycle of the app and hence will not record the events once app gets cleared from RECENTS.
public class MainActivity extends Activity {
BroadcastReceiver mybroadcastReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mybroadcastReceiver = new WifiBroadcastReceiver(this);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
registerReceiver(mybroadcastReceiver, intentFilter);
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mybroadcastReceiver);
}
}
public class WifiBroadcastReceiver extends BroadcastReceiver {
final String TAG = "WifiBroadcastReceiver";
final String desiredMacAddress = "02:17:1c:96:42:fa";
Activity activity;
WifiBroadcastReceiver(Activity activity) {
this.activity = activity;
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
SupplicantState state = intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
if (SupplicantState.isValidState(state) && state == SupplicantState.COMPLETED)
checkConnectedToDesiredWifi();
}
}
/** Detect you are connected to a specific network. */
private void checkConnectedToDesiredWifi() {
WifiManager myWifiManager = (WifiManager)activity.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = myWifiManager.getConnectionInfo();
if (wifiInfo != null) {
// get current router MAC address
String bssid = wifiInfo.getBSSID();
if (desiredMacAddress.equals(bssid))
Log.d(TAG, "Connected to " + bssid + " i.e., desiredMacAddress");
else
Log.d(TAG, "Connected to " + bssid + " not " + desiredMacAddress);
}
}
}
One solution could be to run the BroadcastReceiver from a Service that doesn't depend on the lifecycle of any Activity.
1) Declare the network state permission usage in the manifest
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
1) Create a Service class
public class WifiService extends Service {
private BroadcastReceiver mReceiver;
#Nullable
#Override
public IBinder onBind(Intent intent) {
// When creating the service, register a broadcast receiver
// to listen for network state changes
IntentFilter filter = new IntentFilter();
filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
mReceiver = new WifiReceiver();
registerReceiver(mReceiver, filter);
return null;
}
#Override
public boolean onUnbind(Intent intent) {
// Unregister the receiver when unbinding the service
unregisterReceiver(mReceiver);
mReceiver = null;
return super.onUnbind(intent);
}
}
2) Create a BroadcastReceiver
public class WifiReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
boolean isConnected = networkInfo != null &&
networkInfo.isConnectedOrConnecting();
if (isConnected) {
switch (networkInfo.getType()) {
case ConnectivityManager.TYPE_WIFI:
// Connected via wifi
checkConnectedToDesiredWifi();
break;
case ConnectivityManager.TYPE_ETHERNET:
// Connected via ethernet
break;
case ConnectivityManager.TYPE_MOBILE:
// Connected via mobile data
break;
}
}
}
private void checkConnectedToDesiredWifi() {
// ...
}
}
3) Declare the service in the manifest
<service android:name=".receivers.WifiService"
android:stopWithTask="false"
android:enabled="true"/>

How to check if a receiver is registered or not? [duplicate]

I need to check if my registered receiver is still registered if not how do i check it any methods?
There is no API function to check if a receiver is registered. The workaround is to put your code in a try catch block as done below.
try {
//Register or UnRegister your broadcast receiver here
} catch(IllegalArgumentException e) {
e.printStackTrace();
}
I am not sure the API provides directly an API, if you consider this thread:
I was wondering the same thing.
In my case I have a BroadcastReceiver implementation that calls
Context#unregisterReceiver(BroadcastReceiver) passing itself as the argument after handling the Intent that it receives.
There is a small chance that the receiver's onReceive(Context, Intent) method is called
more than once, since it is registered with multiple IntentFilters, creating the potential for an IllegalArgumentException being thrown from Context#unregisterReceiver(BroadcastReceiver).
In my case, I can store a private synchronized member to check before calling Context#unregisterReceiver(BroadcastReceiver), but it would be
much cleaner if the API provided a check method.
simplest solution
in receiver:
public class MyReceiver extends BroadcastReceiver {
public boolean isRegistered;
/**
* register receiver
* #param context - Context
* #param filter - Intent Filter
* #return see Context.registerReceiver(BroadcastReceiver,IntentFilter)
*/
public Intent register(Context context, IntentFilter filter) {
try {
// ceph3us note:
// here I propose to create
// a isRegistered(Contex) method
// as you can register receiver on different context
// so you need to match against the same one :)
// example by storing a list of weak references
// see LoadedApk.class - receiver dispatcher
// its and ArrayMap there for example
return !isRegistered
? context.registerReceiver(this, filter)
: null;
} finally {
isRegistered = true;
}
}
/**
* unregister received
* #param context - context
* #return true if was registered else false
*/
public boolean unregister(Context context) {
// additional work match on context before unregister
// eg store weak ref in register then compare in unregister
// if match same instance
return isRegistered
&& unregisterInternal(context);
}
private boolean unregisterInternal(Context context) {
context.unregisterReceiver(this);
isRegistered = false;
return true;
}
// rest implementation here
// or make this an abstract class as template :)
...
}
in code:
MyReceiver myReceiver = new MyReceiver();
myReceiver.register(Context, IntentFilter); // register
myReceiver.unregister(Context); // unregister
ad 1
-- in reply to:
This really isn't that elegant because you have to remember to set the
isRegistered flag after you register. – Stealth Rabbi
-- "more ellegant way" added method in receiver to register and set flag
this won't work If you restart the device or if your app got killed by
OS. – amin 6 hours ago
#amin - see lifetime of in code (not system registered by manifest entry) registered receiver :)
I am using this solution
public class ReceiverManager {
private WeakReference<Context> cReference;
private static List<BroadcastReceiver> receivers = new ArrayList<BroadcastReceiver>();
private static ReceiverManager ref;
private ReceiverManager(Context context) {
cReference = new WeakReference<>(context);
}
public static synchronized ReceiverManager init(Context context) {
if (ref == null) ref = new ReceiverManager(context);
return ref;
}
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter intentFilter) {
receivers.add(receiver);
Intent intent = cReference.get().registerReceiver(receiver, intentFilter);
Log.i(getClass().getSimpleName(), "registered receiver: " + receiver + " with filter: " + intentFilter);
Log.i(getClass().getSimpleName(), "receiver Intent: " + intent);
return intent;
}
public boolean isReceiverRegistered(BroadcastReceiver receiver) {
boolean registered = receivers.contains(receiver);
Log.i(getClass().getSimpleName(), "is receiver " + receiver + " registered? " + registered);
return registered;
}
public void unregisterReceiver(BroadcastReceiver receiver) {
if (isReceiverRegistered(receiver)) {
receivers.remove(receiver);
cReference.get().unregisterReceiver(receiver);
Log.i(getClass().getSimpleName(), "unregistered receiver: " + receiver);
}
}
}
You have several options
You can put a flag into your class or activity. Put a boolean variable into your class and look at this flag to know if you have the Receiver registered.
Create a class that extends the Receiver and there you can use:
Singleton pattern for only have one instance of this class in your project.
Implement the methods for know if the Receiver is register.
You have to use try/catch:
try {
if (receiver!=null) {
Activity.this.unregisterReceiver(receiver);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
You can do it easy....
1) create a boolean variable ...
private boolean bolBroacastRegistred;
2) When you register your Broadcast Receiver, set it to TRUE
...
bolBroacastRegistred = true;
this.registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
....
3) In the onPause() do it...
if (bolBroacastRegistred) {
this.unregisterReceiver(mReceiver);
bolBroacastRegistred = false
}
Just it, and now, you will not receive more exception error message on onPause().
Tip1: Always use the unregisterReceiver() in onPause() not in onDestroy()
Tip2: Dont forget to set the bolBroadcastRegistred variable to FALSE when run the unregisterReceive()
Success!
If you put this on onDestroy or onStop method. I think that when the activity has been created again the MessageReciver wasn't being created.
#Override
public void onDestroy (){
super.onDestroy();
LocalBroadcastManager.getInstance(context).unregisterReceiver(mMessageReceiver);
}
Personally I use the method of calling unregisterReceiver and swallowing the exception if it's thrown. I agree this is ugly but the best method currently provided.
I've raised a feature request to get a boolean method to check if a receiver is registered added to the Android API. Please support it here if you want to see it added:
https://code.google.com/p/android/issues/detail?id=73718
I used Intent to let Broadcast Receiver know about Handler instance of main Activity thread and used Message to pass a message to Main activity
I have used such mechanism to check if Broadcast Receiver is already registered or not. Sometimes it is needed when you register your Broadcast Receiver dynamically and do not want to make it twice or you present to the user if Broadcast Receiver is running.
Main activity:
public class Example extends Activity {
private BroadCastReceiver_example br_exemple;
final Messenger mMessenger = new Messenger(new IncomingHandler());
private boolean running = false;
static class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
running = false;
switch (msg.what) {
case BroadCastReceiver_example.ALIVE:
running = true;
....
break;
default:
super.handleMessage(msg);
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter();
filter.addAction("pl.example.CHECK_RECEIVER");
br_exemple = new BroadCastReceiver_example();
getApplicationContext().registerReceiver(br_exemple , filter); //register the Receiver
}
// call it whenever you want to check if Broadcast Receiver is running.
private void check_broadcastRunning() {
/**
* checkBroadcastHandler - the handler will start runnable which will check if Broadcast Receiver is running
*/
Handler checkBroadcastHandler = null;
/**
* checkBroadcastRunnable - the runnable which will check if Broadcast Receiver is running
*/
Runnable checkBroadcastRunnable = null;
Intent checkBroadCastState = new Intent();
checkBroadCastState .setAction("pl.example.CHECK_RECEIVER");
checkBroadCastState .putExtra("mainView", mMessenger);
this.sendBroadcast(checkBroadCastState );
Log.d(TAG,"check if broadcast is running");
checkBroadcastHandler = new Handler();
checkBroadcastRunnable = new Runnable(){
public void run(){
if (running == true) {
Log.d(TAG,"broadcast is running");
}
else {
Log.d(TAG,"broadcast is not running");
}
}
};
checkBroadcastHandler.postDelayed(checkBroadcastRunnable,100);
return;
}
.............
}
Broadcast Receiver:
public class BroadCastReceiver_example extends BroadcastReceiver {
public static final int ALIVE = 1;
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Bundle extras = intent.getExtras();
String action = intent.getAction();
if (action.equals("pl.example.CHECK_RECEIVER")) {
Log.d(TAG, "Received broadcast live checker");
Messenger mainAppMessanger = (Messenger) extras.get("mainView");
try {
mainAppMessanger.send(Message.obtain(null, ALIVE));
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
.........
}
}
i put this code in my parent activity
List registeredReceivers = new ArrayList<>();
#Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
registeredReceivers.add(System.identityHashCode(receiver));
return super.registerReceiver(receiver, filter);
}
#Override
public void unregisterReceiver(BroadcastReceiver receiver) {
if(registeredReceivers.contains(System.identityHashCode(receiver)))
super.unregisterReceiver(receiver);
}
I get your problem, I faced the same problem in my Application. I was calling registerReceiver() multiple time within the application.
A simple solution to this problem is to call the registerReceiver() in your Custom Application Class. This will ensure that your Broadcast receiver will be called only one in your entire Application lifecycle.
public class YourApplication extends Application
{
#Override
public void onCreate()
{
super.onCreate();
//register your Broadcast receiver here
IntentFilter intentFilter = new IntentFilter("MANUAL_BROADCAST_RECIEVER");
registerReceiver(new BroadcastReciever(), intentFilter);
}
}
This is how I have done it, it is a modified version of the answer given by ceph3us and edited by slinden77 (among other things I have removed return values of methods which I did not need):
public class MyBroadcastReceiver extends BroadcastReceiver{
private boolean isRegistered;
public void register(final Context context) {
if (!isRegistered){
Log.d(this.toString(), " going to register this broadcast receiver");
context.registerReceiver(this, new IntentFilter("MY_ACTION"));
isRegistered = true;
}
}
public void unregister(final Context context) {
if (isRegistered) {
Log.d(this.toString(), " going to unregister this broadcast receiver");
context.unregisterReceiver(this);
isRegistered = false;
}
}
#Override
public void onReceive(final Context context, final Intent intent) {
switch (getResultCode()){
//DO STUFF
}
}
}
Then on an Activity class:
public class MyFragmentActivity extends SingleFragmentActivity{
MyBroadcastReceiver myBroadcastReceiver;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
registerBroacastReceiver();
}
#Override
protected Fragment createFragment(){
return new MyFragment();
}
//This method is called by the fragment which is started by this activity,
//when the Fragment is done, we also register the receiver here (if required)
#Override
public void receiveDataFromFragment(MyData data) {
registerBroacastReceiver();
//Do some stuff
}
#Override
protected void onStop(){
unregisterBroacastReceiver();
super.onStop();
}
void registerBroacastReceiver(){
if (myBroadcastReceiver == null)
myBroadcastReceiver = new MyBroadcastReceiver();
myBroadcastReceiver.register(this.getApplicationContext());
}
void unregisterReceiver(){
if (MyBroadcastReceiver != null)
myBroadcastReceiver.unregister(this.getApplicationContext());
}
}
For me the following worked:
if (receiver.isOrderedBroadcast()) {
requireContext().unregisterReceiver(receiver);
}
Here's what I did to check if the Broadcaster is already registered, even if you close you application (finish())
Firstime running your application, send a broadcast first it will return true/false depends on if your broadcaster in still running or not.
My Broadcaster
public class NotificationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getExtras() != null && intent.getStringExtra("test") != null){
Log.d("onReceive","test");
return;
}
}
}
My MainActivity
// init Broadcaster
private NotificationReceiver nr = new NotificationReceiver();
Intent msgrcv = new Intent("Msg");
msgrcv.putExtra("test", "testing");
boolean isRegistered = LocalBroadcastManager.getInstance(this).sendBroadcast(msgrcv);
if(!isRegistered){
Toast.makeText(this,"Starting Notification Receiver...",Toast.LENGTH_LONG).show();
LocalBroadcastManager.getInstance(this).registerReceiver(nr,new IntentFilter("Msg"));
}
if( receiver.isOrderedBroadcast() ){
// receiver object is registered
}
else{
// receiver object is not registered
}
Just check NullPointerException. If receiver does not exist, then...
try{
Intent i = new Intent();
i.setAction("ir.sss.smsREC");
context.sendBroadcast(i);
Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
e.getMessage();
}

How to stop NotificationListenerService android?

I'm using a NotificationListenerService in my android app that was developed from kpbird's example. The service runs in the background even after the app is destroyed. Is there a way to stop this service and start it when app is started?
NotificationListenerService can not be stopped, because after we start the service system will call bindService() . The service will keep a ServiceConnection, then it will not response to the stopService or stopSelf.
As my search result , we also can not remove ServiceConnection from a Service instance.
Create a broadcast receiver inside service which extends NotificationListenerService
like this
public class Block_All_Notification2 extends NotificationListenerService {
boolean check=false;
CancelNotificationReceiver mReceiver = new CancelNotificationReceiver();
public static final String Package_Name = "com.muhaiminurabir.notificationblocker";
#Override
public IBinder onBind(Intent intent) {
return super.onBind(intent);
}
#Override
public void onNotificationPosted(StatusBarNotification sbn){
// Implement what you want here
// Inform the notification manager about dismissal of all notifications.
Log.d("Msg", "Notification arrived");
start_blocking();
/* if (false){
cancelAllNotifications();
}*/
//Block_All_Notification2.this.cancelAllNotifications();
}
#Override
public void onNotificationRemoved(StatusBarNotification sbn){
// Implement what you want here
Log.d("Msg", "Notification Removed");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String block = intent.getStringExtra("block");
Log.d("checking service 1",block+"");
if (block.equals("yes")){
check=true;
}else if(block.equals("no")){
check=false;
}
Log.d("checking service 1",check+"");
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter();
filter.addAction(Package_Name);
registerReceiver(mReceiver, filter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
public void start_blocking(){
Log.d("checking service",check+"");
if (check==true){
cancelAllNotifications();
}
}
class CancelNotificationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("received service","received");
String action;
if (intent != null && intent.getAction() != null) {
action = intent.getAction();
if (action.equals(Package_Name)) {
String block = intent.getStringExtra("block");
if (TextUtils.equals(block, "no")) {
Log.d("checking service 1",block+"");
if (block.equals("yes")){
check=true;
cancelAllNotifications();
}else if(block.equals("no")){
check=false;
}
Log.d("checking service 1",check+"");
} else if (TextUtils.equals(block, "yes")) {
Log.d("checking service 1",block+"");
if (block.equals("yes")){
check=true;
cancelAllNotifications();
}else if(block.equals("no")){
check=false;
}
Log.d("checking service 1",check+"");
}
}
}
}
}
}
and in your activity add this code to communicate with service which create above
Intent intent = new Intent();
intent.setAction(Block_All_Notification2.Package_Name);
intent.putExtra("block", "no");
context.sendBroadcast(intent);
Perhaps this problem has been solved.
However, I recently found a way to start or stop NotificationListenerService, and I would like to share it.
Of course, this is not the official method I think.
Therefore, I think you can just look at it for reference that there is also this way.
I got a hint from the fact that in order to run NotificationListenerService, users must be authorized manually.
When the Start Button is pressed, the NotificationListener permission window is displayed, and a Toast Message is displayed to guide the user to request permission.
On the contrary, when the Stop Button is pressed, the NotificationListener permission window is displayed, and at the same time, a Toast Message is displayed to guide the user to revoke permission.
My code is like belows.
main_start_service_btn.setOnClickListener {
if(isNotificationPermissionAllowed()) {
Toast.makeText(this, "Already Starting Service.", Toast.LENGTH_LONG).show()
}
else {
Toast.makeText(this, "Please allow permission in the next window", Toast.LENGTH_LONG).show()
startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
}
}
main_stop_service_btn.setOnClickListener {
if(isNotificationPermissionAllowed()) {
Toast.makeText(this, "Please deny permission in the next window", Toast.LENGTH_LONG).show()
startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
}
else {
Toast.makeText(this, "Already Stopped Service.", Toast.LENGTH_LONG).show()
}
}
The NotificationListenerService extends Service so yes you can stop a service by calling stopSelf() method in Service class.
Look at this: NotificationListenerService and this Services
Hope it Helps,

How to check if Receiver is registered in Android?

I need to check if my registered receiver is still registered if not how do i check it any methods?
There is no API function to check if a receiver is registered. The workaround is to put your code in a try catch block as done below.
try {
//Register or UnRegister your broadcast receiver here
} catch(IllegalArgumentException e) {
e.printStackTrace();
}
I am not sure the API provides directly an API, if you consider this thread:
I was wondering the same thing.
In my case I have a BroadcastReceiver implementation that calls
Context#unregisterReceiver(BroadcastReceiver) passing itself as the argument after handling the Intent that it receives.
There is a small chance that the receiver's onReceive(Context, Intent) method is called
more than once, since it is registered with multiple IntentFilters, creating the potential for an IllegalArgumentException being thrown from Context#unregisterReceiver(BroadcastReceiver).
In my case, I can store a private synchronized member to check before calling Context#unregisterReceiver(BroadcastReceiver), but it would be
much cleaner if the API provided a check method.
simplest solution
in receiver:
public class MyReceiver extends BroadcastReceiver {
public boolean isRegistered;
/**
* register receiver
* #param context - Context
* #param filter - Intent Filter
* #return see Context.registerReceiver(BroadcastReceiver,IntentFilter)
*/
public Intent register(Context context, IntentFilter filter) {
try {
// ceph3us note:
// here I propose to create
// a isRegistered(Contex) method
// as you can register receiver on different context
// so you need to match against the same one :)
// example by storing a list of weak references
// see LoadedApk.class - receiver dispatcher
// its and ArrayMap there for example
return !isRegistered
? context.registerReceiver(this, filter)
: null;
} finally {
isRegistered = true;
}
}
/**
* unregister received
* #param context - context
* #return true if was registered else false
*/
public boolean unregister(Context context) {
// additional work match on context before unregister
// eg store weak ref in register then compare in unregister
// if match same instance
return isRegistered
&& unregisterInternal(context);
}
private boolean unregisterInternal(Context context) {
context.unregisterReceiver(this);
isRegistered = false;
return true;
}
// rest implementation here
// or make this an abstract class as template :)
...
}
in code:
MyReceiver myReceiver = new MyReceiver();
myReceiver.register(Context, IntentFilter); // register
myReceiver.unregister(Context); // unregister
ad 1
-- in reply to:
This really isn't that elegant because you have to remember to set the
isRegistered flag after you register. – Stealth Rabbi
-- "more ellegant way" added method in receiver to register and set flag
this won't work If you restart the device or if your app got killed by
OS. – amin 6 hours ago
#amin - see lifetime of in code (not system registered by manifest entry) registered receiver :)
I am using this solution
public class ReceiverManager {
private WeakReference<Context> cReference;
private static List<BroadcastReceiver> receivers = new ArrayList<BroadcastReceiver>();
private static ReceiverManager ref;
private ReceiverManager(Context context) {
cReference = new WeakReference<>(context);
}
public static synchronized ReceiverManager init(Context context) {
if (ref == null) ref = new ReceiverManager(context);
return ref;
}
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter intentFilter) {
receivers.add(receiver);
Intent intent = cReference.get().registerReceiver(receiver, intentFilter);
Log.i(getClass().getSimpleName(), "registered receiver: " + receiver + " with filter: " + intentFilter);
Log.i(getClass().getSimpleName(), "receiver Intent: " + intent);
return intent;
}
public boolean isReceiverRegistered(BroadcastReceiver receiver) {
boolean registered = receivers.contains(receiver);
Log.i(getClass().getSimpleName(), "is receiver " + receiver + " registered? " + registered);
return registered;
}
public void unregisterReceiver(BroadcastReceiver receiver) {
if (isReceiverRegistered(receiver)) {
receivers.remove(receiver);
cReference.get().unregisterReceiver(receiver);
Log.i(getClass().getSimpleName(), "unregistered receiver: " + receiver);
}
}
}
You have several options
You can put a flag into your class or activity. Put a boolean variable into your class and look at this flag to know if you have the Receiver registered.
Create a class that extends the Receiver and there you can use:
Singleton pattern for only have one instance of this class in your project.
Implement the methods for know if the Receiver is register.
You have to use try/catch:
try {
if (receiver!=null) {
Activity.this.unregisterReceiver(receiver);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
You can do it easy....
1) create a boolean variable ...
private boolean bolBroacastRegistred;
2) When you register your Broadcast Receiver, set it to TRUE
...
bolBroacastRegistred = true;
this.registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
....
3) In the onPause() do it...
if (bolBroacastRegistred) {
this.unregisterReceiver(mReceiver);
bolBroacastRegistred = false
}
Just it, and now, you will not receive more exception error message on onPause().
Tip1: Always use the unregisterReceiver() in onPause() not in onDestroy()
Tip2: Dont forget to set the bolBroadcastRegistred variable to FALSE when run the unregisterReceive()
Success!
If you put this on onDestroy or onStop method. I think that when the activity has been created again the MessageReciver wasn't being created.
#Override
public void onDestroy (){
super.onDestroy();
LocalBroadcastManager.getInstance(context).unregisterReceiver(mMessageReceiver);
}
Personally I use the method of calling unregisterReceiver and swallowing the exception if it's thrown. I agree this is ugly but the best method currently provided.
I've raised a feature request to get a boolean method to check if a receiver is registered added to the Android API. Please support it here if you want to see it added:
https://code.google.com/p/android/issues/detail?id=73718
I used Intent to let Broadcast Receiver know about Handler instance of main Activity thread and used Message to pass a message to Main activity
I have used such mechanism to check if Broadcast Receiver is already registered or not. Sometimes it is needed when you register your Broadcast Receiver dynamically and do not want to make it twice or you present to the user if Broadcast Receiver is running.
Main activity:
public class Example extends Activity {
private BroadCastReceiver_example br_exemple;
final Messenger mMessenger = new Messenger(new IncomingHandler());
private boolean running = false;
static class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
running = false;
switch (msg.what) {
case BroadCastReceiver_example.ALIVE:
running = true;
....
break;
default:
super.handleMessage(msg);
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter();
filter.addAction("pl.example.CHECK_RECEIVER");
br_exemple = new BroadCastReceiver_example();
getApplicationContext().registerReceiver(br_exemple , filter); //register the Receiver
}
// call it whenever you want to check if Broadcast Receiver is running.
private void check_broadcastRunning() {
/**
* checkBroadcastHandler - the handler will start runnable which will check if Broadcast Receiver is running
*/
Handler checkBroadcastHandler = null;
/**
* checkBroadcastRunnable - the runnable which will check if Broadcast Receiver is running
*/
Runnable checkBroadcastRunnable = null;
Intent checkBroadCastState = new Intent();
checkBroadCastState .setAction("pl.example.CHECK_RECEIVER");
checkBroadCastState .putExtra("mainView", mMessenger);
this.sendBroadcast(checkBroadCastState );
Log.d(TAG,"check if broadcast is running");
checkBroadcastHandler = new Handler();
checkBroadcastRunnable = new Runnable(){
public void run(){
if (running == true) {
Log.d(TAG,"broadcast is running");
}
else {
Log.d(TAG,"broadcast is not running");
}
}
};
checkBroadcastHandler.postDelayed(checkBroadcastRunnable,100);
return;
}
.............
}
Broadcast Receiver:
public class BroadCastReceiver_example extends BroadcastReceiver {
public static final int ALIVE = 1;
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Bundle extras = intent.getExtras();
String action = intent.getAction();
if (action.equals("pl.example.CHECK_RECEIVER")) {
Log.d(TAG, "Received broadcast live checker");
Messenger mainAppMessanger = (Messenger) extras.get("mainView");
try {
mainAppMessanger.send(Message.obtain(null, ALIVE));
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
.........
}
}
i put this code in my parent activity
List registeredReceivers = new ArrayList<>();
#Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
registeredReceivers.add(System.identityHashCode(receiver));
return super.registerReceiver(receiver, filter);
}
#Override
public void unregisterReceiver(BroadcastReceiver receiver) {
if(registeredReceivers.contains(System.identityHashCode(receiver)))
super.unregisterReceiver(receiver);
}
I get your problem, I faced the same problem in my Application. I was calling registerReceiver() multiple time within the application.
A simple solution to this problem is to call the registerReceiver() in your Custom Application Class. This will ensure that your Broadcast receiver will be called only one in your entire Application lifecycle.
public class YourApplication extends Application
{
#Override
public void onCreate()
{
super.onCreate();
//register your Broadcast receiver here
IntentFilter intentFilter = new IntentFilter("MANUAL_BROADCAST_RECIEVER");
registerReceiver(new BroadcastReciever(), intentFilter);
}
}
This is how I have done it, it is a modified version of the answer given by ceph3us and edited by slinden77 (among other things I have removed return values of methods which I did not need):
public class MyBroadcastReceiver extends BroadcastReceiver{
private boolean isRegistered;
public void register(final Context context) {
if (!isRegistered){
Log.d(this.toString(), " going to register this broadcast receiver");
context.registerReceiver(this, new IntentFilter("MY_ACTION"));
isRegistered = true;
}
}
public void unregister(final Context context) {
if (isRegistered) {
Log.d(this.toString(), " going to unregister this broadcast receiver");
context.unregisterReceiver(this);
isRegistered = false;
}
}
#Override
public void onReceive(final Context context, final Intent intent) {
switch (getResultCode()){
//DO STUFF
}
}
}
Then on an Activity class:
public class MyFragmentActivity extends SingleFragmentActivity{
MyBroadcastReceiver myBroadcastReceiver;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
registerBroacastReceiver();
}
#Override
protected Fragment createFragment(){
return new MyFragment();
}
//This method is called by the fragment which is started by this activity,
//when the Fragment is done, we also register the receiver here (if required)
#Override
public void receiveDataFromFragment(MyData data) {
registerBroacastReceiver();
//Do some stuff
}
#Override
protected void onStop(){
unregisterBroacastReceiver();
super.onStop();
}
void registerBroacastReceiver(){
if (myBroadcastReceiver == null)
myBroadcastReceiver = new MyBroadcastReceiver();
myBroadcastReceiver.register(this.getApplicationContext());
}
void unregisterReceiver(){
if (MyBroadcastReceiver != null)
myBroadcastReceiver.unregister(this.getApplicationContext());
}
}
For me the following worked:
if (receiver.isOrderedBroadcast()) {
requireContext().unregisterReceiver(receiver);
}
Here's what I did to check if the Broadcaster is already registered, even if you close you application (finish())
Firstime running your application, send a broadcast first it will return true/false depends on if your broadcaster in still running or not.
My Broadcaster
public class NotificationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getExtras() != null && intent.getStringExtra("test") != null){
Log.d("onReceive","test");
return;
}
}
}
My MainActivity
// init Broadcaster
private NotificationReceiver nr = new NotificationReceiver();
Intent msgrcv = new Intent("Msg");
msgrcv.putExtra("test", "testing");
boolean isRegistered = LocalBroadcastManager.getInstance(this).sendBroadcast(msgrcv);
if(!isRegistered){
Toast.makeText(this,"Starting Notification Receiver...",Toast.LENGTH_LONG).show();
LocalBroadcastManager.getInstance(this).registerReceiver(nr,new IntentFilter("Msg"));
}
if( receiver.isOrderedBroadcast() ){
// receiver object is registered
}
else{
// receiver object is not registered
}
Just check NullPointerException. If receiver does not exist, then...
try{
Intent i = new Intent();
i.setAction("ir.sss.smsREC");
context.sendBroadcast(i);
Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
e.getMessage();
}

Categories

Resources