I get intent for push or custom scheme in A activity.
I'm handling them in onResume.
It seems the intents are not disposed unless explicitly told.
I start an activity for intents, and when I close the started activity, it keeps restarted (I suspect this is due to the living intents)
How should I dispose them?
Are there better way of handling for example, push intent?
(without the need to disposing them?)
--- edit
I think my problem is due to the way I handle push, (or scheme)
GcmIntentService creates notification which would start a MainActivity
MainActivity then look at args and starts appropriate activities.
I guess the more conventional way is to go from GcmIntentService to appropriate activities directly?
Try putting this inside onCreate() method of your MainActivity.java :
if (savedInstanceState == null) {
final Intent launchIntent = new Intent(MainActivity.this, AnotherActivity.class);
startActivity(launchIntent);
}
If the activity is already created, rather put this inside onStart() method.
Related
Suppose I have two activities A and B activity A which contains a button I want to start Activity B when I press Button without intent.
According the Oficial Documentation:
An intent is an abstract description of an operation to be performed. It can be used with startActivity to launch an Activity, broadcastIntent to send it to any interested BroadcastReceiver components, and startService(Intent) or bindService(Intent, ServiceConnection, int) to communicate with a background Service.
An Intent provides a facility for performing late runtime binding between the code in different applications. Its most significant use is in the launching of activities, where it can be thought of as the glue between activities. It is basically a passive data structure holding an abstract description of an action to be performed.
So you have to use it to open activities with no exceptions or workarounds, if you do that, you are ignoring the entire system architecture.
There is no way to start an activity from anotherone without an intent.
If the reason of not using Intent that you don't want the the user to re-enter the previous activity
You can use finish() to finish that activity intent after you done work with
if(currentUser == null){
startActivity(new Intent(MainActivity.this,StartActivity.class));
finish();
}
So user will be unable to back again
If you want to do some code while the activity is finishing
You can use onDestroy() override method, Sometimes it can also be called if the activity is being killed by the android itself so you can add
isFinishing() function
Inside onDestroy() method which checks whether the application is closing by the call finish() returning true or otherwise by anything else returning false then you can easily specify your code for each situation.
#Override
protected void onDestroy() {
super.onDestroy();
if(isFinishing()){
// Activity is being destroyed by the function `finish()`
// What to do...
}else{
// Activity is being destroyed anonymously without `finish()`
// What to do...
}
}
Put your activity inside a Fragment and start the fragment fromo the button.
These are the possible ways to start any Activity
1st
startActivity(new Intent(Activity_A.this, Activity_B.class));
2nd
Intent intent = new Intent(Activity_A.this, Activity_B.class);
startActivity(intent);
3rd
Intent intent = new Intent(Activity_A.this, Activity_B.class);
startActivityForResult(intent,code);
While scanning an NFC tag in an application with Foreground Dispatch enabled, onPause() is called before onNewIntent(). Is it possible to get the NFC intent already in onPause() so that I can stop (or not) processes according to the origin of the intent?
Since the activity is in the foreground and should not be paused/resumed when a tag is scanned, and since I have tasks that have to stop or start in onPause/onResume, you can see the problem.
The getIntent().getAction() is always "MAIN", but surely there must be a way to get a more accurate description of the intent? Or is not possible to know it's an NFC intent before entering onNewIntent()?
No, you won't be able to know what the new intent is before it is delivered to your activity in onNewIntent(). That's the point of the onNewIntent() callback: Deliver the information about the new intent to your activity. Only when this method is called, you can obtain the new intent through the intent parameter of that method:
#Override
protected void onNewIntent(Intent intent) {
...
}
Note that getIntent() will always return the intent that initially started your activity unless you explicitly update that intent using setIntent(newintent). So if you started the activity through the launcher you will get the intent action MAIN.
onPause/onResume() is called due to the way the NFC service dispatches the intent to your activity. There is nothing you can do about that. In fact that should not be something that you need to differentiate in your application logic. If onPause is called you should do whatever you would normally do in there regardless of whether this was invoked due to explicit user UI interaction moving some other UI component in front of yours or due to the system moving some (invisible) UI component in front of yours. If your current onPause logic really needs to differentiate between the two, then it might probably better be done in onStop.
I am trying to connect to different activities from a custom soft keyboard. I need the activity underneath the keyboard to allow data to be sent without the activity creating a new instance of itself. For example: if the keyboard is over the messaging application, I want to send that application data without losing the current conversation that the user is typing into. I currently have the following code to send data to the activity.
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, screenshotUri);
//sendIntent.putExtra("thread_id", (long) 1);
sendIntent.setType("image/*");
startActivity(sendIntent);
I am getting the following obvious error when I try to run it...
E/AndroidRuntime(6129): android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
How can I keep the current activity underneath the keyboard from resetting itself when an intent is sent from the keyboard service? Or more simply, how can I send an intent from a service without setting the FLAG_ACTIVITY_NEW_TASK flag?
You can't really do this like that. A Service can't pass data to an Activity without "starting it". You don't want to do that. You want to pass data to an "already started" Activity. There's 2 ways to do this:
Use a bound Service. Have the Activity bind to the Service. The Activity can then call methods on theService (using AIDL) and receive returned data.
Use a BroadcastReceiver. Have the Activity create and register a BroadcastReceiver to listen for the returned data. In your Service, send a broadcast Intent when you want to transmit data to the Activity.
You can do this by several ways but you must set flag in order to complete task.
If you want to create a new instance and close the current instance you need to set Intent.FLAG_ACTIVITY_CLEAR_TOP.
If you want to reuse the same instance of the activity in this case you need to set both Intent.FLAG_ACTIVITY_CLEAR_TOP and Intent.FLAG_ACTIVITY_SINGLE_TOPafter that it will not create another instance of the activity but call onNewIntent() of activity to run the new Intent.
Inside a broadcast receiver I want to start my app (Activity) and pass in some data.
My problem is that the extras don't seem to carry over into the activity. I am trying to get the data inside the onNewIntent(Intent i) function.
Any ideas?
Here is my current attempt in the BroadcastReceiver:
Intent intSlider = new Intent();
intSlider.setClass(UAirship.shared().getApplicationContext(), SliderMenuActivity.class);
intSlider.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intSlider.putExtra("action", ScreensEnum.Object);
intSlider.putExtra("objectId", objectId);
intSlider.putExtra("objectCode", objectCode);
intSlider.putExtra("userId", userId);
UAirship.shared().getApplicationContext().startActivity(intSlider);
EDIT - Added code used in onNewIntent() and onCreate()
The following code works great in onCreate() when the app isn't currently running. For when the app is already running the same code doesn't work (i.e. no extras) from the onNewIntent() function.
Intent intent = getIntent();
if(intent.hasExtra("objectId")) {
loadDetail(intent.getStringExtra("objectId"), "2w232");
}
The problem is getIntent() method. It always returns the intent that started the activity, not the most recent one. You should use intent that was passed to onNewIntent method as an argument.
We stumbled upon this problem once, when we were trying to launch/call onNewIntent on an Activity in response to a local notification tap. The extras that we put on our Intent were disappearing at the time onNewIntent received it.
I don't remember this being documented anywhere back then, but the "problem" was that we weren't setting the action field on the Intents that we prepared. Turns out if the Intent received by your Activity doesn't have an action set using setAction, the system still delivers the Intent to its destination, but doesn't transmit the extras you have set while creating the Intent.
TL;DR:
If you encounter this problem with an Intent with no action, calling setAction to set an arbitrary action value before sending the Intent might fix it.
Extract from the docs
This is called for activities that set launchMode to "singleTop" in
their package, or if a client used the FLAG_ACTIVITY_SINGLE_TOP flag
when calling startActivity(Intent). In either case, when the activity
is re-launched while at the top of the activity stack instead of a new
instance of the activity being started, onNewIntent() will be called
on the existing instance with the Intent that was used to re-launch
it.
An activity will always be paused before receiving a new intent, so
you can count on onResume() being called after this method.
Note that getIntent() still returns the original Intent. You can use
setIntent(Intent) to update it to this new Intent.
I think the last paragraph explains your problem.
You have to set the flag FLAG_ACTIVITY_SINGLE_TOP or set launchMode singleTop in the manifest file.
Of course when onNewIntent is called you do not use getIntent but the Intent received as argument.
onNewIntent will be called when the activity instance already exists. For example, if last time you pressed the Home Screen button.
I wrote a solution that worked for me here: Intent with old extra in onCreate() for singleTask Activity
You can store the last received intent in a member variable (mLastIntent).
Then you can use this member in your onResume() method to query for your extra data.
private Intent mLastIntent;
#Override
protected void onNewIntent(Intent intent) {
mLastIntent = intent;
};
I am intercepting sms messages with some information in them. Then in my SmsListener I'm creating notification to show in statusbar.
Then, when user clicks on a notification I want
Bring MainActivity to foreground (If such activity does not exist yet it should be created)
Pass to it data from the sms
Perform some ui changes basing on this data in this MainActivity
My activity is defined as
<activity
android:name=".MainActivity"
android:screenOrientation="sensor"
android:label="#string/app_name"
android:launchMode="singleTask"/>
Activity is launched as
Intent i = new Intent();
i.setClass(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
Also in my activity I have overridden method onNewActivity
#Override
public void onNewIntent(Intent intent){
super.onNewIntent(intent);
// I have data from broadcast in intent variable passed to this activity
processDataFromBroadcast(intent);
}
It works fine if the MainActivity already exists but if MainActivity does not exist it is started however onNewIntent was not called
Then I tried to invoke processDataFromBroadcast from onCreate: processDataFromBroadcast(getIntent()).
First time data is passed correctly from my broadcast to the activity.
However if MainActivity is sent to background and then again brought to foreground either onCreate or onNewIntent is called and processDataFromBroadcast is executed again with intent sent by broadcast and thus my MainActivity is updated with data from broadcast every-time the app is bringing to foreground - the latter is unwanted, how can I make my activity to forget this intent after first handling.
Here is sample application.
For an activity to launch only one instance of itself, have a look at the <activity> manifest element, and particularly android:launchMode. You want to configure it with either singleTask or singleInstance.
To pass data to your activity, you add data to the Intent you use to open it. To pass data with the intent, use the putExtra() methods of the intent before sending it off, and getExtra() methods to retrieve them in your receiving activity.
I'm assuming that you know roughly how intents work, but if not you could learn more about intents by taking a look at this Android developers article.
in case your problem is still unresolved, as I was just running into the same issue, here's how I solved it:
I am putting a timestamp as intentId as an extra upon the intent during it's creation. the first time, I am handling the intent in onCreate() or onNewIntent() I am reading the intentId and store it as the last intent handled. so the next time onCreate() or onNewIntet() is invoked I can check the intentId and if it equals the id of the last intent handled, I ignore it! It don't know if this helps in your case, maybe you can adopt it.
To keep intentId independent from activity lifecycles you could persist it in the userdefaults.
I agree that one would expect calling setIntent(new Intent()) in onNewIntent should do the trick.
It it late to answer, but it might be helpful to others looking for the solution.
Just add below lines of code :
Intent mIntent = new Intent(this, SplashActivity.class);
mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // You need this if starting the activity from a service
mIntent.setAction(Intent.ACTION_MAIN);
mIntent.addCategory(Intent.CATEGORY_LAUNCHER);
Where SplashActivity is the name of initial application that is the first screen of your application.
Hope it helps. :)