Within my Main Activity that loads a Webview, depending on where it was launched from determines the url to load.
Bundle extras = getIntent().getExtras();
if (extras != null) {
String theurl = getIntent().getExtras().getString("url");
webView.loadUrl(theurl);
} else {
webView.loadUrl("http://mysite.com");
}
If the application is a fresh instance and loaded from the home screen it loads the default url.
If the application is not running and i click a notification that was sent through google cloud messaging the application loads a custom url.
This functions as expected.
My problem lies when the application is already running in the background, when i click a notification it will bring the app to the front but wont load the new url, it stays at the default.
I'm not too sure with the Flags, i did have this problem before and it was a certain combination of flags that fixed it.
Intent notificationIntent = new Intent(context, MainActivity.class);
notificationIntent.putExtra("url", url);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK );
int requestID = (int) System.currentTimeMillis();
PendingIntent intent = PendingIntent.getActivity(context, requestID, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
Help would be greatly appreciated.
EDIT
If i add the flag PendingIntent.FLAG_CANCEL_CURRENT this almost solves the issue, although it reloads the whole main activity (Splash screen gets called), i want it to reuse the existing webview.
This is the flag you're looking for: FLAG_ACTIVITY_CLEAR_TASK
If set in an Intent passed to Context.startActivity(), this flag will
cause any existing task that would be associated with the activity to
be cleared before the activity is started. That is, the activity
becomes the new root of an otherwise empty task, and any old
activities are finished. This can only be used in conjunction with
FLAG_ACTIVITY_NEW_TASK.
EDIT:
If you place your webview code in onResume and then don't use any flags, it should work fine.
Related
I am working on android application, I want everytime the user click on the notification, it will start new activity, however, the activity has started, but unable to read any data from sqlite
I have splashscreen before mainactivity started. I have set to open splashscreen or mainactivity after clicking the notification, both do the same, it will through oncreate process but unable to get any data from sqlite
I have checked the db connection and it is not null
pending intent
Intent resultIntent;
resultIntent = new Intent(this, MainActivity.class);
resultIntent.putExtra("act", "alert");
resultIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, resultIntent,
PendingIntent.FLAG_ONE_SHOT);
main activity oncreate
HashMap user = new HashMap();
db = DatabaseHelper.getInstance(getApplicationContext());
user = db.getUser();
if mainactivity started from clicking the notification, the user value is always null
but if mainactivity started from launcher, it always return correct data
please help, why is this happen? and how to fix it? thank you
finally after spending a day, I find the solution
actually, the problem is on the way exiting the app,
I was using System.exit(0); , strange behaviour happened after closing the application and reopen the app by clicking the notification dont know why
delete the code and it works perfectly
Once you click on the notification android open you MainActivity than in onCreate() call get the intent you passed in PendingIntent like below
Intent intent = getIntent();
if (intent != null) {
String data = intent.getStringExtra("act");
if (data != null) {
getCallForDataFromSqlite();
}
}
Keep coding :)
It happens because when your activity is started from clicking the notification, your onCreate() won't be called, look here:
https://developer.android.com/reference/android/content/Intent.html?hl=ru#FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_CLEAR_TOP
If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
I have issue in intent of my launcher activity.Scenerio is:
1. Send intents form notification service to my launcher activity
PendingIntent contentIntent = PendingIntent.getActivity(this, TripLoggerConstants.PENDING_TRIPS_NOTIFICATION_ID, new Intent(this, MainActivity.class).putExtra("is_log", true), Intent.FLAG_ACTIVITY_CLEAR_TOP);
2. In my MainActivity i getting this intent. code is:
if(this.getIntent().getExtras()!=null){
boolean isLogNewTripScreen = (boolean)this.getIntent().getExtras().getBoolean("is_log");
}
}
3. this work fine but when i come from notification service,but when i launch from not notification service ,that data in intentis still there.How can i remove that data from intent.
EDIT: I've created a sample application to test this problem and possible solutions. Here are my findings:
If you launch your app from a notification with extras and then later return to your app by selecting it from the list of recent tasks, Android will launch the app again the same way it was launched from the notification (ie: with the extras). This is either a bug or a feature, depending on who you ask.
You'll need to add additional code to deal with this situation. I can offer 2 suggestions:
1. Use FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
When you create your notification, set the flag Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS in the Intent. Then, when the user selects the notification and launches the app from the notification, this will not create an entry for this task in the list of recent tasks. Also, if there was an entry in the list of recent tasks for this application, that entry will also be removed. In this case, it will not be possible for the user to return to this task from the list of recent tasks. This solves your problem by removing the possibility that the user launches the app from the list of recent tasks (but only when the app has been launched from the notification).
2. Detect FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
When the user launches your app from the list of recent tasks, Android sets the flag Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY in the Intent that is passed to onCreate() of your launch activity. You can detect the presence of this flag in onCreate() and then you know that the app has been launched from the recent tasks list and not from the notification. In this case, you can just ignore the fact that the extras in the Intent still contain data.
Choose the solution that best suits the workflow for your application. And thanks for the question, this was an interesting challenge to solve :-)
Additional information:
You are creating the PendingIntent incorrectly. You are calling
PendingIntent contentIntent = PendingIntent.getActivity(this,
TripLoggerConstants.PENDING_TRIPS_NOTIFICATION_ID,
new Intent(this, MainActivity.class).putExtra("is_log", true),
Intent.FLAG_ACTIVITY_CLEAR_TOP);
You are passing Intent.FLAG_ACTIVITY_CLEAR_TOP as the 4th parameter to getActivity(). However, that parameter should be PendingIntent flags. If you want to set FLAG_ACTIVITY_CLEAR_TOP on the Intent, you need to do it this way:
PendingIntent contentIntent = PendingIntent.getActivity(this,
TripLoggerConstants.PENDING_TRIPS_NOTIFICATION_ID,
new Intent(this, MainActivity.class).putExtra("is_log", true)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP), 0);
I noticed that using fragments. I read a QR Code in Activity A that opens fragment 1, send its content to a webservice and if goes right, replace it with fragment 2. When user press back, the onBackPressed in Activity A call finish. If user select the app again in the list, it was opening fragment 1 instead of fragment 2.
I solved that checking in onBackPressed if extra contains a field indicating that fragment 2 was already opened. If true, moveTaskToBack(true) is called instead of finish()
Activity A
#Override
public void onBackPressed() {
Bundle extras = getIntent().getExtras();
if(extras.containsKey(Constants.TICKET_DONT_SHOW_QRCODE_SCREEN)){
moveTaskToBack(true);
}else {
finish();
}
}
Fragment 2
Intent mainIntent = getActivity().getIntent();
mainIntent.putExtra(Constants.TICKET_DONT_SHOW_QRCODE_SCREEN, true);
getActivity().setIntent(mainIntent);
I've tested all the answers of stackoverflow with no luck, what worked for me was this. Create a helper class to check the activity flags. Or a function, it does not matter.
object FlagHelper {
fun notLaunchedFromNotification(activity: AppCompatActivity): Boolean {
return activity.intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY == Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
}
}
Then use as the following code. It returns a boolean so you can check the intent extras when it's false
val notLaunchedFromNotification = FlagHelper.notLaunchedFromNotification(this)
Add android:launchMode="singleInstance" to your launcher activity
and then Use flag Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS while starting your activity
I have some troubles with the management of recommendations (notifications) on an Android TV with the Leanback Launcher.
I use the google sample here to implement my own : https://github.com/googlesamples/androidtv-Leanback
Expected result :
I'm on my activity "MainActivity" (with a webview)
I press HOME, so I'm on the Leanback launcher with recommendation include mines.
I press on one of them
Resume activity "MainActivity" without recreate it with a new Intent with a new extra.
Actually, The resume of the activity without reload the activity works fine, below the creation of the PendingIntent :
private PendingIntent buildPendingIntent(Parcelable media, int id) {
Intent detailsIntent = new Intent(this, MainActivity.class);
detailsIntent.putExtra("media", media);
detailsIntent.putExtra("id", id);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(detailsIntent);
return stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
}
Current result :
I'm on my activity "MainActivity" (with a webview)
I press HOME, so I'm on the Leanback launcher with recommendation include mines.
I press on one of them
My activity receive "onNewIntent" event by in the extrat intent values I have always the same media.
This solution doesn't work, because Google said in a comment of the sample code :
// Ensure a unique PendingIntents, otherwise all recommendations end up with the same
// PendingIntent
detailsIntent.setAction(movie.getId());
So to differentiate all recommandations, I have to set Action with an ID, else, it will be always the last pendingintent sent to my activity. It's my current behavior, I receive in "onNewIntent" always the same "media" and "id" in the intent (the last one), whatever on which recommendation I click, I always get the same Intent.
But if I set the action with an "id", the activity "MainActivity" is recreated, so the resume failed, and the context of my webview is cleared my webview is reloaded :( but I get the good intent with the good media in the extra intent values.
Have you a solution to help me to have the behavior I want ?
To simplify my question, how can I resume my Activity B from a recommendation with the good pendingintent without reload my activity ?
Thank you in advance for your help.
I found a solution. I don't think it's the good one but it works for my case.
PendingIntent pIntent = PendingIntent.getActivity(this, id, detailsIntent, PendingIntent.FLAG_UPDATE_CURRENT);
return pIntent;
So, If I set the "resquetCode" with the id, so Android think it's a different Activity and resume it without recreate a new one.
I want that when the user click on a notification, it brings back the app (instead of create a new instance).
Here is my code (monodroid : in c# but even if you know how to do in android, you may help me).
Intent i = new Intent(context, typeof(MainListProductActivity));
i.AddFlags(ActivityFlags.NewTask | ActivityFlags.BroughtToFront | ActivityFlags.ReorderToFront); // You need this if starting the activity from a service
i.SetAction(Intent.ActionMain);
i.AddCategory(Intent.CategoryLauncher);
context.StartActivity(i);
It works, but it bring back me to the MainListProductActivity. I want that the notification bring back me to the last viewed activity. How to do that ?
More : if the app is not started, I want that the app is launched with the default activity (splashscreen for me) with a parameter.
Thanks.
I solve that by launching a DummyActivity which call Finish on OnCreate.
It works well, even if is not the best way to solve that.
DummyActivity is a great solution. I use it too. Just create dummy and put it instead a needed class on Intent creation:
Intent intent = new Intent(this,DummyActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
This problem was solved for me for Xamarin by using:
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ResetTaskIfNeeded);
I have two (or more) widgets, e.g. A and B, which should launch the same activity passing their appWidgetId in the Intent extras to the activity. This works fine after application install on the first launch from any of the widgets (the activity receives the correct appWidgetId). It also works fine if I press the back button after activity launch and launch the activity from a different widget. However, if I launch the activity from widget A, hit the home button and then launch the activity from widget B (or C or D...) it launches with A's appWidgetId. I'm baffled as to how to fix this. Here is how I am declaring my PendingIntent:
Intent intent = new Intent(context, WidgetActivity.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.setAction(this.getClass().getName() + System.currentTimeMillis());
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
If I understand correctly, I am successfully setting up unique PendingIntents for each widget. Any help most appreciated!
EDIT:
The accepted answer to this question suggests that:
I believe the problem is that you have a PendingIntent that only differs by extra. PendingIntents are cached, so if you use two with the same action and data, they'll overwrite each other.
However, my code creates randomized actions to perform and so I think my PendingIntents differ by more than just extras
Looks like I need to brush up on my activity lifecycle events. The answer was the following code put into my Activity:
#Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
super.onNewIntent(intent);
}
The problem was that, on Home button press, the Activity was holding onto the original Intent which launched it. Then, when the other widget launched the Activity, the original intent was being reused. The above code simply replaces the original intent with the new one and carries on with the remaining lifecycle events.