I have a checkable MenuItemin my application. I check for the last state and change its icon according to the pervious state (when app restarts or ...). The problem is, when the device orientation changes, these methods that I have below does not work!
I wonder if it is my code or there is a special case when orientation changes and the menu items get reset?
It is defined in the xml file like so:
So the above is the default behavior that I want, that is when the application installs on the phone it's first statee should be false.
In the activity, I have in onPrepareOptionsMenu the following code, which will check the state and changes the icon before showing the menu to user:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(R.id.action_toggle_logging);
if (item.isChecked()) {
item.setIcon(R.drawable.ic_action_stop);
} else {
item.setIcon(R.drawable.ic_action_play);
}
return true;
}
And here is in the onOptionsItemSelected method:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_toggle_logging:
if (item.isChecked()) {
getApplicationReference().stopLoggerService(); //stop stuff
item.setIcon(R.drawable.ic_action_play);
} else {
getApplicationReference().startLoggerService(); //start stuff
item.setIcon(R.drawable.ic_action_stop);
}
item.setChecked(!item.isChecked());
}
return super.onOptionsItemSelected(item);
}
You can persist local members to a bundle. This lets them survive configuration changes (like orientation changes).
private static final String LOGGGING_KEY = "logging-key";
private boolean mLoggingOn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mLoggingOn = savedInstanceState.getBoolean(LOGGGING_KEY, false);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean(LOGGGING_KEY, mLoggingOn);
super.onSaveInstanceState(outState);
}
Related
I am using a listview in my application where have implemented setChoiceMode with ListView.CHOICE_MODE_MULTIPLE_MODAL. When long press on the listview, items can be selected but after that, if the screen orientation is changed the action bar goes annoyingly.
My code looks like this
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
adapter = new ItemListAdapter();
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode actionMode, int position, long l, boolean b) {
final int checkedItemCount = listView.getCheckedItemCount();
actionMode.setTitle(checkedItemCount + " Selected");
/*get the selected items*/
}
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
actionMode.getMenuInflater().inflate(R.menu.menu_listview_delete, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(final ActionMode actionMode, MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.delete_item:
/*delete selected items*/
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
adapter.removeSelection();
}
});
}
Image in portrait mode & landscape mode ,It shows selected items as 0
& when trying to delete the respective selected items will not get deleted.then if back button is pressed (on landscape mode which is implemented in my application activity) the action bar color will turn to white.
(Same happens when trying in other way select items in landscape mode and rotate to delete the same in portrait)
One solution is using below in the manifest
android:configChanges="orientation|screenSize"
If this is used the activity is not recreated on orientation change.As it has different layouts for portrait and landscape, activity recreation is must on orientation change.
I know the issue is because of the activity is recreated on orientation change that makes setMultiChoiceModeListener to called every time.
can someone help to tackle the issue? Thanks!
Use these methods to store and restore the values of your selected items.
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt("count",checkedItemCount);
super.onSaveInstanceState(outState);
}
then restore it onCreate method
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
//will return value of selecteditems
int countedItems = savedInstanceState.getInt("count");
}
}
Here's a link for more information:
How to use onSavedInstanceState example please
I've problem when using ListView in Fragment. When i using MultiChoiceModelListener, it will display ActionMode when i Long click on the item in ListView.
The problem is :
When ActionMode is activated, and user replace that fragment with other fragment the actionmode still there, take a look the picture below.
When I use ActionMode mode = null and instantiate that mode variable onCreateActionMode plus implement it in onDestroyActionMode and onDestroyView, please take a look the snippet code. The Problem number one is solved, but it's open another problem, because mode.finish() is called in onDestroyView when fragment orientation change my checked item in ListView disappear.
When I delete onDestroyView() method, I solved the problem number two, but Problem number one is open again.
This is my snippet code :
//My ActionModeListener
private class MyActionMode implements AbsListView.MultiChoiceModeListener {
#Override
public void onItemCheckedStateChanged(ActionMode actionMode, int i, long l, boolean b) {
String nfile = ((DataFileProvider) adapter.getItem(i)).getNfile();
if (b) {
selections.add(nfile);
} else {
selections.remove(nfile);
}
actionMode.setTitle(selections.size() + " " + getString(R.string.item_selected));
}
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
mode = actionMode;
getActivity().getMenuInflater().inflate(R.menu.list_file_action_mode, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
actionMode.setTitle(selections.size() + " " + getString(R.string.item_selected));
return true;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
return true;
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
selections.clear();
mode = null;
showMessage("ListDocFileFragment : onDestroyActionMode");
}
}
This is my snippet code when handle fragment livecycle
//My OnResume,OnPause,and OnDestroyView in Fragment
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
default_location = getArguments().getString("default_location");
}
if (getActivity().getIntent().hasExtra("ActionMode")) {
selections = getActivity().getIntent().getStringArrayListExtra("ActionMode");
}
}
#Override
public void onResume() {
super.onResume();
if(selections.isEmpty() && list_doc_file.getCheckedItemCount() > 0){
for (int i = 0; i < adapter.getCount(); i++) {
list_doc_file.setItemChecked(i, false);
}
selections.clear();
}
showMessage("ListDocFileFragment : onResume");
}
#Override
public void onPause() {
if (selections != null) {
getActivity().getIntent().putExtra("ActionMode", selections);
}
showMessage("ListDocFileFragment : onPause");
super.onPause();
}
#Override
public void onDestroyView() {
if(mode != null){
mode.finish();
}
showMessage("ListDocFileFragment : onDestroyView");
super.onDestroyView();
}
My Question is how to solved three problem above, without open another problem like i did ?
I've searching for another solution in this stack, but i got nothing. When i implement their solution it's always open another problem. Any suggestion ?
so I have a working spinner that shows four options. Any one of these options needs to be chosen by the user and then they need to click a button at the bottom of the screen that will then alter one of four boolean variables, depending on which option was chosen.
Here's my code so far
public class CreateAlarm extends Activity { //declare variables
private Spinner difficultySpinner;
private Button createAlarm;
public static boolean easy = false; //set to true when selected by spinner.
public static boolean medium = false;
public static boolean hard = false;
public static boolean extreme = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_alarm);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_create_alarm, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void addListenerOnButton() {
difficultySpinner = (Spinner) findViewById(R.id.difficultySpinner);
createAlarm = (Button) findViewById(R.id.createAlarm);
createAlarm.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
Could someone help me in telling me how I'd go about getting the value to be taken when the button is pressed? i'm not sure how to read from a spinner and everything I've looked at is just adding to my confusion.
thanks!
Add below code in your createAlarm 'onclick()' method:
String item=difficultySpinner.getSelectedItem().toString();
I have made a simple app and i want to change the theme of all the activities of the app (including the settings activity) after selecting from the preference but the themes do not apply after selection. I've tried adding a recreate() but gets stuck in trying to start the main activity. For now, i added a menu item that does recreate() but i want it to apply automatically once you leave the settings activity.
MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
SharedPreferences getData = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String themeValues = getData.getString("theme_preference", "1");
if (themeValues.equals("1")) {
setTheme(R.style.Theme_Light);
}
if (themeValues.equals("2")) {
setTheme(R.style.Theme_Dark);
}
if (themeValues.equals("3")) {
setTheme(R.style.Theme_Red);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (id == R.id.action_settings) {
Intent i = new Intent("com.cyanoise.helloworld.SettingsActivity");
startActivity(i);
return true;
}
if (id == R.id.about_app) {
startActivity(new Intent(MainActivity.this, AboutActivity.class));
return true;
}
if (id == R.id.refresh_app) {
recreate();
return true;
}
if (id == R.id.exitapp) {
finish();
}
return super.onOptionsItemSelected(item);
}
SettingsActivity.java:
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
}
}
All answers are greatly appreciated.
In order to apply a new theme in every activity when returning to it, but still only recreate activities when it is necessary, I am using a self-written BaseActivity, from which all my activities inherit.
In onCreate() the theme for each activity is set and saved in a String variable theme. By remembering the current theme of every activity you can compare it with your new theme from SharedPreferences in onResume() whenever the user turns to this activity.
Like this, you only need to call this.recreate() on resumed activities if the theme doesn't match yet, to make every activity show the up-to-date theme.
public abstract class BaseActivity extends AppCompatActivity {
String theme;
#Override
protected void onCreate(Bundle savedInstanceState) {
theme = PreferenceManager.getDefaultSharedPreferences(this).getString(getString(R.string.prefsThemesList), getString(R.string.prefsThemesList_default));
try {
Field resourceField = R.style.class.getDeclaredField(theme);
int resourceId = resourceField.getInt(resourceField);
setTheme(resourceId);
} catch (Exception e) {
e.printStackTrace();
}
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
super.onResume();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (!theme.equals(prefs.getString(getString(R.string.prefsThemesList), " none "))) {
this.recreate();
}
}
}
Okay so I've been playing around and found a workaround to it. I added a onBackPressed() in the SettingsActivity to bring up the MainActivity again and it seemed to work, applying the selected theme once exiting the settings activity.
#Override
public void onBackPressed() {
super.onBackPressed();
startActivity(new Intent(SettingsActivity.this, MainActivity.class));
}
As for applying themes to all activities i just added
SharedPreferences getData = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String themeValues = getData.getString("theme_preference", "1");
if (themeValues.equals("1")) {
setTheme(R.style.Theme_Light);
}
if (themeValues.equals("2")) {
setTheme(R.style.Theme_Dark);
}
if (themeValues.equals("3")) {
setTheme(R.style.Theme_Red);
}
to every onCreate of every activity.
I have this code here, I created a popup menu when the user long-presses the "edit_text" view's area which displays a popup menu with "Red" "Yellow" radio button option which changes the background color of the "text_view", but I'm not sure why when I select the other option, like when red is currently selected, I select yellow and the other way around(I have the red option selected as the default state), the selected state does not change at all, red is still selected no matter how many times I press yellow. Could you guys help me with this please? Thank you very much.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit_text = (EditText)findViewById(R.id.edit_text_1);
text_view = (TextView)findViewById(R.id.textView1);
//==========_CREATE A POPUP MENU WHEN LONG-CLICK ON EDITTEXT AREA_==========\\
edit_text.setOnLongClickListener(new OnLongClickListener() {
public boolean onLongClick(View v) {
final PopupMenu pop_up = new PopupMenu(getContext(), v);
getMenuInflater().inflate(R.menu.main, pop_up.getMenu());
//GROUP'S ID IS "group".
pop_up.getMenu().setGroupCheckable(R.id.group, true, true);
pop_up.show();
pop_up.setOnMenuItemClickListener(listener);
return true;
}
});
}
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
switch(item.getItemId()) {
case R.id.red:
text_view.setBackgroundColor(Color.RED);
if (!item.isChecked()) {
item.setChecked(true);
}
return true;
case R.id.yellow:
text_view.setBackgroundColor(Color.YELLOW);
if (!item.isChecked()) {
item.setChecked(true);
}
return true;
default:
return false;
}
}
};
protected Context getContext() {
return this;
}
Looks like there's some logical issue with your code. Based on the documentation:
When a checkable item is selected, the system calls your respective
item-selected callback method (such as onOptionsItemSelected()). It is
here that you must set the state of the checkbox, because a checkbox
or radio button does not change its state automatically.
It's easy to observe that yours onLongClick(View v) get called every time and so the menu gets created every long click again (with initial items states). To fix the issue you can store checked / unchecked state (or current color) some there and set item states properly every time in onLongClick(View v). Like the following:
public class MainActivity extends ActionBarActivity {
private static final String TAG = "MainActivity";
private TextView mText;
// For persistent storage SharedPreferences should be used instead of local variable
private int mColor = Color.RED;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText edit = (EditText) findViewById(R.id.edit_text_1);
mText = (TextView)findViewById(R.id.textView1);
mText.setBackgroundColor(mColor);
edit.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Log.d(TAG, "onLongClick");
final PopupMenu pop_up = new PopupMenu(MainActivity.this, v);
final Menu menu = pop_up.getMenu();
getMenuInflater().inflate(R.menu.popup_menu, menu);
//GROUP'S ID IS "group".
menu.setGroupCheckable(R.id.group, true, true);
pop_up.show();
switch(mColor) {
case Color.RED:
menu.findItem(R.id.yellow).setChecked(false);
menu.findItem(R.id.red).setChecked(true);
break;
case Color.YELLOW:
menu.findItem(R.id.red).setChecked(false);
menu.findItem(R.id.yellow).setChecked(true);
break;
default:
break;
}
pop_up.setOnMenuItemClickListener(mMenuItemClickListener);
return true;
}
});
}
final OnMenuItemClickListener mMenuItemClickListener = new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch(item.getItemId()) {
case R.id.red:
mText.setBackgroundColor(Color.RED);
mColor = Color.RED;
return true;
case R.id.yellow:
mText.setBackgroundColor(Color.YELLOW);
mColor = Color.YELLOW;
return true;
default:
return false;
}
}
};
Also, I'd suggest to checkout ContextMenu which provides slightly more convenient way for creating long-click context menus. Please note that documentation of ContextMenu from onCreateContextMenu() clearly states that menu in proper state should be populated by the app every time:
Called when a context menu for the view is about to be shown. Unlike
onCreateOptionsMenu(Menu), this will be called every time the context
menu is about to be shown and should be populated for the view (or
item inside the view for AdapterView subclasses, this can be found in
the menuInfo)).