So, I've got a question !
I have got an activity called X. When the user click on a button, the activity Y is displayed.
I want that this activity can be closed after have received an event sent by activity X.
Do you know how can I do this ?
Send a BroadcastMessage from X. In y register a BroadcastReceiver with same IntentFilter. So from x you can send a predefined exit message which will be catched by y activity's onReceive method. There you can end the activity Y.
For Example:
in Y activity
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
if (extras != null) {
if (extras.containsKey("exit")) {
finish();
}
}
}
dont forget to register the receiver
registerReceiver(
mMessageReceiver,
new IntentFilter(Constants.YOUR_INTENT_FILTER));
and unregister
unregisterReceiver( mMessageReceiver);
IN X activity:
send the broadcastmessage using `sendBroadcast(Intent i)`
For this kind of internal messaging I prefer LocalBoradcastManager
Unfortunately you can not have two activities "running" at the same time. Activity X goes through its end of lifecycle when you start Activity Y.
See: http://developer.android.com/guide/components/activities.html
Each time a new activity starts, the previous activity is stopped, but the system preserves the activity in a stack (the "back stack"). When a new activity starts, it is pushed onto the back stack and takes user focus. The back stack abides to the basic "last in, first out" stack mechanism, so, when the user is done with the current activity and presses the Back button, it is popped from the stack (and destroyed) and the previous activity resumes. (The back stack is discussed more in the Tasks and Back Stack document.)
When you receive BroadcastMessage from ActivityX then you can set value of one Global boolean
you should check that value of bolean at the time of use of Activity Y(it may in onCreate )
in Activity Y
if you get this boolean value true(or whatever you set at the time of call BroadcastMessage ) then simply call finish()
The thing is android not running two activity at the same time , so
without having activity you can not finish it remotely
Related
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
I have an activity that shows some information based on the intent that initiates the activity. The app icon starts this activity without any extra information and the activity displays correctly. The app widget also starts this activity, but with some extra information and is handled correctly. In this scenario, the app does not work as expected:
The user enters the activity using home screen shortcut.
The user uses the home key to send the app to the background.
The user uses the widget shortcut to enter the app
in this scenario, in onResume() the intent is the old one not the one from widget.
How can I solve this problem?
This is exactly why onNewIntent() exists: it is called:
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.
Therefore add code such as:
#Override
protected void onNewIntent (Intent intent) {
setIntent(intent);
}
And/or move your code from onResume() into a method such as handleIntent() and call it from both your onCreate() and from onNewIntent().
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
There are a lot of topics on this post. But i couldn't find a solution to my problem.
Let me describe my activity stack first.
SplashScreen->A->Login->Home.
What i would like to achieve is , when i click on back button after logging in to Home, i should come out of the application and go to Home if i use my application again. For this i am assuming i should clear the activity stack before Home, after i login. I would also like to preserve the activity stack if the user hasn't logged in yet.
I want this to work on or after 2.1
What i have tried already.
using finish() in Login Activity , before calling startActivity on Home. This will redirect me to A , if i use back button on Home.
All variations of FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_CLEAR_TOP . Nothing worked, when i use back button, i am redirected to login screen.
Any suggestions or simple solution to achieve this?
using finish() in Login Activity , before calling startActivity on Home. This will redirect me to A , if i use back button on Home.
ok so use finish on all the activities that you want them to be popped before calling startActivity
go to Home if i use my application again
Simply save your login parameters in SharedPreference and from A startActivity Home directly if login successful.
You can also try to make use of BroadcastReceiver aswell if you want to try that route.
In your "SplashScreen" and "A" activities, in the onCreate method you can create and register and IntentFilter and a BroadcastReceiver like so:
Assuming you have a global variable called broadcastReceiver
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("ACTION_LOGIN");
this.broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
};
registerReceiver(broadcastReceiver, intentFilter);
Also don't forget to unregister your receiver in the onDestroy method (this is to prevent memory leaks in the program):
#Override
protected void onDestroy() {
unregisterReceiver(this.broadcastReceiver);
super.onDestroy();
}
Now in your "Login" activity, once the user has successfully logged in, you can broadcast a message to all the registered receivers, which will finish those activites in the back stack:
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("ACTION_LOGIN");
sendBroadcast(broadcastIntent);
Your SplashScreen and A activities will now be finished.
I have a foreground service that keeps a connection open with the server as long as the user is logged into the application. This is so that the connection is kept alive and can receive messages directly from the server even when the application has been sent into the background by the user pressing Home.
The application has a number of Activities, any of which could be the active one when it is sent into the background.
I would like to allow the user to click on the notification to restore the current Activity. I understand how to restore a particular activity, but wondered if there is a way to restore the last Activity that the user was on? Of course I could keep track of the the last one, and then call that from the Notification callback, but thought there might be a way at a task level?
Thanks for any advice you can offer.
What you need is just a simple Activity that does nothing. Here is an example:
public class NotificationActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Now finish, which will drop the user in to the activity that was at the top
// of the task stack
finish();
}
}
Set up your notification to start this activity. Make sure that in the manifest the task affinity of this activity is the same as the task affinity of the other activities in your application (by default it is, if you haven't explicitly set android:taskAffinity).
When the user selects this notification, if your application is running, then the NotificationActivity will be started on top of the topmost activity in your application's task and that task will be brought to the foreground. When the NotificationActivity finishes, it will simply return the user to the topmost activity in your application (ie: wherever the user left it when it went into the background).
This won't work if your application isn't already running. However, you have 2 options to deal with that:
Make sure the notification isn't present in the notification bar when your application is not running.
In the onCreate() method of the NotificationActivity, check if your application is running, and if it isn't running call startActivity() and launch your application. If you do this, be sure to set the flag Intent.FLAG_ACTIVITY_NEW_TASK when starting the application so that the root activity of the task is not NotificationActivity.
Works very well, thanks David! The following class checks if the application is already running and if not, starts it before finishing (as suggested by David in option 2).
public class NotificationActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// If this activity is the root activity of the task, the app is not running
if (isTaskRoot())
{
// Start the app before finishing
Intent startAppIntent = new Intent(getApplicationContext(), MainActivity.class);
startAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startAppIntent);
}
finish();
}
}
There is a simpler solution that does not require the extra activity. See this post for details. Basically, the notification starts the (possibly existing) task the same way it is started when you click the launcher icon while the app ist in the background.
My solution, which emulates the behaviour of the launcher (bringing up the task to the foreground):
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClassName(MyApplication.class.getPackage().getName(), MainActivity.class.getName());
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
This works, no doubts about it but the problem is when you set your intent as ACTION_MAIN. Then you will not be able to set any bundle to the intent. I mean, your primitive data will not be received from the target activity because ACTION_MAIN can not contain any extra data.
Instead of this, you can just set your activities as singleTask and call your intent normally without setting ACTION_MAIN and receive the intent from onNewIntent() method of your target activity.
But be aware if you call, super.onNewIntent(intent); then a second instance of the activity will be created. Just don't call super method.
I combined David Wasser's and Raginmari's solution by doing that approach to the root activity of your app then it will work for both cases when your app was already started or haven't been started.
public class YourRootActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (!isTaskRoot()) // checks if this root activity is at root, if not, we presented it from notification and we are resuming the app from previous open state
{
val extras = intent.extras // do stuffs with extras.
finish();
return;
}
// OtherWise start the app as usual
}
}