How better send data from BroadcastReceiver to Activity? - android

I wan catch SMS in my app and show it o my view. I create BroadcastReceiver:
public class SMSMonitor extends BroadcastReceiver {
private static final String ACTION = "android.provider.Telephony.SMS_RECEIVED";
#Override
public void onReceive(Context context, Intent intent) {
if (intent != null && intent.getAction() != null && ACTION.compareToIgnoreCase(intent.getAction()) == 0) {
Object[] pduArray = (Object[]) intent.getExtras().get("pdus");
SmsMessage[] messages = new SmsMessage[pduArray.length];
for (int i = 0; i < pduArray.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pduArray[i]);
}
StringBuilder bodyText = new StringBuilder();
for (SmsMessage message : messages) {
bodyText.append(message.getMessageBody());
}
String body = bodyText.toString();
Toast.makeText(context, body, Toast.LENGTH_LONG).show();
abortBroadcast();
}
}
}
And it show Toast wuth SMS body. Now i dont know what should I do
Create Service and pass SMS to service. And get SMS from service
Use Otto observer and send data(SMS) from:
1. BroadcastReceiver
2. Service
and catch in my activity.
Another more correct way
And if I will use Otto (I want it) where better send data - from BroadcastReceiver or pass data to service and send otto message from Service?

Otto or EventBus is for me the most simple solution and the solution that will reflect best your Activity lifecycle.
A great start is to register/unregister your bus from onPause() and onResume like so :
#Override
public void onResume() {
super.onResume();
BusProvider.getInstance().register(this);
}
#Override
public void onPause() {
super.onPause();
BusProvider.getInstance().unregister(this);
}
Next, post an event from your BroadcastReceiver like BusProvider.getInstance().post(new SmsEvent());
Your fragment or Activity will received the event via the #Subscribe method and the SmsEvent parameter type of the method.
It seems you don't need any Service here except if you want to save the data when the activity is not open.

Related

How to implement callback listener in BroadcastReceiver onReceive on notification tap?

I am creating an app that sends a notification when an SMS is received. When the notification is tapped, it opens the MainActivity and shows the received SMS. The problem is, when the app is closed and an SMS is received, the mListener inside the onReceive method of BroadcastReceiver class produces a null pointer exception (NPE). Logs show the error: "Attempt to invoke interface method 'void com.example.smsread.listener.SmsListener.messageReceived(java.lang.String)' on a null object reference".
What can I do so that the control can be passed to the activity from onReceive?
I can perform the action sending notification within the onReceive but doesn't seem appropriate. I wish to pass the message to the interface and let the activity implement it.
SmsReceiver.java
public class SmsReceiver extends BroadcastReceiver {
//interface
private static SmsListener mListener;
public static void bindListener(SmsListener listener) {
mListener = listener;
}
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
Object[] pdus = new Object[0];
if (bundle != null) {
pdus = (Object[]) bundle.get("pdus");
}
StringBuilder messageBody = new StringBuilder();
if (pdus != null) {
for (Object pdus1 : pdus) {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdus1);
messageBody.append(smsMessage.getMessageBody());
}
}
//Pass the message text to interface
mListener.messageReceived(messageBody.toString()); // mListener here is null
}
}
I expect the mListener to pass the control to the MainActivity where the interface is implemented but mListener is found to be null. Please help as to what changes have to be done so that mListener points to the MainActivity.
If there is a better way to implement the scenario I wish to implement, suggestions are more than welcome.
Thanks in advance :)
You are trying to call function of an Activity that was already destroyed.
If you want to communicate with your activity from a BroadcastReceiver, Use Intent.
Create a new Intent with your Activity as target and send the message as as Extra in Intent Extras Bundle.
In your Activity, you can set launchMode to singleInstance or singleTask in your manifest file. This means that the Intent if sent and your Activity is already open, it will call onIntent function in your activity where you will call the listener function.
android:launchMode="singleInstance"
#Override
public void onNewIntent(Intent intent){
super.onNewIntent(intent);
processDataFromBroadcast(intent);
}
Be sure to read about launch modes and singleInstance to fully understand what it means or you might get unexpected behavior:
https://developer.android.com/guide/components/activities/tasks-and-back-stack#ManifestForTasks

send data from a broadcast to an activity . how to do send?

how to send data from a broadcatReceiver to an activity in android as saying catch the received SMS and send the SMS (is the data) to the activity its my first time that i work with broadcatReceiver so can anyone help me i will appreciate any help.
i read several tutorials about the data transferring that have some steps :
create a class that extends activity
create a class that extends broadcastReceiver
but i did not know how is the communication between these 2 classes.
I would do something like that:
public class YourActivity extends Activity
{
private Handler handler = null;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.id.main_layout);
this.handler = new Handler() {
#Override
public void handleMessage(Message msg)
{
SmsMessage sms = (SmsMessage) msg.obj;
String senderNumber = sms.getOriginatingAddress();
}
};
// Register a new receiver that will trigger on SMS_RECEIVED event
IntentFiler filer = new IntentFilert("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(mSmsReceiver, filter);
}
#Override
protected void onDestroy()
{
super.onDestroy();
// Unregister the receiver
unregisterReceiver(mSmsReceiver);
}
private mSmsReceiver = new BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
Bundle bundle = intent.getExtras();
if (bundle == null || bundle.containsKey("pdus") return;
// Decode the message
SmsMessage sms = SmsMessage.createFromPdu((byte[]) pdus[0]);
// Notify the activity with the message
Message msg = new Message;
msg.obj = sms;
YourActivity.this.handler.sendMessage(msg);
}
};
}
The receiver and the Activity are separate entities and do not usually interact directly. Imagine the following scenario: you have a receiver getting lots of SMS messages, and every time you get one, you launch an Activity to show the message received. Wouldn't this be very annoying to the user?
I'd says that you can interact with the user by creating a Notification and if the user clicks on it, then you open the Activity you want to show the details.
As how to pass the data to the Activity (hopefully using a notification first), given that SMS messages are short in nature you can just put the data in the Intent.
How to set a Notification to launch an Activity: see Open application after clicking on Notification

How to read sms using Service

I am receiving sms using Broadcast Receiver.It is working fine. Now I want to read sms from inbox using service, (which is received by broadcast receiver).
I want to retreive sms from inbox using SERVICE. SMS retreival must be happen in background not in main thread.No any Activity should be used.
//Broadcast receiver to receive sms and starting a service via intent
public class SMSReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
SmsMessage[] message = null;
String str = "";
if(bundle != null){
Object[] pdus = (Object[])bundle.get("pdus");
message = new SmsMessage[pdus.length];
for(int i = 0; i<message.length; i++){
message[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
str += "New SMS from cloudy contacts " + message[i].getOriginatingAddress();
}
Toast.makeText(context, str, Toast.LENGTH_LONG).show();
Intent intent1 = new Intent(context,MyService.class);
context.startService(intent1);
}
}
}
Servie
public class MyService extends Service{
ReadSMS readSMS;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
public void onCreate(Bundle savedInstanceState){
Log.d("Service","inside onCreate of service");
}
public void onDestroy(){
Log.d("Service", "destroyed");
}
public void onStart(){
Log.d("Service","starting service to read sms from inbox");
Toast.makeText(this,"Reading sms from inbox",Toast.LENGTH_LONG).show();
readSMS = new ReadSMS();
ArrayList list = readSMS.readSms("inbox");
}
public class ReadSMS{
public ArrayList readSms(String inbox){
ArrayList sms = new ArrayList();
Uri uri = Uri.parse("content://sms/inbox");
Cursor cursor = getContentResolver().query(uri, new String[]{"_id","address","date","body"},null,null,null);
cursor.moveToLast();
String address = cursor.getString(1);
String body = cursor.getString(3);
sms.add(address+" "+body);
return sms;
}
}
}
The Messages in the inbox wouldn't be received by a broadcast receiver since it's not a broadcast. You will have to read the native database on the device.
Take a look here
EDIT:
First of all, doing something from a Service doesn't automatically spawn a background thread. The service will run on the main thread.
Caution: A service runs in the main thread of its hosting process—the service does not create its own thread and does not run in a separate process (unless you specify otherwise). This means that, if your service is going to do any CPU intensive work or blocking operations (such as MP3 playback or networking), you should create a new thread within the service to do that work. By using a separate thread, you will reduce the risk of Application Not Responding (ANR) errors and the application's main thread can remain dedicated to user interaction with your activities.
Then you can of course spawn a thread yourself, or use an IntentService. But start by reading here.

How to send data to a running activity from Broadcast Receiver,

I am able to receive C2DM message fine but I want to send the data to a running activity, i.e when the activity is running, if the receiver receives C2DM message it is to send the data to the running activity. The code of receiver is (no bugs in the code):
public class C2dmreceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.w("C2DM", "Message Receiver called");
if ("com.google.android.c2dm.intent.RECEIVE".equals(action))
{
final String payload = intent.getStringExtra("key1");
Log.d("C2DM", "message = " + payload );
}
}}
I have tried like this inside the activity in an attempt to register the receiver in the activity so that the receiver can send data and the running activity can receive the data :-
C2dmreceiver c2dmr = new C2dmreceiver();
Registration.this.registerReceiver(c2dmr, new IntentFilter());
I don't know what to put inside the IntentFilter(), also what else I have to put in the code of the activity and the code of the receiver so that while the activity is running and some C2DM message comes the receiver can send the data to the running activity.
So, please tell me the code that is to put in the activity and in the receiver and may also be in the manifest so that the data from the receiver could be send to running activity.
Any advice is highly appreciated.
First of all it's not the best idea to subscribe c2dm receiver in activity. Do it in manifest. For passing data to activity you can create static string field in Activity and set you String there.
You can do something like this:
in Activity
public static YourActivity mThis = null;
#Override
protected void onResume() {
super.onResume();
mThis = this;
}
#Override
protected void onPause() {
super.onPause();
mThis = null;
}
In your BroadcastReceiver:
#Override
public void onReceive(Context context, Intent intent) {
...
if (YourActivity.mThis != null) {
((TextView)YourActivity.mThis.findViewById(R.id.text)).setText("received c2dm");
}
else {
...
}

Is it possible to receive SMS message on appWidget?

Is it possible to receive SMS message on appWidget?
I saw android sample source(API Demos).
In API Demos, ExampleAppWidgetProvider class extends AppWidgetProvider, not Activity.
So, I guess it is impossible to regist SMS Receiver like this,
rcvIncoming = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("telephony", "SMS received");
Bundle data = intent.getExtras();
if (data != null) {
// SMS uses a data format known as a PDU
Object pdus[] = (Object[]) data.get("pdus");
String message = "New message:\n";
String sender = null;
for (Object pdu : pdus) {
SmsMessage part = SmsMessage.createFromPdu((byte[])pdu);
message += part.getDisplayMessageBody();
if (sender == null) {
sender = part.getDisplayOriginatingAddress();
}
}
Log.i(sender, message);
}
}
};
registerReceiver(rcvIncoming, new IntentFilter("android.provider.Telephony.SMS_RECEIVED"));
My goal is to receive SMS message on my custom appWidget.
Any help would be appreciated!!
AppWidgetProvider is a derived class of BroadcastReceiver. Therefore, you can override onReceive() to handle SMS message. Of course, you have to setup intent filter for SMS_RECEIVED in the manifest correctly first.

Categories

Resources