Modify UI from BroadcastReceiver - android

I need some way to detect when the network connection has been lost.
So a switch between mobile and wifi doesn't really matter it's just to detect at runtime when the connection has been lost.
I now have found some code which works fine for me.
public class ConnectivityReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(ConnectivityReceiver.class.getSimpleName(), "action: "
+ intent.getAction());
}
}
I want to check inside the onReceive() method wheter or not a connection is still available or not.
The thing is, that I want to show a message to the user, if it has been lost. So what's the best way of passing back to my Activity, that the connection has been lost?

If you want to track network connection state only when activity is on screen you can place your ConnectivityReceiver as inner nested class in Activity. In this case you should register it in onResume method and unregister it in onPause. It will look like this:
public class MyActivity extends Activity {
private class ConnectivityReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(ConnectivityReceiver.class.getSimpleName(), "action: "
+ intent.getAction());
}
}
private final BroadcastReceiver receiver = new ConnectivityReceiver();
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(receiver, filter);
}
}

You can have an inner Class which extends BroadcastReceiver and you can dynamically register it. From the innterclass(precisely onRecieve() method) you can access your Activity.

Related

Can a Broadcast Receiver send information to an Activity only if it is active without starting a new Activity?

I have a broadcast receiver that gets triggered on geofencing events and either "clocks in" or "clocks out" with the server. If my application's "Attendance" activity is already open I would like it to display the clocking status change but I don't want the Broadcast Receiver to start the activity if it's not open - in other words display the change "live" while the activity is open only.
The way I imagine doing this is with the Broadcast Receiver sending an Intent to the activity but name "startActivity()" doesn't sound encouraging unless there are any special flags I can pass to prevent starting an Activity that isn't already open - I can't seem to find any.
The other option would be to constantly poll the value while the activity is open but it doesn't seem optimal so I would only use it if there wasn't another way and I can't think of a reason why it couldn't be possible with Intents.
There are several different ways to accomplish the same task. One is registering a listener like the following example:
MainActivity
public class MainActivity extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Receiver.setOnReceiveListener(new Receiver.OnReceiveListener() {
public void onReceive(Context Context, Intent intent)
{
//Do something.
}
});
}
#Override
protected void onDestroy()
{
super.onDestroy();
Receiver.setOnReceiveListener(null);
}
}
Receiver
public class Receiver extends BroadcastReceiver
{
private static OnReceiveListener static_listener;
public static abstract interface OnReceiveListener
{
public void onReceive(Context context, Intent intent);
}
public static void setOnReceiveListener(OnReceiveListener listener)
{
static_listener = listener;
}
#Override
public final void onReceive(Context context, Intent intent)
{
if(static_listener != null) {
static_listener.onReceive(context, intent);
}
}
}
Just have your BroadcastReceiver send a broadcast Intent. Your Activity should register a listener from this broadcast Intent and if it gets triggered, it can update the UI.
Here's an example:
Declare a private member variable in your Activity:
private BroadcastReceiver receiver;
In Activity.onCreate(), register the BroadcastReceiver:
IntentFilter filter = new IntentFilter();
filter.addAction("my.package.name.CLOCK_STATUS_CHANGE");
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Here you can update the UI ...
}
};
registerReceiver(receiver, filter);
And in onDestroy() you can unregister it (probably not necessary, but cleaner):
if (receiver != null) {
unregisterReceiver(receiver);
receiver = null;
}
In your BroadcastReceiver that detects the geofencing event, you should create and send a broadcast Intent:
Intent broadcastIntent = new Intent("my.package.name.CLOCK_STATUS_CHANGE");
sendBroadcast(broadcastIntent);

How to pass data from BroadcastReceiver to Activity without in onCreate()

I have a serious issue about passing data from BroadcastReceiver to an Activity. Let see my issue carefully. I have a class PhoneStateReceiver extends BroadcastReceiver that used to received an incoming phone.
public class PhoneStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
System.out.println("Receiver start");
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
The incoming phone will be sent to an Activity, called ReceiverActivity. The ReceiverActivity receives the incoming phone and sends it to a server via a socket connection. The socket connection is initialized in the onCreate function. I googled and found server way to pass the data from BroadcastReceiver to an Activity. The common way is that send data via putExtra function and call startActivity. However, the way will call the onCreate again and then connect the socket, draw the UI again. Thus, it is not helpful in my case.
In my goal, If the phone receives an incoming call, it will send the incoming call to the ReceiverActivity. The ReceiverActivity receives the message and calls the send function. Which is the best way to do it? Thank you
The common way to pass data from a BroadcastReceiver to a ReceiverActivity that I used as follows
In PhoneStateReceiver class :
Intent intent_phonenum = new Intent(context, ReceiverActivity.class);
intent_phonenum.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent_phonenum.putExtra("phone_num", incomingNumber);
context.startActivity(intent_phonenum);
In ReceiverActivity class :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connect_socket();
Intent intent = getIntent();
phone_num = intent.getStringExtra("phone_num");
send(phone_num);
}
Simple without any third party libs.
Make sure BroadcastReceiver must be registered and also unregistered on OnPause().
You have to do two thing
Register a receiver in you activity like below.
public class MainActivity extends Activity {
Context context;
BroadcastReceiver updateUIReciver;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
IntentFilter filter = new IntentFilter();
filter.addAction("service.to.activity.transfer");
updateUIReciver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//UI update here
if (intent != null)
Toast.makeText(context, intent.getStringExtra("number").toString(), Toast.LENGTH_LONG).show();
}
};
registerReceiver(updateUIReciver, filter);
}
}
Now in you service
public class PhoneStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
System.out.println("Receiver start");
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
Intent local = new Intent();
local.setAction("service.to.activity.transfer");
local.putExtra("number", incomingNumber);
context.sendBroadcast(local);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
There is a very simple design pattern you can use here to ease communication between your classes and also decouple your code: publisher/subscriber. My favorite library for this is EventBus:
First, add to your build.gradle file:
compile 'org.greenrobot:eventbus:3.0.0'
Then, create a simple POJO - Plain Old Java Object like this:
public class OnReceiverEvent{
private String phoneNumber;
public OnReceiverEvent(String phone){
this.phoneNumber = phone;
}
public String getPhoneNumber(){
return phoneNumber;
}
}
Next, by making your Receiver class a publisher, and your Activity a subscriber, you should be able to easily pass the information to your activity like this:
//inside your PhoneStateReceiver class when you want to pass info
EventBus.getDefault().post(new OnReceiverEvent(phoneNumber));
Next, inside your activity, simply do this:
//onStart
#Override
public void onStart(){
super.onStart();
EventBus.getDefault().register(this);
}
//onStop
#Override
public void onStop(){
super.onStop();
EventBus.getDefault().unregister(this);
}
Finally, handle the posted data i.e phoneNumber value:
#Subscribe
public void onPhoneNumberReceived(OnReceiverEvent event){
//get the phone number value here and do something with it
String phoneNumber = event.getPhoneNumber();
//display or something?
}
UPDATE
If you have another Event that you want this activity to subscribe to, simply create a method like you did in the first one using the #Subscribe annotation.
#Subscribe
public void onSomeOtherEvent(EventClassName event){
//get the variables here as usual;
}
This is the easiest way to pass the data from your receiver to your activity without having to worry about starting the activity over and over!
I hope this helps and good luck!
So I understand you don't want to recreate your Activity everytime.
In your Intent changing this flag will help you :
intent_phonenum.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
In Intent class if you read method summary of FLAG_ACTIVITY_CLEAR_TOP:
If set, and the activity being launched is already running in the
current task, then instead of launching a new instance of that activity,
all of the other activities on top of it will be closed and this Intent
will be delivered to the (now on top) old activity as a new Intent. (you can read more ...)
In this case: If your app is running and you have an Activity instance then Intent will not recreate your Activity. But assume that your app is in closed state and when BroadcastReceiver triggered, the Intent will create new Activity because you don't have instance of that Activity.
#Edit :
You can specify special Intent like that in your BroadcastReceiver:
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
Intent i = new Intent("mycustombroadcast");
i.putExtra("phone_num", incomingNumber);
context.sendBroadcast(i);
}
Then in your Activity inside onCreate() register receiver like that :
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
int incoming_number= bundle.getInt("phone_num");
Log.e("incoming number", "" + incoming_number);
}
};
//then register receiver like that :
registerReceiver(broadcastReceiver, new IntentFilter("mycustombroadcast"));
You can unregister Receiver in onDestroy() : unregisterReceiver(broadcastReceiver);
Also another way is overriding onNewIntent() in your Activity:
#Override
protected void onNewIntent(Intent intent) {
//your intent is here, you can do sth.
super.onNewIntent(intent);
}

How to know if activity is at the top of stack

How could I know if an activity is the top of stack? I thought about using onResume/onPause, but this is not exactly, as it would fail once the app goes to background.
The fact is that I'm sending a broadcast receiver that is received for all activities (I have a BaseActivity that is extended by all activities and that registers to the broadcast). So, only the activity that is at the top of the stack must react to the broadcast. If I use the isResumed() then it would work always but when the app goes to background. Any idea?
Thanks in advance!
in base activity you register the broadcast Receiver and in receiver function you call one abstract function which one is implemented by all child activities.
The activity which is on top will automatically receive that function call.
Edit sample code:
public abstract class BaseActivity extends AppCompatActivity {
private static final String NOTIFICATION_ARRIVED = "arrived";
public abstract void receivedFunction(Intent intent);
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
displayToast(" received in Base");
receivedFunction(intent);
}
};
public void displayToast(String s) {
Toast.makeText(this,s,Toast.LENGTH_SHORT).show();
}
#Override
public void onResume() {
super.onResume();
registerReceiver(mMessageReceiver, new IntentFilter(BaseActivity.NOTIFICATION_ARRIVED));
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(mMessageReceiver);
}
}
public class MainActivity extends BaseActivity {
#Override
public void receivedFunction(Intent intent) {
displayToast(" received in child");
}
// do whetever you want . if you ovveride onpause and onResume then call super as well
}
or any other child
public class MainActivity2 extends BaseActivity {
#Override
public void receivedFunction(Intent intent) {
displayToast(" received in child");
}
// do whetever you want . if you ovveride onpause and onResume then call super as well
}
// to broadcast
Intent intent = new Intent(BaseActivity.NOTIFICATION_ARRIVED);
sendBroadcast(intent);

Android, calling class method AFTER receiving message from service

Well, I have a service, I have an Activity. They communicate via messages (It must communicate with messages so don't tell me about Intents or other things, please).
I receive a Bundle from the Service, all ok.
Now with the Bundle i've received I want to do something. I want to call a method from "SomeClass", but I can't, because I'm inside of "IncomingHandler" class.
What's the best way to call SomeClass from inside IncomingHandler?
Thanks in advance
class SomeClass implements ServiceConnection {
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyService.MS_GET_SOMETHING:
Bundle received=msg.getData();
...
If you really want the activity to be calling methods on the service, its time to learn about AIDL, which allows an Activity to make function calls on a bound service via an RPC mechanism. Documentation found here.
I have implemented the feature (Service calls method in activity) like this:
Service sends a broadcast-message.
Activity has a local nested broadcastreceiver that can call a method in the parent activity.
public class MainActivity extends Activity {
private BroadcastReceiver myReceiver = null;
class _RemoteTimeTrackerReceiver extends BroadcastReceiver {
#Override
public void onReceive (Context context, Intent intent) {
// call method in activity
reloadGui();
}
}
#Override
public void onResume() {
super.onResume();
if (myReceiver == null)
{
myReceiver = new _RemoteTimeTrackerReceiver();
IntentFilter filter = new IntentFilter(Global.REFRESH_GUI);
registerReceiver(myReceiver, filter);
}
reloadGui();
}
#Override
public void onPause() {
if (myReceiver != null)
{
unregisterReceiver(myReceiver);
myReceiver = null;
}
super.onPause();
}
void reloadGui() {}

Communication between C2DM BroadcastReceiver and multiple activities

I have an Android application which uses C2DM services (aka push).
I have a separate class which implements the registration process and which receives the data (and extends BroadcastReceiver).
I want to communicate this data to the activity which currently is in the foreground. The activity currently in the foreground may differ depending on user action.
What's the best way to communicate in between the receiver and the current activity?
Thanks.
I solved this problem by sending out a new broadcast from the C2DMReceiver class, which looked something like this.
The C2DMReceiver class:
public class C2DMReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
handleRegistration(context, intent);
} else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
handleMessage(context, intent);
}
}
private void handleRegistration(Context context, Intent intent) {
// handle registration
}
private void handleMessage(Context context, Intent intent) {
Intent i = new Intent("push");
i.putExtras(intent);
// context.sendOrderedBroadcast(i, null);
context.sendBroadcast(i);
}
}
Another class I called PushReceiver. This is the class that will extend BroadcastReceiver and receive the broadcast sent by C2DMReceiver.
public class PushReceiver extends BroadcastReceiver {
public PushReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
// do stuff
abortBroadcast();
}
public static class PushFilter extends IntentFilter {
private static final int DEFAULT_PUSH_PRIORITY = 1;
public PushFilter() {
this(DEFAULT_PUSH_PRIORITY);
}
public PushFilter(int priority) {
super("push");
setPriority(priority);
}
}
}
And the activity class, in this case called MyActivity. This should work well if you are using a base activity class that all other activities extend. That way every activity registers the receiver. By doing the register/unregister in onResume/onPause, you should be able to guarantee that only the current activity receives the broadcast. If not, you can send an ordered broadcast from C2DMReceiver and use priority in the PushFilter.
public class MyActivity extends Activity {
private PushReceiver pushReceiver;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// your onCreate method
pushReceiver = new PushReceiver();
}
public void onResume() {
super.onResume();
// your onResume method
registerReceiver(pushReceiver, new PushReceiver.PushFilter());
}
public void onPause() {
super.onPause();
// your onPause method
unregisterReceiver(pushReceiver);
}
}
In my case, I wrote the PushReceiver constructor to take a View and then "did stuff" with the view in the onReceive method. Without knowing more about what your trying to do, I can't elaborate on this, but hopefully this can provide a decent template to work from.

Categories

Resources