Null Local Variable in Overridden OnReceive - java

I initialize the interface SMSListener in my MainActivity's onCreate but it is null in my overridden onReceive function. Am I incorrectly using the public interface variable in my onReceive? I have properly initialized the variable whenever I have tested it outside of the overridden function.
SmsReceiver:
public class SmsReceiver extends BroadcastReceiver {
public interface OnCustomReceiveSMS {
void OnReceiveSMS(String inNumber, String inText);
}
public OnCustomReceiveSMS SMSListener;
//constructor
public SmsReceiver(){
this.SMSListener = null;
}
//register sms listener
public void SetCustomEventListener(OnCustomReceiveSMS eventListener){
this.SMSListener = eventListener;
this.SMSListener.OnReceiveSMS("test1", "test2");
}
#Override
public void onReceive(Context context, Intent intent) {
//THIS IS ALWAYS FALSE EVEN AFTER INITIALIZED
if(this.SMSListener != null){
Toast.makeText(context, "SMSListener is NOT null", Toast.LENGTH_SHORT).show();
this.SMSListener.OnReceiveSMS("test3", "test4");
}else{
Toast.makeText(context, "SMSListener is NULL", Toast.LENGTH_SHORT).show();
}
}
}
MainActivity:
public class MainActivity extends AppCompatActivity {
SmsReceiver smsReceiverObj;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//initialize SMS receiver and register event listener
this.smsReceiverObj = new SmsReceiver();
this.smsReceiverObj.SetCustomEventListener(new SmsReceiver.OnCustomReceiveSMS() {
#Override
public void OnReceiveSMS(String inNumber, String inText) {
Toast.makeText(getApplicationContext(), "test event listener fired", Toast.LENGTH_SHORT).show();
}
});
}
}
The first test in SetCustomEventListener (test1, test2) works just fine immediately after initializing the interface variable. When I try using it in onReceive function later I always get the "SMSListener is NULL" debug message.

The problem might be a sticky broadcast, which will call onReceive method before you even setCustomEventListener, better way to do it is to initialize it in constructor
public class SmsReceiver extends BroadcastReceiver {
public interface OnCustomReceiveSMS {
void OnReceiveSMS(String inNumber, String inText);
}
public OnCustomReceiveSMS SMSListener;
//constructor
public SmsReceiver(OnCustomReceiveSMS eventListener){
this.SMSListener = eventListener;
this.SMSListener.OnReceiveSMS("test1", "test2");
}
#Override
public void onReceive(Context context, Intent intent) {
//THIS IS ALWAYS FALSE EVEN AFTER INITIALIZED
if(this.SMSListener != null){
Toast.makeText(context, "SMSListener is NOT null", Toast.LENGTH_SHORT).show();
this.SMSListener.OnReceiveSMS("test3", "test4");
}else{
Toast.makeText(context, "SMSListener is NULL", Toast.LENGTH_SHORT).show();
}
}
}
And in your activity
this.smsReceiverObj = new SmsReceiver(new SmsReceiver.OnCustomReceiveSMS() {
#Override
public void OnReceiveSMS(String inNumber, String inText) {
Toast.makeText(getApplicationContext(), "test event listener fired", Toast.LENGTH_SHORT).show();
}
});
EDIT
Problem is you are trying to register it in Manifest, remove receiver from manifest and register it inside the MainActivity , It will work like a charm
this.smsReceiverObj = new SmsReceiver(new SmsReceiver.OnCustomReceiveSMS() {
#Override
public void OnReceiveSMS(String inNumber, String inText) {
Toast.makeText(getApplicationContext(), "test event listener fired", Toast.LENGTH_SHORT).show();
}
});
registerReceiver(this.smsReceiverObj,new IntentFilter());

Related

How to create event listener when message from firebase received in android?

I am using firebase to receive messages. When message received (onMessageReceived()). I want to check whether the message contains required string (say "hello"). If yes, i want it to be known to another fragment, so that some method in fragment will be called based on message.
For this i want to create event listener when message received.
In my fragment, two APIs will be called. on API will be called onCreatedView().
based on message from firebase , second API should be called.
The two API calls should be done within fraction of milliseconds.
MyFireBaseMessage.java
public class MyMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.d("message here","message here "+ remoteMessage.getData().toString());
String value = remoteMessage.getData().get("msg");
Log.d("value here","value here"+" "+value);
if (value.equalsIgnoreCase("hello"))
{
//implement custom event listener here
}
}
}
One way I can think of right now is using LocalBroadcast. to do this
Amend your Firebase service and put this content
public class MyMessagingService extends FirebaseMessagingService {
private LocalBroadcastManager broadcaster;
#Override
public void onCreate() {
broadcaster = LocalBroadcastManager.getInstance(this);
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.d("message here", "message here " + remoteMessage.getData().toString());
String value = remoteMessage.getData().get("msg");
Log.d("value here", "value here" + " " + value);
if (value.equalsIgnoreCase("hello")) {
Intent intent = new Intent("custom-listener");
broadcaster.sendBroadcast(intent)
}
}
}
Make changes in your fragment class
public class BlankFragment extends Fragment {
Context context;
BroadcastReceiver br;
public BlankFragment() {
// Required empty public constructor
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
#Override
public void onResume() {
super.onResume();
setup();
}
#Override
public void onDestroyView() {
super.onDestroyView();
LocalBroadcastManager.getInstance(context).unregisterReceiver(mMessageReceiver);
}
private void setup() {
LocalBroadcastManager.getInstance(context).registerReceiver(mMessageReceiver,
new IntentFilter("custom-listener"));
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
}
with broadcasts you will be able to listen to the event you want to. The onReceive method inside the Fragment class will get fired when your if condition is true i.e. value.equalsIgnoreCase("hello")
Apologies for the formatting of this answer. having difficulties adjusting it.
Please try this, if hello is key in message format
if (remoteMessage.getData().containsKey("hello")) {
}
Or if hello is as message string, then try this
Map<String, String> params = remoteMessage.getData();
JSONObject fullObject = new JSONObject(params);
String messageString = fullObject.getString("msg");
Hope it works!!
For this use the Local broadcast receiver in your app
example:
in notification screen use the receiver like this
#Override
public void onMessageReceived(RemoteMessage remoteMessage)
{
super.onMessageReceived(remoteMessage);
Log.d("message here", "message here " + remoteMessage.getData().toString());
String value = remoteMessage.getData().get("msg");
Log.d("value here", "value here" + " " + value);
if (value.equalsIgnoreCase("hello"))
{
Intent intent = new Intent("custom-listener");
broadcaster.sendBroadcast(intent)
}
}
and in fragment register broadcast receiver in onResume method like this
getActivity().registerReceiver(broadcastReceiver, new IntentFilter("custom-listener"));
also unregister the receiver in onPause nethod
getActivity().unregisterReceiver(broadcastReceiver);
and create broadcast receiver method in fragment where you can call the api , like this
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
};

Passing Data to MainActivity after receiving notification with AppNotificationReceiver

Receiving a notification in NotificationReceiver class that includes my data string. However, when trying to pass that string to a class in MainActivity I'm not getting any data. No errors either.
NotificationReceiver
#Override
public void onReceive(Context context, AppNotification notification) {
Toast.makeText(context, notification.payload, Toast.LENGTH_SHORT).show();
if (notification.appEvent.equals(NOTIFICATION_ACTION)) {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("orderId", notification.payload);
context.startActivity(intent);
}
}
MainActivity
public void onNewIntent(Intent intent) {
Toast.makeText(mContext, "Hitting New Intent", Toast.LENGTH_SHORT).show();
}
protected void onHandleIntent(Intent intent) {
Toast.makeText(getApplicationContext(), "New Order Received!", Toast.LENGTH_LONG).show();
new OrderAsyncTask().execute(intent.getStringExtra("orderId"));
}
The expected result is to receive my string in either onHandleIntent or onNewIntent
UPDATED
MainActivity Class Example:
public class MainActivity extends Activity {
public final static String EXTRA_PAYLOAD = "payload";
public String orderId = null;
#SuppressLint("StaticFieldLeak")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = getIntent();
onNewIntent(intent.getStringExtra("orderId"));
}
#Override
protected void onResume() {
super.onResume();
Intent intent = getIntent();
onNewIntent(intent.getStringExtra("orderId"));
}
public void onNewIntent(String orderId) {
if(orderId != null) {
Toast.makeText(MainActivity.this, "List order " + orderId, Toast.LENGTH_LONG);
} else {
Toast.makeText(MainActivity.this, "Value is null", Toast.LENGTH_LONG);
}
}
}
The methods you are trying to get the caller intent on are not overridden from anything. I suggest you to try getting the intent and processing data on activity's onCreate method
Intent intent = getIntent();
new OrderAsyncTask().execute(intent.getStringExtra("orderId"));
Also suggest you to change
public String orderId = null;
into
public String mOrderId = null;
Or just remove it because it might get mixed up with other orderId variable on your
onHandleIntent(String orderId)
method
Edit: Since you want to pass data from notification receiver to your mainActivity while the activity is running, I would suggest you to register the receiver inside your MainActivity
Please see this link, example of such design with Clover SDK https://github.com/clover/clover-android-sdk/blob/master/clover-android-sdk-examples/src/main/java/com/clover/android/sdk/examples/AppNotificationTestActivity.java
From the code:
private String orderId;
private AppNotificationReceiver receiver = new
AppNotificationReceiver() {
#Override
public void onReceive(Context context, AppNotification notification) {
log("Received " + notification);
orderId = notification.payload();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Register the receiver to your mainActivity
receiver.register(this);
}
#Override
protected void onDestroy() {
super.onDestroy();
receiver.unregister();
}
You can directly get orderId into your MainActivity like this

how to send data from background service to activity?

i try almost code in the internet, but i can't solve it.
i want to send data from specific method in the service to activity.
i use intent(putExtra), but it doesn't go to activity class.
here is my RecoBackgroundRangingService.java
(i omit unnecessary code)
private static final String TAG = "RecoBackgroundRangingService";
public static final String BROADCAST_ACTION = "com.example.hello ";
private final Handler handler = new Handler();
Intent intent;
int counter = 0;
#Override
public void onCreate() {
Log.i("BackRangingService", "onCreate()");
super.onCreate();
intent = new Intent(BROADCAST_ACTION);
Toast.makeText(getBaseContext(),"on create", Toast.LENGTH_SHORT).show();
}
#Override
public void didEnterRegion(RECOBeaconRegion region, Collection<RECOBeacon> beacons) {
/**
* For the first run, this callback method will not be called.
* Please check the state of the region using didDetermineStateForRegion() callback method.
*
//Get the region and found beacon list in the entered region
Log.i("BackRangingService", "didEnterRegion() - " + region.getUniqueIdentifier());
this.popupNotification("Inside of " + region.getUniqueIdentifier());
//Write the code when the device is enter the region
DisplayLoggingInfo();
Toast.makeText(getBaseContext(),"did enter region", Toast.LENGTH_SHORT).show();
//this.startRangingWithRegion(region); //start ranging to get beacons inside of the region
//from now, stop ranging after 10 seconds if the device is not exited
}
private void DisplayLoggingInfo() {
//Log.d(TAG, "entered DisplayLoggingInfo");
//intent.putExtra("time", new Date().toLocaleString());
//intent.putExtra("counter", String.valueOf(++counter));
intent.putExtra("status", 1);
sendBroadcast(intent);
Toast.makeText(getBaseContext(),"display logging", Toast.LENGTH_SHORT).show();
}
here is my CheckActivity.java
(when i receive data, my purpose is that store data to the server. therefore, i don't need to use layout. So, in order to check data, i use toast "hello". but toast never popup my phone...)
public class CheckActivity extends Activity {
private static final String TAG = "CheckActivity";
private Intent intent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_check);
intent = new Intent(this, RecoBackgroundRangingService.class);
Toast.makeText(getBaseContext(), "check activity", Toast.LENGTH_SHORT).show();
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateUI(intent);
}
};
#Override
public void onResume() {
super.onResume();
startService(intent);
registerReceiver(broadcastReceiver, new IntentFilter(RecoBackgroundRangingService.BROADCAST_ACTION));
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
stopService(intent);
}
private void updateUI(Intent intent) {
int status = intent.getIntExtra("status", -1);
Toast.makeText(getBaseContext(), "hello", Toast.LENGTH_SHORT).show();
}
}

Communication between Activity and GCMListenerService Android

I am working on an android application with push notification feature using GCM. I have created a class called PushNotificationService which extends GCMListenerService. Inside the onMessageReceived(String from, Bundle data) I am able to get the message in the push notification.
Now, I want to access a method inside my MainActivity class whenever a particular message is received in the push.
Below is my code :-
PushNotificationService.java
public class PushNotificationService extends GcmListenerService {
#Override
public void onMessageReceived(String from, Bundle data) {
// TODO Auto-generated method stub
super.onMessageReceived(from, data);
String message = data.getString("message");
if(message.equalsIgnoreCase("Begin Task"))
{
//call method from MainActivity.class
}
}
}
MainActivty.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void beginTask()
{
Log.d("GCM","Message Received from Server");
finish();
}
}
I want the beginTask() method to execute whenever the message "Begin Task" is received.
I know one approach is via Service->Interface->Activity architecture but I am not able to use this as I never create an object of PushNotificationService.
Please help.
UPDATE :-
I am now using Otto Library and below is my code.
Added new MyBus.java
public class MyBus extends Bus {
private static Bus bus;
//isRegistered is used to track the current registration status
private static boolean isRegistered;
private Handler handler = new Handler(Looper.getMainLooper());
public MyBus() {
if (bus == null) {
//ANY will allow event bus to run even with services
//and broadcast receivers
bus = new Bus(ThreadEnforcer.ANY);
}
}
#Override
public void register(Object obj) {
//The bus is registered when an activity starts
bus.register(obj);
isRegistered = true;
}
#Override
public void unregister(Object obj) {
//The bus is unregistered when an activity goes to background
bus.unregister(obj);
isRegistered = false;
}
#Override
public void post(final Object event) {
if (Looper.myLooper() == Looper.getMainLooper()) {
//post the event in main thread or background thread
bus.post(event);
} else {
handler.post(new Runnable() {
#Override
public void run() {
bus.post(event);
}
});
}
}
public boolean isRegistered(){
return isRegistered;
}
}
PushNotificationService.java
public class PushNotificationService extends GcmListenerService {
#Override
public void onMessageReceived(String from, Bundle data) {
// TODO Auto-generated method stub
super.onMessageReceived(from, data);
MyBus myBus = new MyBus();
myBus.register(myBus);
String message = data.getString("message");
if(message.equalsIgnoreCase("Begin Task"))
{
myBus.post(message);
}
}
}
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Subscribe
public void beginTask()
{
Log.d("GCM","Message Received from Server");
}
}
The problem is still not solved. The beginTask() inside MainActivity.java is still not getting called.
Use eventBus libraries to facilitate this process...
I use Otto for this process
http://square.github.io/otto/
Here is an another eventBus library https://greenrobot.github.io/EventBus/
Steps:
1.Create an event from the service
2.Add a listener in the activity
3.If the activity is running the method will be executed
**EDIT 1 : **
I have abstracted the otto bus like this.
package com.mypackage.eventBus;
import android.os.Handler;
import android.os.Looper;
import com.squareup.otto.Bus;
import com.squareup.otto.ThreadEnforcer;
/**
* Created by gowtham on 10/6/15.
*/
public class MyBus extends Bus {
private static Bus bus;
//isRegistered is used to track the current registration status
private static boolean isRegistered;
private Handler handler = new Handler(Looper.getMainLooper());
public MyBus() {
if (bus == null) {
//ANY will allow event bus to run even with services
//and broadcast receivers
bus = new Bus(ThreadEnforcer.ANY);
}
}
#Override
public void register(Object obj) {
//The bus is registered when an activity starts
bus.register(obj);
isRegistered = true;
}
#Override
public void unregister(Object obj) {
//The bus is unregistered when an activity goes to background
bus.unregister(obj);
isRegistered = false;
}
#Override
public void post(final Object event) {
if (Looper.myLooper() == Looper.getMainLooper()) {
//post the event in main thread or background thread
bus.post(event);
} else {
handler.post(new Runnable() {
#Override
public void run() {
bus.post(event);
}
});
}
}
public boolean isRegistered(){
return isRegistered;
}
}
create an instance of the above object and try posting event
EDIT 2 for Jcarlo's comment
Follow these steps to find the state of the activity.
In your activity's onResume call MyBus.getInstance().register(this).
In your activity's onPause call MyBus.getInstance().unregister(this).
In your GCM IntentService before posting the message
if(MyBus.getInstance().isRegistered()){
//app is alive
//post data
}else{
//show notification
}
Hope this helps
You can use LocalBroadcastManager. Create a LocalBroadcastManager object mBroadcaster = LocalBroadcastManager.getInstance(this); on onCreate of your GCMListener and send broadcast with
#Override
public void onCreate() {
super.onCreate();
mBroadcaster = LocalBroadcastManager.getInstance(this);
}
#Override
public void onMessageReceived(String from, Bundle data) {
super.onMessageReceived(from, data);
String message = data.getString("message");
if(message.equalsIgnoreCase("Begin Task")) {
Intent i = new Intent();
i.setAction("yourPackageName");
i.putExtra("DATA", yourData);
mBroadcaster.send(i);
}
}
Then you can receive message in MainActivity using a BroadcastReceiver.
BroadCastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
beginTask();
}
};
Also you need to register and unregister the receiver in onStart and onStop of your activity
#Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter();
filter.addAction("yourPackageName);
LocalBroadcastManager.getInstance(this).registerReceiver((mBroadcastReceiver), filter);
}
#Override
protected void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
}

Register BroadcastReceiver in non-activity class

I have to use a BroadcastReceiver in a class that I will have to call in an Activity. Obviously, I have to necessarily register the BroadcastReceiver and then I wrote this code:
public class MyClassName {
Context context;
BroadcastReceiver batteryInfoReceiverLevel;
public void CheckBatteryLevel() {
Log.d("App", "I'm in the CheckBatteryLevel");
context.registerReceiver(batteryInfoReceiverLevel, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
batteryInfoReceiverLevel = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Apps", "I'm in the onReceive");
int level= intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0);
if(level <=100) {
//Do something
}
else if(level >=100) {
//Do something
}
}
};
}
}
When I run the code the application crashes giving "Error receiving broadcast Intent { act=android.intent.action.BATTERY_CHANGED flg=0x60000010 (has extras) } and the crash line is
context.registerReceiver(batteryInfoReceiverLevel, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
How can i fix?
There are two problems here:
ρяσѕρєя K has pointed out the first one:
Initialize your context by adding a parameter to the method CheckBatteryLevel() or to the constructor
of MyClass
public class MyClass(Context ctx) {
context = ctx;
}
Second, you have to call registerReceiver(..) AFTER you have initialized the BroadcastReceiver. Or it will be null and not registered.
All in all this should do it:
public class MyClassName {
BroadcastReceiver batteryInfoReceiverLevel;
public void CheckBatteryLevel(Context ctx) {
Log.d("App", "I'm in the CheckBatteryLevel");
batteryInfoReceiverLevel = new BroadcastReceiver() { // init your Receiver
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Apps", "I'm in the onReceive");
int level= intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0);
if(level <=100) {
//Do something
} else if(level >=100) {
//Do something
}
}
};
// register your Receiver after initialization
ctx.registerReceiver(batteryInfoReceiverLevel,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
}
application crashes giving "Error receiving broadcast Intent
Because context is null you should need to initialize context before calling registerReceiver. for initialization use Class constructor or pass to CheckBatteryLevel method from calling Activity. :
public void CheckBatteryLevel(Context aContext) {
context =aContext;
//....your code here...
}

Categories