I am bit new to android. I would like to know how to communicate with a foreground started service.
So, I got a Foreground service with a notification.
This notification has a (X) button to stop the service.
The service got a Static broadcastreceiver.
public static class NotificationStopButtonHandler extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"Close Clicked",Toast.LENGTH_SHORT).show();
Log.i(LOG_TAG, "In Closed");
// imposible to do context.stopForground(true) or
// to call any other private coded by me
}
}
So my question is :
Is BroadcastReceiver is the best way ?
If it is : How I can communicate with the service to call stopForeground in the broadcastReceiver ?
Thanks in advance for your responses.
Same question like mien... But I would like to know which are the other solution than broadcastReceiver. thx
In your notification you will have a PendingIntent for the X button. I presume you have built that PendingIntent with
PendingIntent.getBroadcast(/* ... */);
What you can do instead is to create a PendingIntent for your service
Intent intent = /* intent for starting your service */;
intent.putExtra("STOP_FOREGROUND", true);
PendingIntent.getService(context, requestCode, intent, flags);
and in the intent you pass to the PendingIntent you would add an extra (STOP_FOREGROUND). When this intent is fired, your service will get called in onStartCommand(). Here you check the intent and if it contains your extra, you know you're expected to call stopForeground.
Instead of broadcasts, you can use PendingIntent with an Intent to the Service and tell the Service to shut down. You assign the PendingIntent to the close button action and/or to the notifications onDelete call when you build the notification.
Assuming that you're starting the Service with the notification, you can put commands in the Intent to tell the service to stop itself. Service#onStartCommand will be called on the service with the new Intent. The service checks for the shutdown call and calls stopSelf() when done.
Basically, the reason this works is because there can only be one Service started. Every subsequent attempt to start the service will send the intent to Service#onStartCommand, but it will not restart the Service. Thus, this is a way you can send commands to the service through means outside of binding. Plus it's way cleaner than using broadcasts.
Related
This is my requirement.
I have an application which can be force kill by user. I want this application to receive broadcast from other app to execute some task even it is forced kill.
I am trying to make another app with service which will send a broadcast in event 1 mins to my first application.
My first application should receive this broadcast even it is forced kill.
This is what I am trying to do.
in First app:
BroadcastReceiver dummy = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("broadcast Received","broadcast Received");
}
};
IntentFilter filter = new IntentFilter("com.action.blockapp");
registerReceiver(dummy,filter);
In my second app.
Intent intent = new Intent("com.action.blockapp");
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setPackage("com.example.myapplication2");
sendBroadcast(intent);
I am not able to receive the broadcast when my app is forced kill.
Please suggest.
My point . You need to declare revice in the service running in the background. Your specific revice declared in the manifest<receiver android:name=".service.NotifyReceiver" />
</application>
When the service is run. You can get notifications from revice like below
Intent intent1 = new Intent(context, NotifyReceiver.class);
intent1.setAction(action);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
Hope to help you!
You have registered your BroadcastReceiver dynamically, in code. When your app is force stopped, that code is no longer running and your BroadcastReceiver no longer exists. It is no longer registered.
You will need to create a proper class that extends BroadcastReceiver and create a manuifest entry <receiver> for that with an <intent-filter> that matches the broadcast Intent you are broadcasting.
I want notification manager to show a popup which has an 'X' button to close it.
When closed, I want the BroadcastReceiver to invoke a method on the Service which had registered the receiver and notification, and is the container.
RemoteViews remoteView = createPopupView();
Intent intent = new Intent(myService, MyReceiver.class);
intent.setAction(CLOSE_BUTTON_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(myService,
MY_POPUP_ID, intent, 0);
remoteView.setOnClickPendingIntent(R.id.img_close_selector, pendingIntent);
builder.setContent(remoteView);
I found that MyReceiver had to be statically defined in the manifest.
When I tried to dynamically register the receiver, it was not called at all when notification was fired.
But then I also found that my Receiver could not invoke any methods in myService because trying to cast context in onReceive(),
((MyService)context).foo();
or
((MyService) getApplicationContext()).foo()
causes...
AndroidRuntime: java.lang.RuntimeException:
Unable to start receiver com.myco.MyClass$MyReceiver: java.lang.ClassCastException:
android.app.ReceiverRestrictedContext cannot be cast to com.myco.MyService
I suppose I could fire another intent from BroadcastReceiver, but it seems like another relay race - One BroadcastReceiver hooked to another BroadcastReceiver. Also I heard that broadcasts can be delayed.
So how does my BroadcastReceiver communicate with the Service?
When I tried to dynamically register the receiver, it was not called at all when notification was fired.
I am assuming that this Notification is for a foreground service. If so, a dynamically-registered receiver should work, if your Intent matches your IntentFilter, though you may need to call setPackage() on the Intent to get past the implicit broadcast ban on Android 8.0+.
But then I also found that my Receiver could not invoke any methods in myService because trying to cast context in onReceive()
The Context passed to onReceive() will be unrelated to any other component of your app.
So how does my BroadcastReceiver communicate with the Service?
If the Notification should only exist when the service is running, you should switch back to the dynamic registration approach. Or, use a getService() version of PendingIntent to talk directly to your Service. A getService() PendingIntent will trigger onStartCommand() on your Service, and you can put stuff in the Intent to tell you what to do, such as your setAction(CLOSE_BUTTON_ACTION) call. The Intent will need to identify your service instead of identifying a BroadcastReceiver, though.
If the Notification might exist when the service is not running, then either:
Use the getService() PendingIntent that I mentioned above, or
Use startService() from onReceive() of your BroadcastReceiver to start the service (if it is not already started) and trigger onStartCommand() (for you to do whatever it is that you are supposed to be doing)
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
I have some Service class, which registers multiple alarms.
In my BroadcastReceiver class, I want the onReceive() method to call some method of the Service class.
However, I don't see how I can bind them together. I tried to make the BroadcastReceiver an inner class, but then I got more errors and couldn't fire the alarm at all.
Thanks
Look at http://developer.android.com/reference/android/content/BroadcastReceiver.html life cycle. BroadcastReceiver is created only for handling a message. It means that it's life is very short, ant it is also stateless. So you cannot bind anything to it.
Anyway you can try to start a service form onReceive(Context context, Intent intent) method of BroadcastReceiver,
like this:
public void onReceive(Context context, Intent intent) {
Intent intent2 = new Intent(context, GCMService.class);
intent2.putExtras(intent);
context.startService(intent2);
}
Then a=the service should handle a broadcast message.
From the http://developer.android.com/guide/components/bound-services.html
Note: Only activities, services, and content providers can bind to a service - you cannot bind to a service from a broadcast receiver.
I have an app in which the main Activity starts an AlarmReceiver that calls an IntentService that runs in the background and does stuff. I'm unclear on what the correct way is to check on the IntentService's actions and present the end-user with some feedback in the visible Activity that they're in, on the IntentService's current state. In my ideal world there can be an icon somewhere on the screen that I can set to notify the user of what's going on with the IntentService. I don't need the user to be able to *do anything, just have feedback.
All advice welcome.
Android has a notification API, which is even easy to use - Creating Status Bar Notifications.
If you want your activity to receive updates from the service, I would suggest using broadcasts and broadcast receivers.
How to send a broadcast intent:
Intent i = new Intent("your.action");
sendBroadcast(i);
To receive this broadcast within your activity, you have to implement a broadcast receiver:
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//
}
};
which you have to register...
registerReceiver(myReceiver, new IntentFilter("your.action"));