After defining FLAG_ACTIVITY_NO_ANIMATION for the back arrow in the action bar to correct to animation when the toolbar back arrow is clicked, a warning is then returned. What is the best way to get rid of this warning?
Method invocation 'addFlags' may produce 'java.lang.NullPointerException'
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
final Intent intent = getParentActivityIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
Wrap it into an if intent != null.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
final Intent intent = getParentActivityIntent();
if(intent != null){
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
}else{
//Do some error handling.
}
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
From the doc of the getParentActivityIntent:
#return: a new Intent targeting the defined parent of this activity or null if
there is no valid parent.
This method returns null only if there is no parent Activity and so they marked the #Nullable annotation for the return value. That's why you are getting the warning.
If you are sure that you have defined the parent Activity in the manifest, you don't have to worry about the NullPointerException, you can suppress this warning.
To suppress, you have to add #SuppressWarnings("ConstantConditions") to the method.
And it is a good practice to add a comment above the annotation explaining why you have suppressed the warning.
Related
Im able to send data to parent activity when back button is pressed.
However, for up button i cannot implement similar logic and data is not getting returned to parent activity why is that ?
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
.....
Intent resultIntent = new Intent();
resultIntent.putExtra("noteJSON", noteJSON.toString());
setResult(Activity.RESULT_OK, resultIntent);
this.finish();
return true;
}
return super.onOptionsItemSelected(item);
}
Im using startActivityForResult to start childactivity. On onactivityresult basically handling the intent info. When back, button is pressed its working. When UP is pressed onactivityresult never gets executed. Thats the problem
When you call navigateUpFromSameTask method, it finishes the current activity and starts (or resumes) the appropriate parent activity. If the target parent activity is in the task's back stack, it is brought forward. As a result onActivityResult won't be called.
If you want to ensure result is returned via onActivityResult then remove call to navigateUpFromSameTask as follows:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
....
Intent resultIntent = new Intent();
resultIntent.putExtra("noteJSON", noteJSON.toString());
setResult(Activity.RESULT_OK, resultIntent);
this.finish();
return true;
}
return super.onOptionsItemSelected(item);
}
try below
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
.....
startActivity(new Intent(YourActivity.this,ParentActivity.class).putExtra("noteJSON", noteJSON.toString()));
return true;
I have two layouts, A and B. The app launches the A_layout, and through a button you can go to the B_layout. On default when you press the back button the app closes, doesnt matter if the app is on the A or B layout. When I override the back button to set the content view always on the layout A whenever the back button is pressed, then I cant open the B activity anymore through the button. How do I need to override the method correctly? :)
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
setContentView(R.layout.activity_main);
return true;
}
return super.onKeyDown(keyCode, event);
}
activity_main = A layout
Do I need to make Intents there?
You can override the onBackPressed function:
#Override
public void onBackPressed() {
super.onBackPressed();
Intent intent = new Intent(getApplicationContext(), ActivityA.class);
startActivity(intent);
finish();
}
When finsihing the activity is destroyed
I am using the same tabBar across multiple Activities. And since there are extensive logic involved for onOptionsItemSelected, I want to write the relevant methods once and then reuse them. Hence I am deciding to created a super class called CustomActionBarActivity and then have the children activities extend it. One particular problem I need help with is how can I tell which child has caused the onOptionsItemSelected to be called? To elucidate, I will present the general code and then a failed attempt at a solution.
Here is the general code
public class CustomActionBarActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.tab_dog:
startActivity(new Intent(this, DogActivity.class));
return true;
case R.id.tab_cat:
startActivity(new Intent(this, CatActivity.class));
return true;
case R.id.tab_mouse:
startActivity(new Intent(this, MouseActivity.class));
return true;
case R.id.tab_goose:
startActivity(new Intent(this, GooseActivity.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
Failed attempt
If I try, for instance,
case R.id.tab_dog:
if(!(this instanceof DogActivity))
startActivity(new Intent(this, DogActivity.class));
then I get a compile error such that CustomActionBarActivity is not compatible with DogActivity. Thanks for any help you can provide.
Instead of having your parent class inspect the children using reflection (which is pretty fragile since it doesn't scale with the number of children subclasses you create), maybe you could take advantage of dynamic dispatch instead.
For example, maybe you could declare an abstract method in your parent activity like:
protected abstract void onTabItemSelected(MenuItem item);
Then your children activities can override this method depending on the desired behavior. For example, DogActivity might implement it like this:
protected boolean onTabItemSelected(MenuItem item) {
if (item.getItemId() != R.id.dog_tab) {
startActivity(new Intent(this, DogActivity.class));
return true;
}
return false;
}
The onOptionsItemSelected method would then be implemented like this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (onTabItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
Let me know if I misunderstood the question. Either way, you might be able to modify this approach to suit your use case.
Below is the code for my submenu buttons and I'm trying to make it delete the note and return to the main list view. The delete option is called "Red" for now.
I copied my delete code from my main activity thinking it would work, but it does not. I'm very new to android coding, so help would be appreciated.
This is how I delete in my Main Activity.java
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
currentNoteId = (int)info.id;
menu.add(0, MENU_DELETE_ID, 0, "Delete");
}
#Override
public boolean onContextItemSelected(MenuItem item) {
if (item.getItemId() == MENU_DELETE_ID) {
Noteitem note = notesList.get(currentNoteId);
datasource.remove(note);
refreshDisplay();
}
return super.onContextItemSelected(item);
}
Here is my code for my NoteEditorActivity.java
Again I'm trying to delete, but I can't seem to figure out how to delete the note from the submenu.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_exit:
EditText et = (EditText)findViewById(R.id.noteText);
if (et.length() > 0) {
saveAndFinish();
}
else
{
finish();
}
case R.id.menu_red:
currentNoteId = (int) MENU_DELETE_ID;
datasource.remove(note);
return true;
default:
return super.onOptionsItemSelected(item);
}
Put break statements in your switch case
switch (item.getItemId())
{
case R.id.action_exit:
EditText et = (EditText)findViewById(R.id.noteText);
if (et.length() > 0){
saveAndFinish();
}else{
finish();
}
//you are missing this!!!
break;
case R.id.menu_red:
datasource.remove(note);
finish();
break;
default:
return super.onOptionsItemSelected(item);
break;
}
Try reading this here also: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
its just weird..you aren't calling notesList.add() method anywhere in your code, so I just think it's empty at all..
you are certainly missing the break statement there, but I guess it is not the issue why your note is not deleted after clicking in the menu item. You are saving your note in the "previous" (in terms of backstack) activity? if so, you might try to just alter the return code for the setActivityResult() call (or add some extras to the intent) and then check for it in your onActivityResult() callback..
because right now everytime you close the activity via back key, the notes is saved (the saveAndFinish() method gets called);
please describe better where you actually do save notes (to DB or so) and where you wanna delete them..I could then provide you with some code snippet probably.
I have an Activity in a Library that has a menu in it. The menu has all the standard attributes as well as the #Override on onCreateOptionsMenu and onOptionsItemSelected.
In my actual project which imports above library I have another activity that extends teh above activity. For this specific implementation of this program I want to have a different menu on this activity so inside this activities code base add add onCreateOptionsMenu and onOptionsItemSelected with the proper #Override, but i get the menu from the Library, not the override in the library.
What could I be doing wrong?
Base Class:
public class ListItems extends ListActivity {
public static final int LOGOUT = 0;
public static final int HISTORY = 1;
public static final int REFRESH = 2;
#Override
public boolean onCreateOptionsMenu(Menu menu){
menu.add(0, LOGOUT ,0,"Log Out");
menu.add(0,HISTORY,0,"Order History");
menu.add(0,REFRESH,0,"SMS");
return true;
}
#Override
public boolean onOptionsItemSelected (MenuItem item){
TextView textView = (TextView)findViewById(com.imobileminutes.library.R.id.text);
switch (item.getItemId()){
case LOGOUT:
Intent logOut = new Intent(ListItems.this,MainScreen.class);
startActivity(logOut);
finish();
return true;
case HISTORY:
Intent orderHistory = new Intent(this,OrderItems.class);
startActivity(orderHistory);
return true;
case REFRESH:
Intent orderHistory = new Intent(this,OrderItems.class);
startActivity(orderHistory);
return true;
}
return false;
}
}
Override Class
public class ListItems extends com.imobileminutes.library.ListItems {
static final int SMS = 2;
#Override
public boolean onCreateOptionsMenu(Menu menu){
Log.d("onCreateOptionsMenu", "My onCreateOptionsMenu ran");
Toast.makeText(getApplicationContext(), "HEllo Menu Created", Toast.LENGTH_LONG).show();
super.onCreateOptionsMenu(menu);
return true;
}
#Override
public boolean onOptionsItemSelected (MenuItem item){
Log.d("onCreateOptionsMenu", "My onOptionsItemSelected ran");
Toast.makeText(getApplicationContext(), "HElloonOptionsItemSelected", Toast.LENGTH_LONG).show();
super.onOptionsItemSelected(item);
return false;
}
}
CONCLUSION
It ended up being that my library was calling ListItems.this and CreateAccount.this which was referencing the activities in the library not in the extended classes.
I added an intent for every extended activity type and nwo call that, thus bringing up the extended activity rather than the base activity.
Thanks for the help guys.
Either you didn't copy and paste the code correctly, or part of the problem is in your base class, which provides the same definition for onCreateOptionsMenu as your derived class:
#Override
public boolean onCreateOptionsMenu(Menu menu){
menu.add(0, LOGOUT ,0,"Log Out");
menu.add(0,HISTORY,0,"Order History");
menu.add(0,REFRESH,0,"SMS");
return true;
}
That last line can't be right -- I'm pretty sure the last line of the base class implementation should be: menu.add(0,REFRESH,0,"REFRESH");.
But that last line of onCreateOptionsMenu also needs to be changed in the derived class:
#Override
public boolean onCreateOptionsMenu(Menu menu){
menu.add(0, LOGOUT ,0,"Log Out");
menu.add(0, HISTORY,0,"Order History");
menu.add(0, SMS,0,"SMS"); // Use the correct constant (SMS instead of REFRESH)
return true;
}
EDIT: Also, you can simplify the code a bit, by re-using the superclass implementation for those choices where you're currently just copying the superclass code (LOGOUT and HISTORY):
#Override
public boolean onOptionsItemSelected (MenuItem item){
TextView textView = (TextView)findViewById(com.imobileminutes.library.R.id.text);
// Left this as a 'switch'; you might want to use an 'if' instead.
switch (item.getItemId()){
case SMS:
AppClass.sendSMS("8135551212", "Hello Jason");
return true;
}
return super.onOptionsItemSelected(item);
}
Use the fully qualified name on the import my suspicion is you are referencing the wrong class.
Turns out it was the way I was calling the Activitys. I was calling the Activity directly in the Library rather than calling the overridden one. Since the overriden ones will be dynamic depending on the Apps naming, I ended up using Intents that will search for the callers packagename and append the specific intent onto it.
As soon as I set all that up, my SMS menu item showed.