android service, broadcast and activity - android

Current I have three classes: activity (A), broadcastReceiver (B) and service (C).
Assuming that A is binding to C and now, B get a new intent from system.
Can B bind to the C (exactly the same one) directly?
I find out that there is a peekService method in broadcastReceiver.
my question is can I bind the running service in broadcastReceiver?

If you have registered your receiver dynamically with Context.registerReceiver() then you can bind to a Service from the onReceive method.
However, If you have declared your BroadcastReceiver in the manifest, then you should not bind to a Service from the onReceive() method. You can start a Service though - you just cannot bind to it because bindService() is asynchronous. More details about this in the Android Dev Guide and the onReceive documentation.

I find out that using peekService can bind the running service.
Such like
IBinder ib = peekService(context, new Intent(context,
xxxxService.class));
((xxxxService.class)ib). do anything here...

Related

How can BroadcastReceiver communicate with Service when ReceiverRestrictedContext cannot be cast to MyService?

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)

Send broadcast intent from service to Application Class

Is it possible to send an intent from a service to an Application class? Not Activity?
I wouldn't know what activity would be running at a particular time, so I am adding a boolean flag in the activity class that detects the activity and sends the appropriate data based on the broadcast received.
If your Service is active, then your Application class is active as well.
Otherwise you wouldn't be able to use getApplicationContext().
Although I'm skeptic about a service that runs forever there is a very clean way to make the Service communicate with a certain Activity, should the last one be currently active.
Such clean way is called LocalBroadcastManager.
The Activity meant to receive the data should register a BroadcastReceiver in onResume() and unregister it in onPause().
You instantiate your BroadcastReceiver in your Activity's onCreate()
this.localBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Do what you have to do here if you receive data from the Service.
}
}
You create a Filter so your Activity only listens to a certain type of signals.
private IntentFilter notifIntentFilter new IntentFilter("com.you.yourapp.MY_SIGNAL");
in onResume()
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, notifIntentFilter);
in onPause()
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
Now whenever you want to send data to your Activity, your Service can call:
final Intent intent = new Intent();
intent.setAction("com.you.yourapp.MY_SIGNAL");
// put your data in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
If your Activity is awake, it will respond to the signal. Otherwise, if it's in the background, or it is not instantiated it won't.
You can apply this pattern to as many Activities as you wish.
Still, I have never used this inside the Application class. But you can try to register your receiver there. It might work, since if the Application class is destroyed, the BroadcastReceiver is destroyed too and thus probably unregistered as well.
The point is, if your Application gets destroyed, your Service will be killed as well. Unless you launched it in another process. But then it will have it's own instance of Application; and this is a complex thing you probably do not want to get into details now...
Important: since the Application class is not tied to any UI component, you can do whatever you need directly inside your service. If you need to manipulate the UI, then the pattern described above will work for you.
Please read about new Android's background limitations.
Edit:
Oh yeah right, if you need your Service to call a function declared in your Application class, you can just do
((MyApplication) getApplication()).myFunctionToHandleData(Intent intent);
I didn't really understand your question though, but either of the methods described above should work for you.

How to avoid broadcast from being wasted when receiver is registered inside activity?

I have a service which will broadcast a message to broadcast receiver which is registered in some activity. The activity might be running or not. If it's open then broadcast will be received. But if not, the broadcast will be wasted. Is there a way to avoid this broadcast from being wasted without adding the broadcast inside manifest?
Consider to start/stop that service based on Activity's lifecycle, when Activity is created (onCreate()) start that service. When Activity is destroyed (onDestroy()) stop the service so you avoid "waste" those messages and even have a service running.
1- Create an inner class in your activity that extends BroadcastReceiver.
2- Create an object of your receiver and an intent filter.
3- Override onResume and registerReceiver(receiver, intentFilter);
4- Override onPause and unregisterReceiver(receiver);
Take a look at this answer. you dont have to add it in the manifest.
answer here

After moving BluetoothActivity into service class.How to send data to service from another activity to control led

I'm using service to run Bluetooth in background,but i don't no how to send data from another activity to service
Service and other activities work in the same process
To start a Service, use following statement:
Intent intent = new Intent(context, Service.class);
// intent put some extra
startService(intent);
Calling this statement firstly, Service call onCreate() method and onStartCommand().
Not firstly, Service just call onStartCommand().
You can check if it is called firstly by extra in intent.
So you can send data with the same method startService(Intent intent).
Service works in another process
use [bindService](https://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int)) and AIDL
It is suggested that make service and other activities work in the same process when your target is not complex.

how to contact a service's method from a notification?

I am implementing a music player. The notifications allow the user to pause or skip a song.
I use
Intent i = new Intent("com.package.app");
mExpandedView.setOnClickPendingIntent(R.id.next_song, PendingIntent.getBroadcast(this, 0, i, 0));
In order to transmit this click to the MusicService that hosts the MediaPlayer and all the associated methods. I would like to directly call a method part of this service (playNextSong() for example) but getService() seems to only allow me to launch a new service, not to call a method in the service, or get some data. I don't even need to launch the service, since the music is playing, it is already running.
So is there a way to do this that I am not aware of ?, or is :
Notification broadcasts to BroadcastReceiver, then BroadcastReceiver broadcasts to the service the recommended way do accomplish this action ?
It looks like a convoluted way to do something simple...
Create PendingIntent for notification as broadcast message, custom one (use your own string like com.my.custom.broadcast.message.action). Create and register in AndroidManifest new broadcast receiver that will be fired by this custom action. OnReceive method of the Broadcast receiver, start your service with custom arguments/action or whatever, based on class of Service and context arguments passed into onReceive method.
Probably you can try to directly start service by creating PendingIntent for that, but I think it is better do it through middle-step: BroadcastReceiver
From the Notification you can start an Activity. That activity would do "bindService" and call the appropriate method in the service, then finish(). The activity doesn't need to have a UI, so the user won't see it. But that's even more code than a Broadcastreceiver.

Categories

Resources