The Android app uses a library project to contain most of the app code, as there are two versions of the app built from the core source. Since an IntelliJ IDEA update (to v11) I'm getting this warning on each of the case statements below:
Resource IDs cannot be used in a switch statement in Android library modules
Here's the code:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_one: // Build error here
// Do stuff
return true;
case R.id.menu_item_two: // Build error here
// Do stuff
return true;
default:
return super.onOptionsItemSelected(item);
}
}
OK, so if I can't reference them via their ID, how DO I reference them?
Substitute the switch with an if/else if construct.
int id = item.getItemId();
if(id == R.id.menu_item_one) {
// ...
}
else if(id == R.id.menu_item_two) {
// ...
}
This is neccessary since ADT 14 because the final modifier was removed from id's in the R class.
See Non-constant Fields in Case Labels
Related
I made a project in Android Studio with Google Cloud Platform Java sample project from github a year ago. It was working correctly by then but a month ago when I opened the project, I faced the following error:
error: an enum switch case label must be the unqualified name of an enumeration constant
I have checked other solutions on SO,Ex, but on the StreamingRecognizeResponse class I saw the code is written as the solution suggests. Ex:
protected final Object dynamicMethod(
com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,
Object arg0, Object arg1) {
switch (method) {
case NEW_MUTABLE_INSTANCE: {
return new com.google.cloud.speech.v1.StreamingRecognizeResponse();
}
case IS_INITIALIZED: { //**clicking on first error takes to this line.** but it is as solution suggests.
return DEFAULT_INSTANCE;
}
case MAKE_IMMUTABLE: {
results_.makeImmutable();
return null;
}
case NEW_BUILDER: {
return new Builder();
}
case VISIT: {...
...................
I can't compile my project anymore and I need to fix this error.
Any suggestion to solve this problem would help.
It is unclear which Java sample you are referring to, but com.google.protobuf enumeration GeneratedMessageLite.MethodToInvoke generally has these constants:
Object dynamicMethod(MethodToInvoke method, Object arg0, Object arg1) {
switch (method) {
case GET_DEFAULT_INSTANCE: {
return DEFAULT_INSTANCE;
}
case GET_PARSER: {
break;
}
case IS_INITIALIZED: {
break;
}
case MAKE_IMMUTABLE: {
results_.makeImmutable();
return null;
}
case MERGE_FROM: {
break;
}
case NEW_BUILDER: {
return new Builder();
}
case NEW_INSTANCE: {
return new com.google.cloud.speech.v1.StreamingRecognizeResponse();
}
case PARSE_PARTIAL_FROM: {
break;
}
}
}
There is no NEW_MUTABLE_INSTANCE and there is no VISIT. One can also list them:
for (GeneratedMessageLite.MethodToInvoke c : GeneratedMessageLite.MethodToInvoke.values()) {
System.out.println(c);
}
Also see StreamingRecognizeResponse.
I've recently upgraded to cordova 5 and removed/recreated android platform in version 4.0.0 and uninstalled/reinstalled all plugins.
I also had to upgrade android sdk to sdk 22 instead of 21.
Since the update, I'm no more able to catch the menubutton event as described in the cordova documentation.
As it's still referenced in the edge docs, I assume it should still be working and I've seen nothing about this in the release notes.
back button is still working.
I tried to set the target-sdk to 19, it did not solve anything about the issue.
Edit:
I've dug into cordova source code and found in CordovaWebViewImpl.java I found a suspicious TODO comment :
public void setButtonPlumbedToJs(int keyCode, boolean override) {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_BACK:
// TODO: Why are search and menu buttons handled separately?
if (override) {
boundKeyCodes.add(keyCode);
} else {
boundKeyCodes.remove(keyCode);
}
return;
default:
throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
}
}
Well my answer would be "IT SHOULDN'T!!!!"
Cordova makes a list of keycode to handle but does not add the menu button and later on the keycode is compared to KeyEvent.KEYCODE_MENU only after the keycode has been skipped because it's not in the list.
I've tried to add a case for the menu button, but it turns out the function is only called with the code of the back button.
So now I know why it doesn't work but still not how to fix it.
Edit 02/2016:
As per latest Jira, the support of the menubutton is now fixed in java part in Cordova Android 5.1.0 but still not initialized from the javascript.
For the moment, as indicated by Jira user Keith Wong, you need to add a javascript call before you add your event listener :
document.addEventListener("deviceready", function() {
...
navigator.app.overrideButton("menubutton", true); // <-- Add this line
document.addEventListener("menubutton", yourCallbackFunction, false);
...
}, false);
clarent's answer didn't do it for me, the menu button still didn't respond.
I tried several patches, one other suggestion to disable the boundKeyCodes check completely didn't do it either, because then the backbutton behaviour would be compromised.
The clean way to get the old behaviour back should be as follows.
The boundKeyCodes check ensures, that custom behaviour is only executed when there actually is a custom event handler bound to the event. But binding an event handler to "menubutton" in your app's JS code no longer triggers the menubutton key code to be added to the boundKeyCodes list.
This is because the setButtonPlumbedToJs method is never executed for the "menubutton" handler in the first place AND even if it would, the switch statement in this method doesn't handle KEYCODE_MENU.
You can get that behaviour back quite easily, first you will have to apply the change suggested by clarent:
Handle KEYCODE_MENU
in CordovaLib/src/org/apache/cordova/CoreAndroid.java (around line 357, setButtonPlumbedToJs) add a case statement after the KEYCODE_BACK entry like this:
public void setButtonPlumbedToJs(int keyCode, boolean override) {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_MENU:
// TODO: Why are search and menu buttons handled separately?
if (override) {
boundKeyCodes.add(keyCode);
} else {
boundKeyCodes.remove(keyCode);
}
return;
default:
throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
}
}
Then ensure that setButtonPlumbedToJs actually gets executed. You need two more changes for that.
Add framework handler
In CordovaLib/src/org/apache/cordova/CoreAndroid.java (around line 243, overrideButton) make the method look like this (add the last else-if clause):
public void overrideButton(String button, boolean override) {
if (button.equals("volumeup")) {
webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);
}
else if (button.equals("volumedown")) {
webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);
}
else if (button.equals("menubutton")) {
webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_MENU, override);
}
}
Add javascript handler call
In platform_www/cordova.js (around line 1532, bootstrap) change this line:
cordova.addDocumentEventHandler('menubutton');
to this:
var menuButtonChannel = cordova.addDocumentEventHandler('menubutton');
menuButtonChannel.onHasSubscribersChange = function() {
exec(null, null, APP_PLUGIN_NAME, "overrideButton", ['menubutton', this.numHandlers == 1]);
};
This will trigger the frameworks overrideButton method as soon as an event handler is added to "menubutton".
That should do it. I also added this solution as a comment to
https://issues.apache.org/jira/browse/CB-8921
and might be filing a pull request shortly.
Just add to function setButtonPlumbedToJs one line : case KeyEvent.KEYCODE_MENU:
public void setButtonPlumbedToJs(int keyCode, boolean override) {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_MENU:
So in onDispatchKeyEvent switch will work:
} else if (boundKeyCodes.contains(keyCode)) {
String eventName = null;
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
eventName = "volumedownbutton";
break;
case KeyEvent.KEYCODE_VOLUME_UP:
eventName = "volumeupbutton";
break;
case KeyEvent.KEYCODE_SEARCH:
eventName = "searchbutton";
break;
case KeyEvent.KEYCODE_MENU:
eventName = "menubutton";
break;
case KeyEvent.KEYCODE_BACK:
eventName = "backbutton";
break;
}
Now with cordova-android 5.1, the code has changed and my patch didn't work any-more (and sadly, with no patch the menu button is still not working in this version).
As I wanted to be able to upgrade the platform without having to review the code each time, I searched for a new way to get the menu button working again.
In cordova android 5.1 it turns out that everything is here in the java code for the button to be working, except that the menu button key is never added to the boundKeyCoded array.
It turns out that this array needs to be filled by a call from javascript (which is done for the back button and volume button, but neither for the search button or the menu button).
The code that is missing is something like that :
exec(null, null, APP_PLUGIN_NAME, 'overrideButton', ['menubutton' , true]);
(a js call to the java function overrideButton from CoreAndroid.java to tell to add the menu button key to the boundKeyCodes array.
I think this call should be added to platform.js, but since platform.js is used to build cordova.js during the platform add, I decided to make a after_platform_add hook that patchs the cordova.js file.
The advantage of this hook is that there's no java change and it should work even if you use a different webview like crosswalk.
So, first, in config.xml, in the android section add the hook :
<platform name="android">
....
....
<hook type="after_platform_add" src="scripts/android/patch_menubutton.js" />
....
....
</platform>
Then, in the scripts folder add the hook file patch_menubutton.js :
#!/usr/bin/env node
module.exports = function(ctx) {
var fs = ctx.requireCordovaModule('fs'),
path = ctx.requireCordovaModule('path');
var CordovaJSPath = path.join(ctx.opts.projectRoot, 'platforms/android/platform_www/cordova.js');
var data = fs.readFileSync(CordovaJSPath, 'utf8');
var result = data.replace(new RegExp("cordova\\.addDocumentEventHandler\\('menubutton'\\);", "g"), "cordova.addDocumentEventHandler('menubutton'); exec(null, null, APP_PLUGIN_NAME, 'overrideButton', ['menubutton' , true]);");
fs.writeFileSync(CordovaJSPath, result, 'utf8');
}
(it looks for the initialisation of the event handler for the menu button and appends the call to the overrideButton function, like described in the last part of FewKinG's answer)
I have an application about pmt function. However there are so many conditions that need to be handled. Somehow the app will not work with having more than 12 if-else. I want to use switch case, but i still not really understand how to use switch case(been 1 and half month since my 1st try using eclipse).Any example will be highly appreciated.
here is my example code:
if(String1.toString().equals("condition1")){
//do something
if(String2.toString().equals("condition1.1")&& String3.toString().equals("condition1.2")){
//do something else
}
.
.
.
.
.
if(String2.toString().equals("condition1.##")&& String3.toString().equals("condition1.##")){
//do something else
}
}
else if(String1.toString().equals("condition2")){
//do something
if(String2.toString().equals("condition2.1")&& String3.toString().equals("condition2.2")){
//do something else
}
.
.
.
.
.
if(String2.toString().equals("condition2.##")&& String3.toString().equals("condition2.##")){
//do something else
}
}
if(String1.toString().equals("condition3")){
//do something
if(String2.toString().equals("condition3.1")&& String3.toString().equals("condition3.2")){
//do something else
}
.
.
.
.
.
if(String2.toString().equals("condition3.##")&& String3.toString().equals("condition3.##")){
//do something else
}
}
and still keep going....to handle all possibilities .I am wondering, How to do this in switch case . Or a better implementation if we have 3 times 3 conditions. For example a,b,c(suppose these three conditions can only be used once) and d,e,f and g,h,i then condition 1 is a,d,g ; condition 2 is a,d,h condition 3 is a,d,i ; condition 4 a,e,g........on so on
Note:Suppose that the API version is 8-11 (old android)
thanks
The answer is dependent on your target version of android. From KitKat and upwards (API Level 19+), Java 7's switch (String) is available. I'd also strongly suggest trying to group the subcases (condition n.x) into different methods. It just gets very unwieldly quickly, otherwise:
switch (String1.toString) {
case "condition1":
handleCase1(String2, String3);
break;
case "condition2":
handleCase2(String2, String3);
break;
}
If that still results in too complex code, you can try a lookup table together with a command pattern:
class ConditionKey {
final String String1;
final String String2;
final String String3;
public int hashCode(); // hash strings
public boolean equals(); // compare strings
}
interface ConditionCommand {
// use whatever arguments the operation needs, you can also
// add fields and initialize in the constructor
void perform(final ConditionKey key, /* [...] */);
}
Map<ConditionKey, ConditionCommand> actionMap = new HashMap<>();
actionMap.put(
new ConditionKey("condition1", "condition1.1", "condition1.2"),
new ConditionCommand() {
void perform(final ConditionKey key) {
// perform actions that need to be done
}
}
);
And then instead of the if-else or switch-case:
[...]
ConditionKey key = new ConditionKey(string1, string2, string3);
// get the action from the map
ConditionCommand command = actionMap.get(key);
// perform the command
command.perform(key);
since java 1.7 switch on string is supported.
you could annidate two switch:
switch(String1) {
case "condition1": {
switch(String2) {
case "condition1.1":
break;
// ... other cases
default:
break;
}
}
break;
// ... other cases
default break;
}
I can't for the life of me fix this. It is returning an error on else. I tried everything on all the other threads that had the same problem, but it didn't work.
#Override
public boolean onOptionsItemSelected(MenuItem item) { //this method is used for handling menu items' events
// Handle item selection
switch (item.getItemId()) {
case R.id.goBack:
if(myWebView.canGoBack()) {
myWebView.goBack();
}
return true;
else
return super.onOptionsItemSelected(item);{
}
}
}
Eclipse is complaining because the else statement does not follow an if statement -- there's a return true in between (which by the way prevents any code after it from being executed). Fixing your indentation and code formatting helps discover (and also prevent) simple mistakes like this.
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.goBack:
if (myWebView.canGoBack()) {
myWebView.goBack();
return true;
}
}
return super.onOptionsItemSelected(item);
}
The error is because in java (and most-likely any programming language that defines if...else blocks such as c#, c, c++, etc.) the else block (if present) must come right after an if block or an else if statement definition any other statement between the if and else is illegal. However, you have a return statement right before the else block which is illegal and useless because any code blocks after a return statement becomes "unreachable"
You can change your code to...
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.goBack:
if (myWebView.canGoBack()) {
myWebView.goBack();
return true;
}
break;
default:
return super.onOptionsItemSelected(item);
}
}
Hi I´m new to Android and Eclipse. I have just following the tutorial from developer.android.com. Right now I´m in adding ActionBar
Right now I´m at this part
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_search:
openSearch();
return true;
case R.id.action_settings:
openSettings();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
I have received an error for openSearch() and openSettings(). It said that The method openSettings() is undefined for the type DisplayMessageActivity. What shoud I do now?
Thanks
openSearch() and openSettings() are methods that the author of the tutorial created in order to perform other operations. Search well into the code, there must be somewhere the declaration of those methods, if the author made them visible.
They should look something like this:
public void openSearch() {
//Do something here.
}
public void openSettings() {
//Do something here.
}
Replacing the //Do something here with the code implementation present in the tutorial.
Im up to the same section as you, they haven't provided the methods but you have to implement them as stated above.
However I found code to open up the device settings using this code in the switch;
case R.id.action_settings:
startActivity(new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS));
return true;
define them.
You're basing your code on an incomplete snippet. That snippet makes no expectation of what it means to search or create settings in your app... that's your job to implement. This snippet is only concerned about showing you how to establish the action bar, not the whole application.
The methods openSearch() and openSettings() should be defined. Use the following code. It'd help..
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id){
case R.id.action_search :
startActivity(new Intent(Settings.ACTION_SEARCH_SETTINGS));
return true;
case R.id.action_settings :
startActivity(new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS));
return true;
default :
return super.onOptionsItemSelected(item);
}
}
Maybe you should code those methods?
private void openSearch(){
//your code here
}
private void openSettings(){
//your code here
}
Those two methods are just examples how selecting an option can start an action. The implementation was not provided because it was irrelevant to the example. Note that it is not a tutorial, but a single and un-compile-able example of how to add behavior to an options item.