Android and sendOrderedBroadcast - how to immediately get the results? - android

In some cases I need to get data from misc intents and try to use sendOrderedBroadcast. But this call is async, and I don't know how to wait for it. I try:
onCreate(...)
{
// ...
sendOrderedBroadcast(...);
if (someResult!=null)
{
// Never executed
}
// ...
}
onButtonPressed(...)
{
if (someResult!=null)
{
// Often fires
}
}
I think I need to call something like Windows message loop
while (::PeekMessage(...))
{
GetMessage(...);
}
after sendOrderedBroadcast and before using someResult.
How I can do it? Or, is there more convenient and right way?
UPD More details
public class DetailsChecker extends BroadcastReceiver{
public void onReceive(Context context, Intent intent)
// ...
}
// ...
sendOrderedBroadcast(detailsIntent, null, new DetailsChecker(), null,
Activity.RESULT_OK, null, null);

Actually, it is possible. You can specify a handler that will receive the response in sendOrderedbroadcast, so you can receive it on another thread and block the UI thread while the broadcast is being processed. Something like that:
final Object monitor = new Object();
HandlerThread thread = new HandlerThread("blabla");
thread.start();
synchronized (monitor) {
Intent intent = new Intent("nanana");
context.sendOrderedBroadcast(intent,
null,
new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// mystuff
someResult = tagada;
synchronized(monitor) {
monitor.notify();
}
}
},
new Handler(thread.getLooper()),
Activity.RESULT_OK,
null,
null
);
try {
monitor.wait(2000); // timeout for receiving the result
} catch (InterruptedException e) {
}
}
thread.quit();
if (someResult != null) {
// gets executed
}
Of course, "blocking the UI thread is bad, m'kaaaaay". But I guess you know what you're doing.

Related

Android not able to stop service

In my app i am using a Service that periodically checks if there is a new personal message for the logged in user.
The service is started if the user enables the notification feature. Now if the user disables the notification feature i would like to stop the service.
I try to stop the service with the following lines of code.
Intent service = new Intent(getApplicationContext(), MessageService.class);
stopService(service);
The problem is that the service doesn't stop. It goes on working.
Here you can see my message service.
public class MessageService extends Service {
private int intervall;
public MessageService(){
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent,flags,startId);
Bundle intentData = intent.getExtras();
if(intentData != null) {
this.intervall = intentData.getInt("intervall");
}
final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// async task for calling api otherwise we get an exeception here
new ServiceMessagesTask().execute(MessageService.this);
}
};
new Thread(new Runnable(){
public void run() {
while(true)
{
try {
Thread.sleep(intervall); // repeat after given intervall
handler.sendEmptyMessage(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
I have an activity where the user can edit his preferences. There it is also possible to activate the notification feature.
The notification service is started or stoped in the savePreferences() method:
public void savePreferences(View button) {
EditText login = (EditText)findViewById(R.id.txtbLogin);
EditText password = (EditText)findViewById(R.id.txtbPassword);
CheckBox enableNotification = (CheckBox) findViewById(R.id.cbNotifications);
Spinner spinner = (Spinner) findViewById(R.id.notificationInterval);
if(!login.getText().equals("") && !password.getText().equals("")){
Map<String, Object> preferences = new HashMap<String, Object>();
preferences.put("document_type", CouchbaseHelper.CB_VIEW_USER_PREFERENCES);
preferences.put("login", login.getText().toString());
preferences.put("password", password.getText().toString());
if(enableNotification.isChecked()){
preferences.put("enableNotification", true);
} else {
preferences.put("enableNotification", false);
}
preferences.put("notificationInterval", this.notificationInterval);
CouchbaseHelper couchbaseHelper = new CouchbaseHelper(getApplicationContext());
String documentId = couchbaseHelper.createDocUserPreferences(preferences);
couchbaseHelper.closeDb();
// start notification service if enabled
if(enableNotification.isChecked()){
Intent service = new Intent(getApplicationContext(), MessageService.class);
service.putExtra("intervall", Integer.valueOf(this.notificationInterval)*60*1000);
startService(service);
} else {
// TODO: this is not working!!! service doesnt stop
// try to stop running service
if(isMyServiceRunning()){
Intent service = new Intent(getApplicationContext(), MessageService.class);
stopService(service);
}
}
}
finish();
Intent main = new Intent(Preferences.this, Main.class);
startActivity(main);
}
I'm afraid you really don't get what a service is, service is just a component that do not require UI and is not linked to an activity life cycle, hence it runs in background, BUT background doesn't necessarily means in a separate thread, actually the service runs in the main thread, now that's one thing, killing a service doesn't mean you are killing all the working threads you create within, and in your code you are creating a Thread that is looping forever, that thread although created in the service is not linked in any way to the service life cycle.
So, if you want to stop the thread, get a reference to the thread you are creating in the startCommand method and in the onDestroy method just stop it, instead of having a while(true) validation, go for a flag and just change it to false in the onDestroy so it will stop the thread you created when started the service.
Regards!

Communicate with a WallpaperService

Is there any way to directly communicate with a WallpaperService from an Activity? It doesn't look like I can use the normal service communication classes because the onBind method is declared final in the WallpaperService class I'm extending. Worth noting that I'm referring to my WallpaperService not any.
Any workarounds if this isn't possible?
My solution was to use local sockets. I created an instance of a LocalServerSocket in the constructor of my wallpaper's Engine. Here's a quick implementation. Server runs on a separate thread and is directly tied to the lifecycle of MyEngine. The thread will stop when continueSocket is set to false. This happens onDestroy. Problem is that LocalServerSocket.accept() blocks until there's something to do. The workaround is to send a message to our own server so it will run through the loop again and check continueSocket (which is now false), closing the server. Check the closeSocketServer method. I have it running in onDestroy in the example but you might want to use it elsewhere like onSurfaceDestroyed and add your own sanity checks.
public class MyWallpaperService extends WallpaperService {
#Override
public Engine onCreateEngine() {
return new MyEngine();
}
private class MyEngine extends Engine {
private boolean continueSocket = true;
MyEngine() {
new Thread() {
#Override
public void run() {
try {
LocalServerSocket server = new LocalServerSocket("MyAddress");
Log.d("SERVER READY", "Server is ready.");
while(continueSocket) {
LocalSocket receiver = server.accept();
if(receiver != null) {
InputStream input = receiver.getInputStream();
byte[] data = IOUtils.toByteArray(input);
Log.d("GOT DATA", new String(data));
}
}
server.close();
} catch (IOException ex) {
Log.wtf("IOEXCEPTION", ex);
}
}
}.start();
}
#Override
public void onDestroy() {
closeSocketServer();
super.onDestroy();
}
private void closeSocketServer() {
continueSocket = false;
try {
LocalSocket socket = new LocalSocket();
socket.connect(new LocalSocketAddress("MyAddress"));
socket.getOutputStream().write(new byte[0]);
socket.getOutputStream().close();
socket.close();
} catch (IOException ex) {
//
}
}
}
}
And in my Activity it can be as simple as this...
try {
LocalSocket sender = new LocalSocket();
sender.connect(new LocalSocketAddress("MyAddress"));
String data = "Hello world!";
Log.d("SENT DATA", data);
sender.getOutputStream().write(data.getBytes());
sender.getOutputStream().close();
sender.close();
} catch (IOException ex) {
Log.wtf("IOEXCEPTION", ex);
}
Logcat ends up looking like this:
D/SERVER READY﹕ Server is ready. (when the wallpaper starts up)
D/SENT DATA﹕ Hello world! (when the activity sends data)
D/GOT DATA﹕ Hello world! (when the wallpaper gets the data)
In your WallpaperService onCreateEngine:
IntentFilter intentFilter = new IntentFilter("your.package.your.action");
MyBroadcastReceiver mReceiver = new MyBroadcastReceiver(mRenderer);
LocalBroadcastManager.getInstance(getApplicationContext())
.registerReceiver(mReceiver, intentFilter);
In mRenderer's class:
public void receiveCommand(int i) {
Log.d("got", String.valueOf(i));
}
Receiver class:
public class MyBroadcastReceiver extends BroadcastReceiver {
private final MyRenderer _mRenderer;
public MyBroadcastReceiver(MyRenderer mRenderer) {
_mRenderer = mRenderer;
}
#Override
public void onReceive(Context context, Intent intent) {
_mRenderer.receiveCommand(intent.getExtra("msg", -1));
}
}
Now call from activity:
Intent in = new Intent();
in.setAction("your.package.your.action");
in.setExtra("msg", 42);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(in);

Android - BroadcastReceiver unregisterReceiver issue (not registered)

I'm having some problems unregistering a BroadcastReceiver. I'm first registering it but then when I want to unregister it by using unregisterReceiver(); command gives me tons of errors. The error says that I've not registered my BroadcastReceiver.
Code:
public class Receiver extends BroadcastReceiver implements Variables {
CheckConexion cc;
#Override
public void onReceive(Context contxt, Intent intent) {
// Cuando hay un evento, lo diferenciamos y hacemos una acción.
if (intent.getAction().equals(SMS_RECEIVED)) {
Sms sms = new Sms(null, contxt);
sms.uploadNewSms(intent);
} else if (intent.getAction().equals(Intent.ACTION_BATTERY_LOW)) {
// st.batterylow(contxt);
} else if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
// st.power(1, contxt);
} else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
// st.power(0, contxt);
} else if (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
|| intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)
|| intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) {
Database db = new Database(contxt);
if (db.open().Preferences(4)) {
Uri data = intent.getData();
new ListApps(contxt).import_app(intent, contxt, data,
intent.getAction());
}
db.close();
} else if (intent.getAction().equals(
ConnectivityManager.CONNECTIVITY_ACTION)) {
cc = new CheckConexion(contxt);
if (cc.isOnline()) {
/*Database db = new Database(contxt);
db.open();
if (db.move() == 1) {
new UploadOffline(contxt);
}
db.close();*/
}
}
}
public void register(Context c) {
Receiver r = new Receiver();
IntentFilter i = new IntentFilter();
i.addAction(SMS_RECEIVED);
i.addAction(Intent.ACTION_BATTERY_LOW);
i.addAction(Intent.ACTION_POWER_CONNECTED);
i.addAction(Intent.ACTION_POWER_DISCONNECTED);
i.addAction(Intent.ACTION_CALL_BUTTON);
i.addAction(Intent.ACTION_CAMERA_BUTTON);
i.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
c.registerReceiver(r, i);
IntentFilter apps = new IntentFilter();
apps.addAction(Intent.ACTION_PACKAGE_ADDED);
apps.addAction(Intent.ACTION_PACKAGE_CHANGED);
apps.addAction(Intent.ACTION_PACKAGE_REMOVED);
apps.addDataScheme("package");
c.registerReceiver(r, apps);
}
public void unregister(Context c) {
BroadcastReceiver r = new Receiver();
if (r != null) {
c.unregisterReceiver(r);
}
}
}
First of all,
Use this to work with the object of the class Reciever
remove all r objects, don't call constructors in the extending class.
Then:
Define
boolean isRegistered = false;
In your register method:
c.registerReceiver(this);
isRegistered = true;
In your unregister method:
if (isRegistered) {
c.unregisterReceiver(this);
isRegistered = false;
}
Then in your activity use instance of the class Reciver.
Hope, it was helpful!
The best solution is to put the unregisterReceiver method into a try catch block.
try {
this.unregisterReceiver(myReceiver);
}
catch (final Exception exception) {
// The receiver was not registered.
// There is nothing to do in that case.
// Everything is fine.
}
Unfortunately, there is no specific exception thrown when unregisterReceiver fails, so you got to use Exception. Also, there is unfortunately no method like isReceiverRegistered(BroadcastReceiver receiver), which in my opinion would be an enhancement to the Android API.
Besides, it won't hurt to take a look at ReceiverLifecycle
You cannot unregister a new instance of broadcast Receiver. You will need to use the same instance of BroadcastReciever which has been registered.
So use
c.registerReceiver(this, apps);
and
c.unregisterReceiver(this);
In unregister method, you are creating a new BroadcastReceiver instance and unregistering that. Instead make the instance in register method global and call
if (r != null) {
c.unregisterReceiver(r);
r = null;
}
in unregister method.

Start activity in a try/catch bloc

I just want to know how to launch an Activity in a try/catch bloc, i made this
public void onReceive(Context context, Intent intent) {
SipAudioCall incomingCall = null;
try {
Intent monIntent = new Intent(this,dialog.class);
startActivity(monIntent);
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
#Override
public void onRinging(SipAudioCall call, SipProfile caller) {
But i have errors:
constructor Intent(IncomingCallReceiver, Class<dialog>) is not defined
Method startActivity(Intent) is undefined for the type IncomingCallReceiver
I want to show an alertdialog when having a call.
How can i solve this problem?
Thank you very much.
Whole class:
public class IncomingCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
SipAudioCall incomingCall = null;
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
#Override
public void onRinging(SipAudioCall call, SipProfile caller) {
try {
call.answerCall(30);
} catch (Exception e) {
e.printStackTrace();
}
}
};
SIPCommunicator wtActivity = (SIPCommunicator) context;
incomingCall = wtActivity.manager.takeAudioCall(intent, listener);
incomingCall.answerCall(30);
incomingCall.startAudio();
incomingCall.setSpeakerMode(true);
if(incomingCall.isMuted()) {
incomingCall.toggleMute();
}
wtActivity.call = incomingCall;
wtActivity.updateStatus(incomingCall);
} catch (Exception e) {
if (incomingCall != null) {
incomingCall.close();
}
}
}
}
The problem you are facing is not the try catch block, it's the fact that you are starting activity in a listener implementation. Substitute
Intent monIntent = new Intent(this,dialog.class);
with
Intent monIntent = new Intent(<Name of this class>.this,dialog.class);
and
startActivity(monIntent);
with
<Name of this class>.this.startActivity(monIntent);
By <Name of this class> I mean the head class where you are writing your code.
By the looks of it, you are launching a new thread from within a try/catch block. This is bad practice as the thread can fail should an exception be being thrown.
Instead, declare a variable before the value, and assign to it on the line preceding the catch statement.
Also assign to it if the exception is raised, but a different value.
Then launch the thread outside the try/catch block, based on the successful evaluation of the variable.
Use callbacks to trap failed threads, not exceptions.
int x = 0;
try
{
/* Do some logic here */
x = 1; // we have success
}
catch(Exception e)
{
x = -1; // failure
}
if (x > 0)
{
Intent monIntent = new Intent(this,dialog.class);
startActivity(monIntent);
...
}
As a newbie I would like to state my view:-
Try putting some error messages to find out where the error is occurring. Also check the log file.
Example of try catch:-
try
{
//some code
//Toast message on success
Toast.makeText(this, R.string.msgStatusUpdatedSuccefully, Toast.LENGTH_LONG).show();
}
catch (TwitterException e)
{
//Toast message on failure
Toast.makeText(this, R.string.msgStatusUpdateFailed, Toast.LENGTH_LONG).show();
e.printStackTrace();
}
I would check if my imports are all fine for all the api's that I am using.
Also does your main public class looks like the following to resolve the undefined error:-
public class StatusActivity extends Activity implements OnClickListener{}

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