I have a context menu with a menu item that is supposed to start an intent:
#Override
public void onCreateContextMenu(ContextMenu menu, View view,
ContextMenuInfo menuInfo) {
MenuItem item = menu.add(menuItemText);
item.setIntent(intent);
This used to work, but in newer Android versions, it throws an exception:
Calling startActivity() from outside of an Activity context requires
the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
Adding this flag would be the easy way out, but I don't want to create a new task since this is supposed to be part of the application's activity stack. The problem is that the system calls startActivity which the context of the item, which in this case is a DecorContext, not an Activity. Since this is all handled by the framework, I have no control over this.
Is there a good solution to this other than setting the flag or handling the operation in onContextItemSelected?
This is because Android uses DecorContext for Activities starting in Android 27.
You can see the change here.
You can confirm this in the system level by looking inside of line 319 in PhoneWindow. Notice that when the PhoneWindow is being constructed from an Activity, mUseDecorContext is always set to true. This means that your Menu will be built with the DecorContext every time.
My understanding is that having a separate DecorContext for ContextMenu is intentional. ContextMenus are meant to "float" above content and thus act as a separate menu from the content on which they are being presented.
Depending on what you are using ContextMenu for, you might have to consider waiting to build the Intent until onContextItemSelected, even though you mentioned you would like to avoid that situation. Alternatively, you might have to use some form of IPC to wrap and send your intent back to the Activity. We use the RxBus pattern for this rare use-case. Alternative options are LocalBroadcastManager and EventBus by GreenRobot. Hopefully, this helps get you started on alternative solutions. Let me know if you have questions.
Exception is because you may have not overridden onContextItemSelected method.You have to override onContextItemSelected() as below :
#Override
public boolean onContextItemSelected(MenuItem item) {
startActivity(item.getIntent());
return true;
}
Hope this will help you.
You can try
#Override
public void onCreateContextMenu(ContextMenu menu, View view,
ContextMenuInfo menuInfo) {
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
MenuItem item = menu.add(menuItemText);
item.setIntent(intent);
}
I'm new to android studio applications, so i'm not sure if either will work.
Related
I'm having type issues when attempting to inflate a ContextMenu while making use of the ActionBarSherlock library, which as you know ultimately mimics/implements the Android support library.
There is a SherlockFragmentActivity which sets the layout content and within that content exists two fragments. One of those fragments is a SherlockListFragment. Within the onCreate of the SherlockListFragment I make a call to register for the ContextMenu.
registerForContextMenu(getListView());
The problem stems when attempting to inflate the menu.
listView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
#Override
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
MenuInflater inflater = getSherlockActivity().getSupportMenuInflater();
inflater.inflate(R.menu.lot_menu, contextMenu);
}
});
I am unable to call inflate due to the type specified within the method parameters, which it expects as com.actionbarsherlock.view.Menu however the passed in type is android.view.ContextMenu.
I seem to be missing something as inflating a Menu within the action bar was trivial however the ContextMenu seems to be posing issues when making use of the support framework.
How do I register appropriately to make use of the support framework as needed and subsequently inflate the ContextMenu?
Try using getMenuInflater() instead of getSupportMenuInflater() for inflating into a ContextMenu.
It looks like the onCreateContextMenu insn't being called at all. In my onCreate for my ListActivity I have:
list = getListView();
registerForContextMenu(list);
(I know it's redundant, and I've just passed getListView() with the same results).
Here is my onCreateOntextMenu;
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
Log.d("LM", "onCreateContextMenu");
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.context_landmarks, menu);
}
The log never gets generated. Doesn't anyone have any suggestions?
My thought is ListView intercepting the event and not going into contextMenu behaviour. It make sense to me because the OnItemLongClickListener behaviour overlaps contextMenu's. If not how it can recognize between contextMenu and OnItemLongClickListener?
Just remove youwidget.setonLongclicklistener and yourwidget.setLongClickable
And then add registerforContextmenu(yourwidget) in onCreate()
then add code according to the widget used.
Hope It will be helpful.
My problem was very closely related to lulumeya's answer, which pointed me in the right direction. I've done context menus many times before and somehow never ran into this until now.
I was calling View.setOnClickListener(listener) in Adapter.getView(...) when it should be ListView.setOnItemClickListener(listener) to avoid conflicting with the context menu.
In general, I'm sure OnItemClickListener is more optimized, especially since only one listener instance is used instead of creating a new instance every time a view is created or recycled.
Try to locate registerForContextMenu(list); as ur last method to call in the onCreate method.
I mean this method shoul be called after the list adapter is called not before.
I had that problem and could only resolve it by ensuring
that because the resp. Activity registered the Views, the same Activity must then also override onCreateContextMenu(); doing this in a Fragment will not work
since I used an additional Fragment creating the Adapter (and registering with it) the Fragment not the Activity must override onContextItemSelected().
I'm considering abandoning long press popup in favor of a Youtube-style button at the right margin of the cards popping up a menu that does not fade everything else to background---what's the search term for that btw?
You have to call registerForContextMenu(View view) method in onCreate(Bundle savedInstanceState).
Hope you can help me with the following:
I need to add an action in the Context Menu that pops up after a
Long Press of an image in the Browser (the one that has 'Save Image', 'Copy Image', 'View Image', 'Set as a wallpaper', etc. )
As a result of choosing my action it should call my service and
etc....
I don't want my app to overwrite all the context menu of the browser
but only add an action to it.
I haven't found any information on how to do this. Is it possible?
Thanks!
In short, you can't do this. The browser is just an application like yours. If you were developing the browser, how you would expose such functionality from within your browser application?
Android gurus: Am I missing anything here?
As a side note, the closest you can come from doing that is define Intent.ACTION_VIEW and on resources and hope that the browser uses an IntentChooser, in which case, your app (along with others) would show up.
General actions are defined by the Android Intent system (http://developer.android.com/reference/android/content/Intent.html).
In accordance to the above aswer.
No you cannot add a menu item to any application.
When you use call and see skype, its just that skype has capabilities of handling calls.
And has registered in the Manifest.
Hence, when the call action is raised all the applications with the Manifest registered will be given as option.
The similar behavior can be achieved by your application by simply declaring appropriate fields in the manifest file.
For example if you want to handle the images all you need to do is handle the mime in data section of your intent filter.
Okay, if you want to add a context menu to the web view you will need to do the following. In the main application class that extends DroidGap you will need to add the following line to the onCreate method:
this.registerForContextMenu(this.appView);
then you'll need to add the following two methods to the same Java class:
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.example, menu);
}
Of course you'll need to update the R.menu.example to the name of your menu's XML file.
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case R.id.settings:
this.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS));
return true;
case R.id.help:
this.appView.sendJavascript("navigator.notification.alert('No help')");
return true;
default:
return super.onContextItemSelected(item);
}
}
and in this method you'll need to handle all your menu option activities.
Halo,
My ideia is to show a Context Menu by clicking on one of the options menu.
I don't think it will be quite difficult but I'm not being able to get the View in the OptionsMenu class.
So actually it is just call the showContextMenu() on the OptionsMenu class.
Can somebody give me a hint?
ty!
It's possible to call a Context Menu by means other than a long press. If you implement your menu options within your activity, using an inner class for instance, you should be able to call your context menu:
yourView.showContextMenu();
Remember to register your context menu at onCreate:
registerForContextMenu(yourView);
Finally made it, and it was a quite simple solution.
Basically I pass the View, to the OptionsMenu constructor.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_event);
View v = findViewById(R.id.activity_event);
registerForContextMenu(v);
options = new Options(getApplicationContext(), getMenuInflater(), v);
fillData();
}
...
private class Options extends ActivityOptionsMenu {
public Options(Context c, MenuInflater mi, View v) {
super(c, mi, v);
}
}
...
private abstract class ActivityOptionsMenu {
...
public void onMenuItemSelected(int featureId, MenuItem item) {
switch (item.getItemId()) {
case R.id.directions:
v.showContextMenu();
}
}
}
Thanks for all the help.
My ideia is to show a Context Menu by clicking on one of the options menu.
AFAIK, you cannot show a context menu from a long-tap on an option menu choice.
I don't think it will be quite difficult but I'm not being able to get the View in the OptionsMenu class.
The View is not exposed to you.
The only way to literally do what you seek is to not use the standard Android option menu. You can watch for the MENU key via onKeyDown() in your activity, at which point you can display whatever you want, including something that supports context menus.
However, context menus are not particularly popular among users, simply because they are not very discoverable. Users never read the documentation, even if it is supplied, and they tend not to randomly stab the screen to see if a menu will pop up. They will be even less likely to decide to hold down a fake option menu choice to see if a context menu will pop up.
Hence, I really recommend you consider some other approach, for improved usability.
I have an activity that on it's onCreate method it does:
registerForContextMenu(theView);
and in onCreateContextMenu:
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(blablabla);
This works great, but the problem is that the context menu disappears when the screen rotates.
How to fix this?
Thanks for reading!
Here's the solution:
The contextMenu disappeared because by default when rotating android calls destroy() and then onCreate() but :
If you don't want Android to go through the normal activity destroy-and-recreate process; instead, you want to handle recreating the views yourself, you can use the android:configChanges attributes on the element in AndroidManifest.xml.
<activity
android:name=".SmsPopupActivity"
android:theme="#android:style/Theme.Dialog"
android:launchMode="singleTask"
android:configChanges="orientation|keyboardHidden"
android:taskAffinity="net.everythingandroid.smspopup.popup">
</activity>
This way my contextMenu is not closed when my phone rotates, because onCreate() method is not called.
See also:
Developing Orientation-Aware Android Applications
activity-restart-on-rotation-android
According to the Android developers blog:
The Activity class has a special method called onRetainNonConfigurationInstance(). This
method can be used to pass an
arbitrary object your future self and
Android is smart enough to call this
method only when needed. [...]
The implementation can be summarized
like so:
#Override public Object
onRetainNonConfigurationInstance() {
final LoadedPhoto[] list = new LoadedPhoto[numberOfPhotos];
keepPhotos(list);
return list; }
In the new activity, in onCreate(),
all you have to do to get your object
back is to call
getLastNonConfigurationInstance(). In
Photostream, this method is invoked
and if the returned value is not null,
the grid is loaded with the list of
photos from the previous activity:
http://android-developers.blogspot.com/2009/02/faster-screen-orientation-change.html?utm_source=eddie
I may be wrong, but from what I know you cant persist it, however (this is the part where i may be wrong in) you could open the menu dynamically after you rotate. Giving the illusion of persistence.