I'm just getting into Android development, and I have a question about communicating between a receiver class and an activity class. I'm very new to JAVA and Android so I hope I don't sound too stupid. I'm developing an application where I intercept an SMS message and then based on various elements of that SMS I might delete it once it's been saved to the inbox. I have a receiver class that intercepts the txt message, and I am also able to delete messages from my inbox with code in the activity class using a button at the moment. The problem I have is communicating between the receiver class and the activity class where the code to delete a message resides. I tried putting that code directly into the receiver class but as I'm sure most of you already know the BroadcastReceiver class doesn't seem to support what I need to delete messages. I've been searching for an answer to this for a while, but haven't been able to find anything. Honestly I'm not sure I know enough about JAVA and Android to even recognize a solution if I saw it.
If you need to complete a job without an interface look into creating a Service, if you need user interface just start an Activity
You can use the Context parameter of the onReceive method of the receiver to start a new service/activity
You can use Extras to pass params between context. So you can put as extra the message id or entire message and pass it to your service/activity and deal it there.
You could implement the handling messages logic using an IntentService. When your receiver gets the new incomming message, start the IntentService passing an intent with the message data.
Receiver
onReceive(Context context, Intent intent) {
//Setup Intent
Intent i = new Intent(context, MyIntentService.class);
i.setAction(MyIntentService.HANDLE_MESSAGE);
//Pass data to intent
i.putExtra(MyIntentService.MESSAGE_DATA, data);
//Start Intent Service
context.startService(i);
}
MyIntentService
onHandleIntent(Intent i){
String action = i.getAction();
if(action != null && action.equals(MyIntentService.HANDLE_MESSAGE){
//Get data and implement message logic
}
}
Hope it helps.
Related
I'm developing an android application, which when user enters licence code, retrieves from web service some simple key-value data and saves to sharedpreferences.
My app also have a service, which starts on separate process and it needs to get a part of previously saved data from sharepreferences.
My main app lets say is in "com.foo.myMainApp" package. And my service is "com.foo.myMainApp/myService".
The problem is, that the service can't access main program's shared prefs, because they are saved in different location.
I'm struggling with this problem for a couple of days and can't find a way out.
Any help would be appreciated.
Use BroadcastReceivers.
in Service
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("ACTION");
broadcastIntent.putExtra("MESSAGE", "hello");
sendBroadcast(broadcastIntent);
In MainACtivity
register this broadcast receiver and your good to go receiving messages.
private class Message extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// get the message here
}
}
// register this onStart
registerReceiver(new Message(),new IntentFilter("ACTION") );
hope this helps :)
Update: GCM is deprecated, use FCM
How to refresh activity on receiving gcm push notification if my app is open. I have an activity which contains listview filled with data from the server. I want to refresh my activity (here adding one more item to listview) , if I receive gcm push notification(which also contains some data).
One alternative is to add timer that periodically do server requests and update the list adapter data but I don't want these because it will take much resources.
Do I need to add broadcast receiver which will trigger on receiving gcm push which further request for newer server data and update my activity UI?
Dear commentors, please read the question carefully, I only need to refresh the list (if app is open and that particular activity is open) else no need for same.
Took me a few hours to figure it out. Posting here in case anyone anyone else has the same problem.
The idea is that you have to register your activity as a broadcast receiver. The easiest way to do this is like so:
//register your activity onResume()
#Override
public void onResume() {
super.onResume();
context.registerReceiver(mMessageReceiver, new IntentFilter("unique_name"));
}
//Must unregister onPause()
#Override
protected void onPause() {
super.onPause();
context.unregisterReceiver(mMessageReceiver);
}
//This is the handler that will manager to process the broadcast intent
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
//do other stuff here
}
};
The above code goes in the activity that you want to 'listen' for events.
Now, how do we send data to this 'listener'? Go to your push notification handler(or from where you want to update your activity) and when you receive a notification call this function:
// This function will create an intent. This intent must take as parameter the "unique_name" that you registered your activity with
static void updateMyActivity(Context context, String message) {
Intent intent = new Intent("unique_name");
//put whatever data you want to send, if any
intent.putExtra("message", message);
//send broadcast
context.sendBroadcast(intent);
}
When you call the above function, your activity should receive it.
Note: Your activity must be running/open to receive the broadcast intent
Note2: I switched to a library called 'otto'. It does actually the same thing but easier, 'broadcasts events' thoughout the app. Here's a link http://square.github.io/otto/
I'm assuming your GCMBroadcastReceiver is in it's own .java file?
As far as refreshing an activity, I would also like to know the answer to that question.
But for knowing if a particular activity is active or not, meaning on screen just add a boolean (call it something like "active") and set it to true in your activity's onResume() event, and to false in the onPause() event:
protected void onResume()
{
super.onResume();
active = true;;
}
protected void onPause()
{
super.onPause();
active = false;
}
Your active variable would be a boolean which is global or static. This way you know if a particular activity is in "front".
Hope that helps a bit.
The accept answer is indeed correct for the "Refreshing activity on receiving gcm push notification" (I've upvoted it too). But if you only want to update a ListView that's being displayed you don't need a broadcast receiver.
Your GCM listener service can update the database using a ContentProvider rather than inserting a direct sql query.
Then you can rely on the notifyChange method on the ContentResolver to do the trick.
Notify registered observers that a row was updated. To register, call
registerContentObserver(). By default, CursorAdapter objects will get
this notification. If syncToNetwork is true, this will attempt to
schedule a local sync using the sync adapter that's registered for the
authority of the provided uri. No account will be passed to the sync
adapter, so all matching accounts will be synchronized.
If your app is already running then try to override the onNewIntent method
Seems there is an easier way. In the OnMessageReceived method of the GCM Listener, you can just do the update from there instead of sending the notification. You can use the same code you would have used if processing the notification. If you're doing StartActivity from the listener, you have to use the ActivityFlags.NewTask flag.
To sum it up in single sentence:
If you want to refresh activity, broadcast your custom event when notification arrives and register your activity as broadcast receiver of that event
Intent notificationIntent = new Intent(context, MainActivity.class);
notificationIntent.setAction(Long.toString(System.currentTimeMillis()));
PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
I'm using a BroadcastReceiver in my Android app which simply contains the following piece of code:
public BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
GcmIntentService.isHandled = true;
Toast.makeText(context, "broadcast receiver test", Toast.LENGTH_SHORT).show();
}
}
I'm using this receiver to determine if my activity is running and carry out some updates in a ListView without having any notifications produced by GcmIntentService.
With the code being simple so far, only creating a toast message, I'm unable to catch the boolean value from GcmIntentService.isHandled as soon as the sendBroadcast is invoked.
Is it possible in any way to determine if the code for my receiver has finished running. I understand that sendBroadcast is an asynchronous call, and I'm making use of Thread.sleep(1000) so far to wait for the isHandled value, but it would be nice if there is a more reliable method on achieving this.
Any thoughts?
Your question can be divided to two parts:
1.How to know that if there is a receiver actually received the broadcast.
2.How should the receiver notify the service that message is been handled.
It seems difficult to achieve the first goal through standard Intent api, instead I suggest you may try the "observer pattern".
You may create a global Observable object in your Application and make your Activity implements Observer, register itself in onCreate() and unRegister in onDestory().Inside the Service you can check if there is an Activity running through countObservers() and then simply notify it.
Is this possible? Currently when I receive a notification OnMessage(Context context, Intent intent) fires, but I'm not able to reference any of my Activities in this context. Is there any way for me to do this? Or do I need the user to click the notification to update the activity and view?
In the OnMessage handler, just execute:
var i = new Intent(this, typeof(MyActivity));
i.SetFlags(ActivityFlags.NewTask);
context.StartActivity(i);
I had a similar problem. You can send a LocalBroadcast inside onMessage. See LocalBroadcast Manager.:
LocalBroadcast Manager is a helper to register for and send broadcasts of Intents to local objects within your process. The data you are broadcasting won't leave your app, so don't need to worry about leaking private data.`
You can send the LocalBroadcast from within the omMessage. Then inside you Activity you can listen to the broadcast which can be with an Intent message. Whenever you receive that local broadcast, you may do the desired action.
See how to use LocalBroadcastManager? on how to implement it. Hope it helps you.
I am developing an android application. This application architecture is divided into 5 modules with 2 modules having multiple features. To develop this app, I am creating 2 process with multiple threads in them as required and 3 other threads. I have a some questions regarding this implementation:
Is this a good model? If not, why not? Right now I am considering only modularity.
I need to send a message from broadcast receiver in process1 to Service thread in process2, what is the best way to do it?
what is the best IPC mechanism in android? I tried to use this link, http://androidapps.org.ua/androidintro_ipc_intent.html which suggests startActivity and startActivityForResult, but these options are not available in broadcast receiver and service does not have startActivityForResult option.
Thank you.
Use Custom BroadcastReceiver
Write this in ActivityA.java
Intent intent = new Intent();
intent.putExtra("message","hi");
intent.setAction("com.android.activity.SEND_DATA");
sendBroadcast(intent);
Write this in ServiceA.java
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
Now register Receiver
LocalBroadcastManager.getInstance(mContext).registerReceiver(mMessageReceiver,
new IntentFilter("com.android.activity.SEND_DATA"));
Just create an Intent in the BroadcastReceiver, add your data as extras, can call startService() with the Intent:
Intent intent = new Intent(context, MyService.class);
intent.putExtra("message", "whatever data you need to pass to the service");
context.startService(intent);
The method onStartCommand() will be called in your service with the passed Intent.
To answer your other question "what is the best IPC method", the answer (as always) is "that depends". Using Intents is the easiest method, as it is supported for all components out-of-the-box. If you need more complicated interaction between components you can look at using AIDL which will allow you to do remote method calls in a Service. If that still isn't enough, then just implement your own socket protocol between the 2 components.
First of all, trying to understand your terminologies. By process, I presume you mean activity and "service thread", I presume you mean a service.
If you want to send a message from onReceive() broadcast receiver, running in context of Activity 1, to a service which is already active, you can try one of the below:
1) Create a new intent (service class name as the class) and call startService() with the intent. Add the additional parameters you need as intent extras. It does not matter if your service is already active, the onStartCommand() is still called, you can have special parameters as intent extras to differentiate a onStartCommand() from onReceive.
2) If your scenario allows this, consider registering to same broadcast event in both your activity and service and act appropriately (then no need to pass messages)
3) Write another broadcast receiver in your service and call sendBroadcast() from the Activity's broadcast receiver