What kind of broadcast Receiver to use? - android

I have read this answer here and also this here and I'm trying to figure out what fits best for my case.
I start a Service inside onCreate() where I make an HTTP requests and I get an id as a response. I then broadcast this id and receive it in my activity.
The problem is that the user can obviously navigate to another activity just by opening the drawer and selecting an option and I can miss the broadcast.
I can obviously have all my Activities extend an abstract class which extends Activity like is mentioned here but I'm not 100% sure its the best solution. What if user decides to quit the app before I receive the id ?
Edit : app architecture
User captures an image using an Intent to open camera app and get the path of the image file.
FormActivity starts where user can add some details about the image.
User clicks upload and I pass the data user has just entered to QuizActivity.
In onCreate() of QuizActivity I start an Service where I :
create an empty entry to server and I get an id as a response and
upload image to server
That id I get as a response from server I then broadcast it.
QuizActivity has an entryIdReceiver registered where receives the id and stores it in a private field until user decides to either leave the activity or click to upload the quiz ( if he entered data for the quiz of course )
If user clicks upload I start an IntentService with the id and the quiz data.
If User opens drawer and select another Activity or clicks cancel to create a quiz I start an IntentService to upload the id with the "empty quiz data" and move user to MainActivity.
The problem is : what if uer closes app while on QuizActivity and I haven't yet receive the id, or user decides to got to another Activity using the drawer without adding a quiz. I still have to start a service and upload the id with "empty quiz data".

It's pretty good, by using abstract class, where you handle all action, and just send callback to your activity. Using that example in your question above seems to me like EventBus.
And even better using special class and interfaces, instead of abstract class, because you may want use FragmentActivity, AppCombatActivity, etc.
For example, your have your own class, which receiving result from your service and send all registered to him activities. Invoking result from net requests with interfaces:
public class NetRequestReceiver extends BroadcastReceiver {
private List<Activities> registeredActivities;
public static void getInstance () {
//Continue singleton initialing!
//....
}
#Override
public void onReceive(Context context, Intent intent) {
for (Activity act : registeredActivities) {
if (act instanceOf ReceivingCallback) {
act.onReceiveMessage(intent);
} else throw Exception("Activity missing ReceivingCallback");
}
}
public void registerActivity (Activity, activity) {
if (!registeredActivities.contains(activity)) {
registeredActivities.add(activity);
}
}
public void unRegisterActivity (Activity, activity) {
if (registeredActivities.contains(activity)) {
registeredActivities.remove(activity);
}
}
public interface ReceivingCallback {
onReceiveMessage (Intent intent);
}
}
Then in all you activities add next listener. But (!) don't forget register receiver above in you Service for receiving result!
public class MainActivity extends Activity implements NetRequestReceiver.ReceivingCallback {
public void onStop () {
super.onStop()
NetRequestReceiver.getInstance().unRegisterActivity(this);
}
public void onResume () {
super.onResume()
NetRequestReceiver.getInstance().registerActivity(this);
}
#Override
public onReceiveMessage (Intent intent) {
//put here whaterver you want your activity
//to do with the intent received
}
}
What do you think, we get, using design above? We now have single Receiver and Callback as an interface. So you can use Fragment, Activity, FragmentActivity, and other class, for receiving result from Service via Broadcast and (!) without copy pasting same behavior!
Also it's looks nice, because we split of different layer - presentation, view, and receiver. You call net request in Service. This Service send result to Broadcast, and then he sends data to all registered activities.
Yes, it's seems like EventBus, but based on your question it's just what you need for listen connection from service to different activities, and with better structure.

Maybe you can send a sticky broadcast. The system will keep it even the activity destroyed and you can receive the intent immediately when your register property
receiver.
But notice sendStickyBroadcast is deprecated and don't forget declare
android.permission.BROADCAST_STICKY
in your AndroidManifest.xml if you decide to using it.

Related

Moving between activities with updated info

I have 2 activities . Activity 1 has Information. Activity 2 has a form to update Information in Activity 1 .
How can i return yo Activity 1 and show updated information ?
When i move from activity to another should i use finish () ?
Starting another activity doesn't have to be one-way. You can also start another activity and receive a result back. To receive a result, call startActivityForResult() (instead of startActivity()).
For example, your app can start a camera app and receive the captured photo as a result. Or, you might start the People app in order for the user to select a contact and you'll receive the contact details as a result.
Of course, the activity that responds must be designed to return a result. When it does, it sends the result as another Intent object. Your activity receives it in the onActivityResult() callback.
This the detailed link of about startActivityForResult
Use this pattern.. dont have to override back pressed it will automatically use the super method.. So, in activity 1 use this field var..
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// update the info and UI here
}
};
onResume() of activity 1
LocalBroadcastManager.getInstance(mContext).registerReceiver(mBroadcastReceiver ,new IntentFilter("info"));
and in Activity 2
Intent intent= new Intent("info");
intent.putExtras("infoss",*yourInfo*);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
Note The activity 1 will be automatically updated with correct info .. you dont need to use onBackPressed() logic for this
In your first activity
In the second Activity when your work is done and you want to send data from the second activity to the first activity
receive data in the first activity

Activity opened twice

I have an application that uses Urban Airship for push notification. When a notification arrives and the user clicks on it, activity A in my application should open and do something.
I've installed the BroadcastReceiver as is shown in the docs, and it's almost working.
When my app is in the foreground I don't let the user see the notification at all, and just handle it automatically.
When my app is not running at all, the activity opens up just fine.
When my app is in the background (which always happens when A is the top activity), a second instance of Activity A is created.
This is, of course, a problem. I don't want two A activities, I just want one of them. Here's the relevant BroadcastReceiver code:
#Override
public void onReceive(Context ctx, Intent intent)
{
Log.i(tag, "Push notification received: " + intent.toString());
String action = intent.getAction();
int notificationId = intent.getIntExtra(PushManager.EXTRA_NOTIFICATION_ID, -1);
if(action.equals(PushManager.ACTION_NOTIFICATION_OPENED))
{
Intent intentActivity = new Intent(ctx, ActivityA.class);
intentActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
UAirship.shared().getApplicationContext().startActivity((intentActivity);
}
}
UPDATE:
I tried to bypass this bug by calling System.exit(0) when the user presses Back on Activity A. The process ended, but then it was restarted immediately! My BroadcastReceiver is not called again in the second instance. What's happening?
UPDATE 2:
#codeMagic asked for more information about the app and activity A.
This app lets its user review certain items and comment on them. Activity A is started when the app is launched. If the user's session isn't valid any more, a Login activity is started. Once the user logs in, activity A becomes active again. A only has a "No items to review" message and a "Try now" button.
When the user logs in, the server starts sending push notifications whenever a new item is available for review. When the app gets the notification, activity A accesses the server and gets the next item to review. The item is shown in activity B. Once the review is submitted to the server, activity B finishes and activity A is again the top activity.
The server knows when a user is reviewing an item (because activity A fetched it), and doesn't send push notifications until the review is submitted - meaning a notification can't come if the user isn't logged in or if the user is viewing activity B.
While I agree there is a subtle race condition here, it is not causing the problem I'm seeing - in testing I am 100% positive there's no race condition - the push notification is only sent after Activity A becomes active again.
The solution was to add a launchMode='singleTask' to the activity in AndroidManifest.xml . As a result, instead of a new activity, onNewIntent of the same activity instance is called.
You can use one of several Intent Flags. FLAG_ACTIVITY_REORDER_TO_FRONT being one of them. This will bring the Activity to the front of the stack if it is already in the stack and if not then it will create a new instance. I believe you will still need FLAG_ACTIVITY_NEW_TASK if you aren't calling it from an Activity
Intent.FLAG_ACTIVITY_CLEAR_TOP should also work. But this will clear any other Activities on the stack. It just depends on what other functionality you need. Look through the Intent Flags and see which of these will work best for you
There are multiple scenarios when this could happen. One of them can be handled this way. Please see my answer here: https://stackoverflow.com/a/44117025/2959575
Ok, two notes on this :
You can register a broadcast receiver via the manifest so it is independent of any parts of your app. and use a Singleton pattern (keep a static reference to your activity somewhere in your app) that way you can check if their is an activity viewing or not and process accordingly.
// your activity A
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
myActivityReference = this;
}
public void onPause() {
super.onPause();
if (isFinishing()) {
myActivityReference = null;
}
}
or you can keep everything as it is and use activity lunching modes flags in your manifest such as singleTop, singleInstance ... etc. take a look here android activity lunch modes

android: hiding and destroying activity started from a service

I'm new to Android development. I am trying to monetize a live wallpaper that I built and the ad delivery company wants me to call their code from the onCreate of an activity.
The live wallpaper didn't have an activity before I started to monetize it, being an extension to WallpaperService, so I've added one. I've managed to create the activity and make it translucent, but it doesn't close when the dialog closes. I cannot edit the dialog code since it is being created by a call into a .jar, so I thought I could setup a listener for when the dialog is dismissed, but I wasn't able to find any practical examples that might help with the code below.
LWP.java
public class SBLiveWallpaper extends WallpaperService {
super.onCreate();
Intent i = new Intent();
// i.setClass(this, MainActivity.class);
i.setComponent(new ComponentName("appname", "appname.MainActivity"));
// i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
activity_main.xml has no elements (just the RelativeLayout)
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppBucksAPI.initialize(this, APPID, "APIKEY", true, null, null);
AppBucksAPI.userOptOutDialog(this, "marketname");
}
I could make the activity be non-transparent, and just add a close button, but that is ugly and confuses users.
Edit for clarification: I had tried originally to call the dialog directly from the service's onCreate(). It causes the LWP to crash in the screen where you can make it the active LWP. The error I get is android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application.
I contacted AppBucks support before making the original post here. Their response (pasted below) prompted me to create the translucent activity.:
I believe this error means that there is a problem with the first parameter you are passing to the AppBucksAPI.userOptOutDialog method… the call which looks like this from the docs:
AppBucksAPI.userOptOutDialog(this, "<App Name>");
This call expects an Activity or Activity context as the first parameter. It needs this because our default opt out dialog uses an AlertDialog call, which requires an active Activity for it to display correctly. If you are already creating an Activity along with your service, you should pass that activity as the first parameter instead of “this” (or you could move this call to the onCreate of that activity instead of onCreate for the service).
If you don’t have an Activity in your app, I found this StackOverflow question which has an answer that may help (in a nutshell, you can create a transparent activity when your service starts up, and make the userOptOutDialog call from that instead of your service’s onCreate method):
Display AlertDialog as system overlay window from Service
Unfortunately, the above article covers creating the activity and closing the dialog under the assumption that the person reading it has access to the dialog's code. Since I do not have access to that, because it is imported into my project as a library, I need to know how to listen, from the parent activity, for the child to finish.
I did some digging and it looks like either of these could work, depending on how the activity is started from the dialog call my code makes:
http://developer.android.com/reference/android/app/Activity.html#finishActivityFromChild(android.app.Activity, int)
or
http://developer.android.com/reference/android/app/Activity.html#finishFromChild(android.app.Activity)
I'll give those a try tonight.
The AppBucks SDK also exposes the following functions:
setIconAdsEnabledForUser
setPushAdsEnabledForUser
The AppBucksAPI.userOptOutDialog is basically a convenience function that wraps calls to these in an AlertDialog. For your app, it probably makes more sense to forego the convenience function and write your own AlertDialog that calls the enable functions directly. That way you will have full control over what happens when the dialog is dismissed and can close the new activity you created when you need to.
Looking at the AppBucks API and documentation, I don't think using an Activity is mandatory. It is just the most common way.
I think you can call AppBucks method in your service onCreate as well?
When dismissing your dialog, send an intent to your activity for it to close itself.
For instance
Put this in the dialog dismiss method:
sendBroadcast(new Intent(MainActivity.ACTION_TERMINATE));
Then in the MainActivity add and register a BroadcastReceiver:
Add fields for the receiver and the filter in the activity:
private ActivityBroadcastReceiver mReceiver;
static final IntentFilter mFilter = new IntentFilter();
static {mFilter.addAction(ACTION_TERMINATE);}
Instantiate it in onCreate():
mReceiver = new ActivityBroadcastReceiver();
Register it in onResume():
registerReceiver(mReceiver, mFilter);
Unregister it in onPause():
unregisterReceiver(mReceiver);
And the broadcast receiver's inner class in the activity would look like this
private class ActivityBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
String action = intent.getAction();
if (ACTION_TERMINATE.equals(action)) {
finish();
}
} catch (Exception e) {
Log.w(mTag, "Oops: " + e, e);
}
}
}

Service to Activity in Android

How can I send data from a Service to an Activity? Broadcast receiver? Handlers? Intent? I have several Strings in particular that I would like to send from Service to an Activity, so that I can then display some View to the user.
getApplication().startActivity(new Intent()) ?
Since both Activity & Service is in same application. Instead of going for Service Binder IPC, try implementing register callBack mechanism. Try follow below step.
-> Make a static class which extends from class Application to make quick reference anywhere in your application.
-> Register a callBack from Activity to this application class.
-> Post event from your service to the application class and let Application class deliver the event to all register callBacks.
As #justin-shield mentioned the best way is to use some form of IPC. I don't think you need to use AIDL, however. You can see another answer I gave to a similar question that outlines the basic steps to register Handlers and Messengers in your Activity and your Service.
I think all your answers are way more complex than what I need. I think I have come up with a rather simple solution (psuedo-code):
Service:
Intent i = new Intent(this,Activity.class);
i.putExtra(name,value);
startActivity(i);
Activty:
private Intent intent;
private String s1;
from the onCreate(Bundle savedInstanceState)
{
super(savedInstanceState);
intent = this.getIntent(); //Gets the intent that started this Activity.
s1=intent.getExtras().getString(name);
}
Would I use same code in onStart() ? What about onResume() ? onRestart() ? Lastly, I only want to send to the Activity some data to publish via some View objects, I don't need any communication going back to the Service.

Running activity from remote service

iam trying to run an activity from diffrent package from my remote service:
this is how i implement the service.java
public class CurrencyService extends Service
{
public class CurrencyServiceImpl extends ICurrencyService.Stub
{
int CALL_PUSH_SERVICE_ACTIVITY=10;
#Override
public void callSomeActivity(int activityId) throws RemoteException
{
Intent pushActivity=new Intent("com.pushservice.PushActivity");
pushActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(pushActivity);
}
.....
}
ive also added a line in the manifest of the service:
the service works fine, but i cant run the activity -> PushActivity which is in diffrent package of diffrent application,
this is the error:
Activity not found Exception: No Activity found to handle Intent {act=com.pushservice.PushServiceActivity flq=0x10
...
thanks.
You shouldn't call start activity from your service. From Android developers best practice:
Instead of spawning Activity UIs
directly from the background, you
should instead use the
NotificationManager to set
Notifications. These will appear in
the status bar, and the user can then
click on them at his leisure, to see
what your application has to show him.
You are attempting to open an Activity that has an intent-filter with an action of "com.pushservice.PushActivity". You do not have an Activity that has an intent-filter with an action of "com.pushservice.PushActivity".
The best answer is to not display an activity from a service, since users will be very irritated with you if you interrupt them when they are using the device.

Categories

Resources