I have working with widgets which helpfull the user to show important data and open the application from widget.
My widget has 3 buttons and i need to open the app when user click on the different buttons.
i need to open same activity but with different data based on which button user clicked. I have passing different extra with intent
for example
Ist button i set user name as "Ranjith"
and for 2nd button i set user name as "Thomas"
and for 3rd button "Rixon"
But when the activity open it always shows Rixon the third one.
logIntent= new Intent(context, MainActivity.class);
earnIntent=new Intent(context, MainActivity.class);
connectIntent=new Intent(context, MainActivity.class);
logIntent.putExtra("user_name", "Ranjith");
connectIntent.putExtra("user_name", "Thomas");
earnIntent.putExtra("user_name", "Rixon");
}
remoteViews.setOnClickPendingIntent(R.id.bottom_of_widget_log,createPendingIntent(context, 0, logIntent));
remoteViews.setOnClickPendingIntent(R.id.bottom_of_widget_earn, createPendingIntent(context, 1, earnIntent));
remoteViews.setOnClickPendingIntent(R.id.bottom_of_widget_connect, createPendingIntent(context, 2, connectIntent));
AppWidgetManager manager = AppWidgetManager.getInstance(context) ;
manager .updateAppWidget(thisWidget, remoteViews);
You have to check the android:launchMode option in your Manifest,concerning the Activity.
As said in the Documentation,
An activity with the "standard" or "singleTop" launch mode can be instantiated multiple times[....]
In contrast, "singleTask" and "singleInstance" activities can only begin a task. They are always at the root of the activity stack. Moreover, the device can hold only one instance of the activity at a time — only one such task.
Related
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
This is the code I use to create the PendingIntent for my notification.
Intent notificationIntent = new Intent(context, Activity1.class);
PendingIntent myIntent = PendingIntent.getActivity(context, 0,notificationIntent, 0);
This PendingIntent launches Activity1 when the notification is click.
How can I simply reopen the app and go to the most recent Activity (as though clicking on the launcher icon) instead of launching a new Activity when the notification is clicked?
Activity1 is just an example. I have multiple Activity in the app. I just want to reopen the app and go to the most recent Activity
NOTE: this looks like wrong design for me, because notification should allow user to enter activity that is in context with the notification.
Technically, you can create redirecting activity and your notification intent should launch it when tapped. In its onCreate() you check what activity you want user to be redirected (you can keep this info in SharedPreferences, and each activity would write this info in onCreate() (or make that in your base class if you have it). Then in redirector you call regular startActivity() to go last activity and call finish() to conclude your redirector. Moreover, your redirector activity does not need any layout so add
android:theme="#android:style/Theme.NoDisplay"
to its Manifest entry (of course you also need no call to setContentView())
create Activity1 as a singletask activity , by changing the launchMode of the activity to singleTask...
set your activity to launchMode="singleTop" in your Manifest.xml then use this code instead of what you are using above to reopen the active one:
Title = "YourAppName";
Text = "open";
notificationIntent = new Intent(this, Activity1.class);
cIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(getApplicationContext(), Title, Text, cIntent);
You can change the android:launchMode in the manifest file for the activity targeted by the pending intent.
Typically, you can use singleTop, which will reuse the same instance when the targeted activity is already on top of the task stack (i.e.: Activity is shown before you left your app).
You can also consider SingleTask and SingleInstance, if you want to keep only a single instance of the activity.
In my app, i created a custom notification that contain a button that show recent apps(instead of home button long press)
when user open main activity and press home button to go to home screen then drag the notification drawer and click on the button:
Desired result is that the recent apps are shown and the main activity is one of the recent apps.
Actual result is that the recent apps are shown but the main activity is not in them and the main activity resumes.
My code to start "RecentApps (is a dummy class that show recent apps)" class with pending intent
Intent recentAppIntent = new Intent(getBaseContext(), RecentApps.class);
PendingIntent pendingrecentAppIntent = PendingIntent.getActivity(getBaseContext(), 1, recentAppIntent, 0);
notificationView.setOnClickPendingIntent(R.id.recentAppButt, pendingrecentAppIntent);
I think that the problem is getBaseContext, so when the main activity is alive and not finished the recent apps are shown but with context is the main activity.
I tried getApplication and getApplicationContext but not working.
I also tried to use flags for "recentAppIntent" but it is not working, It is a half solution to use
recentAppIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
but it not what i need.
So, my question is "How to finish the main activity in which the pending intent starts".
Thanks in advance, Mostafa
You need to ensure that your MainActivity and your RecentApps don't belong to the same task. The "Recent apps" doesn't actually show recent apps. It shows recent tasks.
To make sure that your RecentApps isn't in the same task as your MainActivity, you can add the following to the <activity> definition in the manifest for RecentApps:
aandroid:taskAffinity=""
Also, when creating the notification, add FLAG_ACTIVITY_NEW_TASK to the Intent, like this:
Intent recentAppIntent = new Intent(getBaseContext(), RecentApps.class);
recentAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingrecentAppIntent = PendingIntent.getActivity(getBaseContext(), 1, recentAppIntent, 0);
notificationView.setOnClickPendingIntent(R.id.recentAppButt, pendingrecentAppIntent);
I think FLAG_ACTIVITY_CLEAR_TOP will help as a flag.
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Explanation for Intent flags are available here: link
I have been struggling with this problem for a while now. I have a widget which displays summary of a cooking recipe. The widget is clickable so whenever user clicks on it the new activity is opened with a full description of that recipe. The problem is that sometimes when the widget is clicked it opens a wrong activity. Let me give you an example:
User clicks on widget and activity A is opened
User starts activity B (e.g. recipe index) from the activity A.
User starts activity C from activity B.
User presses Home button.
User clicks on the widget again and the activity C is displayed instead of A
I tried setting a compibation of those three flags which helps in solving only a half of the problem:
openIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
By using above flags I managed to display a correct activity (A) until I do the following:
User opens activity A from the widget
User moves to activity B and opens activity A by clicking on new recipe
New recipe is displayed to the user
User clicks Home button and clicks on the widget.
Activity A is displayed (the right one) but with different recipe.
From now on if I move to different activities B or C and click Home and then widget again the activity A is not displayed but the one which was visible before pressing Home button.
I hope I explained it in enough details. I would be really grateful for your help because this thing drives me crazy!
Updated:
This is my pendingIntent:
Intent openIntent = new Intent(context, ProfanityDefinition.class);
openIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
openIntent.setData(Uri.parse(openIntent.toUri(Intent.URI_INTENT_SCHEME)));
Bundle bundle = new Bundle();
bundle.putBoolean("widgetRequest", true);
openIntent.putExtras(bundle);
PendingIntent openPendingIntent = PendingIntent.getActivity(context, 0, openIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_content, openPendingIntent);
Thanks
Show the code for creating the PedningIntent. If you are passing extras to your activity, be aware that two intents that differ only by extras are treated as equivalent. You probably want to pass the PendingIntent.FLAG_CANCEL_CURRENT when you create the PendingIntent to make sure your intent is not reused.
I am having problems launching my application from my widget when it's clicked upon.
Here is a cut of some code
// Create an Intent to launch activity
Intent intent = new Intent(context, Entry_MainTabView.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
updateViews.setOnClickPendingIntent(R.id.Widget, pendingIntent);
Now take the scenario.
I launch my app, exit to the home page , then click on my widget.
It launches a second instance of the application, so when I hit "back" , the application goes away and reveals the other copy. I then hit back again and finally go back to the homescreen.
How can I make the Intent only create a new instance if none already exists in ram ?
Have you looked at singleInstance and singleTask launch modes of an activity? This extract from Pro Android 2 indicates that there is no documented way of ensuring that there is only one instance of the widget running.