I have an activity that creates an intent, puts some extras with putExtra() and calls the startService(intent) to start a service.
This service calculates some stuff based on the extras and then I want to send the result back to the activity.
In which way can I do this?
I tried to create an intent on my service and broadcast it using sendBroadcast(). I have a broadcastReceiver on the activity but Im not sure if I register it correctly. Im confused!
Is there any other way to do so? Something like StartActivityForResult but for services (something like StartServiceForResult or something)?
The method you are attempting to use is good! Without code though it will be hard to say what you might be doing incorrectly.
In your service you would broadcast an intent like this...
/**
* Send broadcast to the activity letting it know the service is active
*
* #param pActivate
*/
private final void sendServiceActiveBroadcast( final boolean pActivate ) {
final Intent _intent = new Intent();
_intent.setAction( "com.yourtld.android.SERVICE_BROADCAST" );
_intent.addCategory( "com.yourtld.android.CATEGORY" );
_intent.putExtra( "isactive", pActivate );
this.sendBroadcast( _intent );
}
then in your activity you could have something like...
Create an action string:
private static final String SERVICE_BROADCAST_ACTION = "com.yourtld.android.SERVICE_BROADCAST";
In your onResume() method you would have...
final IntentFilter serviceActiveFilter = new IntentFilter( SERVICE_BROADCAST_ACTION );
serviceActiveFilter.addCategory( "com.yourtld.android.CATEGORY" );
this.serviceReceiver = new BroadcastReceiver() {
#Override
public void onReceive( final Context context, final Intent intent ) {
if( intent != null ) {
if( intent.getBooleanExtra( "isactive", false ) ) {
// The service is active
} else {
// False...
}
}
}
};
this.registerReceiver( this.serviceReceiver, serviceActiveFilter );
Hope that helps
You can do these three things which I know:
You can create an Intent and put data in Intent and start that activity ----- bad Idea
You can use SharedPreferences to pass the values -- only for primitive values
You can use static variables ------ which I think the best way to pass from service.
Note:
You can also use DB which is good if u have bulk of data.
First, you can have the service send the intent directly to the activity. That way, even if the activity isn't currently running, it will be launched.
Second, you start the activity with FLAG_ACTIVITY_SINGLE_TOP. This keeps the activity from launching if it's already running.
Third, you implement onNewIntent() in your activity to catch any intents the service sends if your activity is already running.
Related
I'm trying to create a pinned shortcut on the desktop for an app. The CreateShortcut method is called from a button and presents the android create-shortcut dialog. When the caller selects ok, the broadcast receiver should get called and execute finish so the activity exits.
This is the first time I've used a broadcast receiver but it looks like it's pretty straight-forward. Just create a receiver, register it with an intent filter that has the same action as an intent and when the intent is sent it should cause the receiver to be called, right?
The shortcut is created just fine but the broadcast receiver never gets called. I'm not seeing any messages on logcat.
private void CreateShortcut(final Context c) {
if (ShortcutManagerCompat
.isRequestPinShortcutSupported(c)) {
Intent shortcutIntent = new Intent(
c, CreateAppHomeShortcut.class);
shortcutIntent.setAction(
Intent.ACTION_CREATE_SHORTCUT);
ShortcutInfoCompat shortcutInfo
= new ShortcutInfoCompat
.Builder(c, "shortcut")
.setShortLabel(c.getString(R.string.app_name))
.setIcon(IconCompat.createWithResource(
c, R.drawable.qmark)
)
.setIntent(shortcutIntent)
.build();
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(
Context context, Intent intent) {
Log.d(TAG, "msg received");
unregisterReceiver(this);
finish();
}
}
, new IntentFilter(
Intent.ACTION_CREATE_SHORTCUT
)
);
PendingIntent successCallback =
PendingIntent.getBroadcast(
c, 99
, shortcutIntent, 0
);
ShortcutManagerCompat.requestPinShortcut(c,
shortcutInfo,
successCallback.getIntentSender()
);
}
}
I've been working on this several days and I'm stumped.
Thanks
I finally got the callback to my BroadcastReceiver. My main problem was that I was using the intents wrong. I thought that the brodcast receiver intent and the shortcut intent could be the same as long as the action was correct. Wrong! The shortcut intent must hava an action set but in the tests I did, it didn't seem to care what that action was. And the broadcast receiver was created as "Intent = new Intent(context, class); setAction(...); ", the shortcut would be created and function fine but the broadcast receiver was never invoked. The only way I could get the broadcast receiver to work was with an Intent just for it with nothing but the action set (or possibly extras) set. I couldn't get the program to work using the same intent to create the shortcut and invoke the broadcast receiver.
The other problem encountered was that the interface allows you to create multiple pinned shortcuts -- and would then call your broadcast receiver once for each shortcut created. I discovered you can query the interface for all pinned shortcuts and filter by id to find out if your shortcut already exists and use that info to avoid creating multiple identical pinned shortcuts on your home page.
The code below seems to work fine API26+ for creating a shortcut and the receiver gets called as long as the user accepts the shortcut. The docs state that they will only call your receiver on the user's acceptance. That of course makes detecting the end of the user's interaction rather difficult. Since the request gets buried in my actual app, the plan was to open this as part of a separate activity, but I don't have any way to detect that the user is done if he doesn't want the shortcut. If anyone has suggestions, I'd appreciate hearing them.
// Create a shortcut and exit the activity. If the shortcut
// already exists,just exit.
private void CreateShortcut(final Context c) {
if (Build.VERSION.SDK_INT >= 26) {
ShortcutManager sm =
getSystemService(ShortcutManager.class);
if (sm != null && sm.isRequestPinShortcutSupported()) {
final String shortcutId = "StartApp";
boolean shortcutExists = false;
// We create the shortcut multiple times if given the
// opportunity. If the shortcut exists, put up
// a toast message and exit.
List<ShortcutInfo> shortcuts
= sm.getPinnedShortcuts();
for (int i = 0;
i < shortcuts.size() && !shortcutExists; i++) {
shortcutExists
= shortcuts.get(i).getId().equals(shortcutId);
if (shortcutExists) {
Toast.makeText(c , String.format(
"Shortcut %s already exists."
, shortcutId
)
, Toast.LENGTH_LONG
).show();
finishActivity();
}
else {
// this is the intent that actually creates the
// shortcut.
Intent shortcutIntent
= new Intent(c, CreateAppHomeShortcut.class);
shortcutIntent.setAction(
Intent.ACTION_CREATE_SHORTCUT);
ShortcutInfo shortcutInfo = new ShortcutInfo
.Builder(c, shortcutId)
.setShortLabel(
c.getString(R.string.app_name))
.setIcon(createWithResource(c
, R.drawable.qmark))
.setIntent(shortcutIntent)
.build();
// this intent is used to wake up the broadcast
// receiver.
// I couldn't get createShortcutResultIntent to
// work but just a simple intent as used for a
// normal broadcast intent works fine.
Intent broadcastIntent
= new Intent(Intent.ACTION_CREATE_SHORTCUT);
// create an anonymous broadcaster. Unregister
// to prevent leaks when done.
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(
Context c, Intent intent) {
unregisterReceiver(this);
Log.d(TAG, String.format(
"ShortcutReceiver activity = "
+ "\"$1%s\""
, intent.getAction()));
finishActivity();
}
}
, new IntentFilter(
Intent.ACTION_CREATE_SHORTCUT)
);
PendingIntent successCallback
= PendingIntent.getBroadcast(
c, 99
, broadcastIntent, 0);
// Shortcut gets created here.
sm.requestPinShortcut(shortcutInfo
, successCallback.getIntentSender());
}
}
}
}
I have on my app a service who get my location (gps). This service get information like latitude, longitude, etc, and I want wrote these information in layouts fragment and activity (TextView).
But how can I get view reference of theses fragments since my service ?
You can do one thing to achieve this. send broadcast to the activity. And on that activity where you want to update view register broadcast there. Once you get the location stuff then send broadcast. Hope that helps you. Write this code in service when you get location stuff and pass that stuff via intent as mentioned in below code
Intent broadcastIntent = new Intent(your action here);
broadcastIntent.putExtra(BaseBroadCastReceiver.BROADCAST_KEY_AUDIO_INDEX, audioIndex);
broadcastIntent.putExtra(BaseBroadCastReceiver.BROADCAST_KEY_AUDIO_LIST, mSongList.size());
sendBroadcast(broadcastIntent);
And in your activity write below code
private void registerMyReceiver() {
IntentFilter filter = new IntentFilter(your action here you passed in service);
registerReceiver(playNewAudio, filter);
}
NOTE: your action can be any string but string must be same on both side
When activity's oncreate method is called, call registerMyReceiver() method
and in onDestroy method unregister is else you may get RUNTIME exception.
Below will be your code for actual broad cast receiver
private BroadcastReceiver myBroadcast= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//do your stuff here... get extra which you passed
// from service and set that value in views
}
};
In my laboratory work I have to create a service, which sends notifications when speed of battery discharging is greater then set.
I created an Activity with EditText for this value and 2 button for starting and stopping the service. Also I created a BatteryService class, inherited form Service class and BatteryReciever.
Now reciver registers with action BATTERY_CHANGED in service in onStartCommand. And problem is how to pass data to reciever or how to know about events in service.
What is the best way to solve this task?
To trigger a BroadcastReceiver, you need to use
sendBroadcast(intent);
Put the data you want to send from the Service in the intent as follows:
Intent intent = new Intent("my.custom.action");
Bundle b = new Bundle();
b.putSerializable("name", name);
b.putShort("count", count);
intent.putExtra("bundle", b);
sendBroadcast(intent);
And retrieve the data in the onReceive() method of the BroadcastReceiver:
#Override
public void onReceive (Context context, Intent intent){
Bundle b = intent.getExtras();
// do awesome things ...
}
Try this. This will work.
I'm wanting to implement what CommonsWare describes on this blog post: http://commonsware.com/blog/2010/08/11/activity-notification-ordered-broadcast.html. The post makes sense, and I was able to browse the example source here: https://github.com/commonsguy/cw-advandroid/tree/master/Broadcast.
What I'm curious about is if calling LocalBroadcastManager.getInstance(UnzipService.this).sendBroadcast(broadcast); inside of a service will still be picked up by a broadcast receiver of the type you define in your manifest.
In case what I'm asking isn't clear, what I'm trying to do is use the LocalBroadcastManager because the broadcasts from my service don't necessarily need to be seen system wide and I'd rather keep them private if possible, but I also want to display notifications if the user closes my app and the service is still running. Is there a way to combine both of those capabilities without sending a broadcast twice inside of the service?
(What I don't want to have to do) like:
LocalBroadcastManager.getInstance(UnzipService.this).sendBroadcast(broadcast);
sendOrderedBroadcast(broadcast);
What I'm curious about is if calling LocalBroadcastManager.getInstance(UnzipService.this).sendBroadcast(broadcast); inside of a service will still be picked up by a broadcast receiver of the type you define in your manifest.
No. LocalBroadcastManager only works with receivers registered with the LocalBroadcastManager singleton itself. Moreover, LocalBroadcastManager does not support ordered broadcasts, last I checked.
what I'm trying to do is use the LocalBroadcastManager because the broadcasts from my service don't necessarily need to be seen system wide and I'd rather keep them private if possible
So long as you are not using an <intent-filter> on your BroadcastReceiver in the manifest, and therefore are using an explicit Intent as the broadcast itself, your broadcast will only be seen by yourself and the bit of the OS that manages broadcasts. Other apps will not be able to spy upon it.
If you only have 2 objects that might handle your broadcast (in your case an Activity and a notifications controller), you can achieve the behavior of a ordered broadcast using only the LocalBroadcastManager.
The general idea is:
Set up your Service so that it broadcasts an Intent to your Activity with a particular action when you want to display your result
In your Activity create a BroadcastReceiver that handles your Service result Intent, and register it on the LocalBroadcastManager with an IntentFilter using the action from step 1
In your Service, when the results are available, try to send the result Intent using LocalBroadcastManager.getInstance(Context).sendBroadcast(Intent) this method returns a boolean that indicates if the broadcast has been sent to at least one receiver. If this boolean is false, it means that your Activity didn't handle your broadcast and you should show a notification instead.
In your service:
public UnzipService extends IntentService {
public static final String ACTION_SHOWRESULT = UnzipService.class.getCanonicalName() + ".ACTION_SHOWRESULT";
#Override
protected void onHandleIntent(Intent intent) {
Thread.sleep(500); // Do the hard work
// Then try to notify the Activity about the results
Intent activityIntent = new Intent(this, YourActivity.class);
activityIntent.setAction(ACTION_SHOWRESULT);
activityIntent.putExtra(SOME_KEY, SOME_RESULTVALUE); // Put the result into extras
boolean broadcastEnqueued = LocalBroadcastManager.getInstance(this).sendBroadcast(activityIntent);
if (!broadcastEnqueued) { // Fallback to notification!
PendingIntent pendingIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), activityIntent, PendingIntent.FLAG_UPDATE_CURRENT);
((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE))
.notify(SOME_ID, new NotificationCompat.Builder(this)
.setContentIntent(pendingIntent)
.setTicker("results available")
.setContentText("results")
.build());
}
}
}
In your Activity:
public YourActivity extends Activity {
private BroadcastReceiver resultReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
processResult(intent); // Results Intent received through local broadcast
}
}
private IntentFilter resultFilter = new IntentFilter(UnzipService.ACTION_SHOWRESULT);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate();
Intent intent = getIntent();
if (UnzipService.ACTION_SHOWRESULT.equals(intent.getAction())) {
// The Activity has been launched with a tap on the notification
processResult(intent); // Results Intent contained in the notification PendingIntent
}
}
#Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this)
.registerReceiver(resultReceiver, resultFilter);
}
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(resultReceiver);
super.onPause();
}
private void processResult(Intent intent) {
// Show the results from Intent extras
}
}
This should be a complete working example.
I hope this helps who is trying to implement ordered broadcasts with LocalBroadcastManager from support library!
I understand you want to achieve the following:
"I have an event that occurs in the background. I want to update my activity, if the activity is on the screen. Otherwise, I want to raise a Notification." (#TheCommonsBlog)
You can achieve this behaviour by implementing a ResultReceiver.
Examples Restful API service and
http://itekblog.com/background-processing-with-intentservice-class/
What you basically do is instance a ResultReceiver in your Activity and pass it to the Service like a Parcelable parameter through an intent. Then, each time your service whats to update the UI, the service verifies the ResultReceiver object for NULL. If not NULL, you update the Ui via the onReceiveResult interface. Else, you raise a notification. When your activity dismisses, make sure you set the ResultReceiver on the Service to NULL.
Hope it helps.
PS: IMO, broadcasts are too much work and hard to control.
Use LocalBroadcastManager and broadcasts become easy to use.
I am not in favor of updating an Activity if an event occurs in the background. The user might already be doing something else in the Activity. Seems to me that a Notification is sufficient; it's always visible and remains until the user dismisses it. Gmail and Gcal work like this; Gmail doesn't update the current screen if a new mail comes in. If you want to know how to handle the task flow for handling a notification when the user is already in the app, see the Notifications API guide and also the [Notifying The User2 training class.
I've a simple Main Activity which has to stop till an SMS is received... How can I launch a method from the MainActivity within the BroadcastReceiver's onReceive() Method?
Is there away with Signal and Wait? Can I pass something with a pending Intent, or how can I implement this communication?
Communication from BroadcastReceiver to Activity is touchy; what if the activity is already gone?
If I were you I'd set up a new BroadcastReceiver inside the Activity, which would receive a CLOSE message:
private BroadcastReceiver closeReceiver;
// ...
closeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//EDIT: receiving parameters
String value = getIntent().getStringExtra("name");
//... do something with value
finish();
}
};
registerReceiver(closeReceiver, new IntentFilter(CLOSE_ACTION));
Then from the SMS BroadcastReceiver you can send out this action:
Intent i = new Intent(CLOSE_ACTION);
i.putExtra("name", "value"); //EDIT: this passes a parameter to the receiver
context.sendBroadcast(i);
I hope this helps?
I had the exact same problem, I tried using intent but i was unsuccessful
The easiest way to use it would be using static methods and static variables
MainActivity.java
public static void stopsms()
{
/*
some code to stop the activity
*/
}
SMSReceiver.java
at the end call this function
MainActivity.stopsms();
It works amazing if your code does not affect when you use static methods and variables. Let me know if you need any help.
The problem with registering a second receiver within the activity, however, is that it will not be persistent like registering in the manifest... thus, although, this solution may work, will only work if the activity is running in background.
it's easy, use interface like that:
1) in your broadcast receiver create an interface.
public interface ChangeListener{
public void functionWhoSendData(String type);
public void etc();
}
and instantiate that interface in your broadcast receiver, use it:
public void onReceive(....
String data=functionWhereYouReceiveYouData();
ChangeListener.functionWhoSendData(data);
}
And in your activity, make it implements your interface