I am using SingleChoiceItems in ActionBar using DialogBuilder. I need to save the item selected even after exiting the application then restore the saved setting when accessing the application again.
I saw many examples of shared preferences and onRestoreInstanceState() and onSaveInstanceState() but I am quite confused. Below is the code with explanations of what I did.
Dialog Builder
I saved the present state of the selected option in - > selectPosition .. Then saving the selectedPosition in the global variable isChecked and setting it to the SelectSingleChoice arguments.
public void displaySortDialog(final Context context) {
int selection = context.getSharedPreferences(PREF_NAME,
Context.MODE_MULTI_PROCESS).getInt("Selection_key", 0);
Toast.makeText(getApplicationContext(), "Start Sel :"+selection , Toast.LENGTH_SHORT).show();
CharSequence[] sort_options = { "Z-A", "A-Z", "Size" };
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.sort_apps));
builder.setSingleChoiceItems(sort_options, selection,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int selected_sort) {
/*
* Toast.makeText(getApplicationContext(),
* sort_options[selected_sort], Toast.LENGTH_SHORT)
* .show(); // isChecked = restoredChecked;
*/
}
});
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// saving
context.getSharedPreferences(PREF_NAME,
Context.MODE_MULTI_PROCESS).edit()
.putInt("Selection_key", id ).commit();
Toast.makeText(getApplicationContext(), "Choosen :"+id, Toast.LENGTH_SHORT).show();
}
});
builder.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
builder.create().show();
}
Declaring and using the displaySortDialog funtion
public boolean onOptionsItemSelected(MenuItem item) {
boolean result = true;
result = menuChoice(item);
switch (item.getItemId()) {
case R.id.menu_Sort_By_Size: {
displaySortDialog(getBaseContext());
break;
}
case R.id.menu_Action_Search: {
// openSearch();
break;
}
default: {
result = super.onOptionsItemSelected(item);
break;
}
}
return result;
}
Using the below code when I long press the home button or press the home button from the application the selected setting seems OK. They are selected and saved as I toast the message to make sure they are selected which means onSaveInstanceState is working because the toast message in onSaveInstanceState is displayed. But when I try to restore the settings saved through onRestoreInstanceState() then it doesn't work. After exiting the application the settings go back to default.
public void onRestoreInstanceState(Bundle savedInstanceState) {
if(savedInstanceState != null){
isChecked = savedInstanceState.getInt("SELECTED_SORT_ITEM");
Toast.makeText(getApplicationContext(), "RESTORED: "+isChecked, Toast.LENGTH_SHORT).show();
}
}
public void onSaveInstanceState(Bundle savedInstanceState) {
//outState.putInt(SELECTED_SORT_ITEM, getActionBar().getSelectedNavigationIndex());
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt(SELECTED_SORT_ITEM, isChecked);
Toast.makeText(getApplicationContext(), SELECTED_SORT_ITEM+isChecked, Toast.LENGTH_SHORT).show();
}
The toast OnSaveInstanceRestore is shown when I press the home button from the app or long press the home button and again select the app. But after exiting the app I am unable to restore the selected settings.
If you can help me with these methods or know some other method it would be appreciated.
Use shared preference,
like:
// For saving
context.getSharedPreferences(PREF_NAME,Context.MODE_MULTI_PROCESS)
.edit()
.put("Selection_key",selectedPosition)
.commit();
//For retrieve
int selection = context.getSharedPreferences(PREF_NAME,Context.MODE_MULTI_PROCESS)
.getInt("Selection_key",0); // 0 being default selection value, put whatever u want
// int selection, Use this Selection for your UI
Related
I created an interface so I can communicate between a dialogue and a fragment.
Goal: When the user selects anything from the dialogue it should display it on a text view.
In this interface, I created an interface method, called in the main activity and passed the value the user selected in the dialogue. Along with the user selected value, in my fragment, I created a method that will set the text view to that value. However, whenever I call that method it always returns null.
I did plenty of testing with logs and found that the values being passed through my method is NOT null, everything seems to work the exact way I want it to which is odd. What confuses me even more, is that this method isn't even running, it immediately returns null before executing the code inside which is really strange to me.
Dialog Code:
public String users_time;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final String time_options[] = {"10", "20", "30", "40", "50", "60", "70", "80", "90"}; // Since we know how many options there are in the array we use an array instead of an arraylist
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Choose the time");
builder.setSingleChoiceItems(time_options, -1, new DialogInterface.OnClickListener() { // check items = what index is auto selected in the dialog, use -1 bc you dont want that
#Override
public void onClick(DialogInterface dialog, int which) { // which = Index in the array
CharSequence time = time_options[which];
Log.i("this" ,"LOG 1 dialogsTime retusn" + time);
listener.onDialogInput(time);
users_time = time_options[which];
int usersTime = Integer.valueOf(users_time);
listener.grabTime(usersTime);
}
});
builder.setPositiveButton("Set Time", new DialogInterface.OnClickListener() { // positive = Ok or continue
#Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { // Negative = Cancel or stop
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
return builder.create(); // always return this at the end
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof DiaglogListener) {
listener = (DiaglogListener) context;
}
else {
throw new RuntimeException(context.toString()
+ " must implement DiaglogListener");
}
}
#Override
public void onDetach() {
super.onDetach();
listener = null;
}
}
Main Activity Interface Method:
#Override
public void onDialogInput(CharSequence dialogsTime) {
Fragment1_timer frag1 = new Fragment1_timer();
Log.i("this" ,"LOG 2 runs successfully");
try {
frag1.setDialogTime(dialogsTime);
} catch (Exception e){
Toast.makeText(this, "Null error :/", Toast.LENGTH_SHORT).show();
}
}
Fragment Method:
public void setDialogTime(CharSequence time){
Log.i("this" ,"LOG 3 ran successfully");
text_view_time.setText(time + ":00");
}
You can't use onAttach method for Fragment to DialogFragment communication.
you will have to use "setTargetFragment" & "getTargetFragment" for that.
you can refer this answer. https://stackoverflow.com/a/32323822/9792247
I have a very strange situation. I am using Contextual Action Mode for selecting multiple items of the ListView. The flow goes as follows:
User selects the list items using long press on them --> Uses the action item "Operations" to choose what he wants to do --> This action item creates a AlertDialog with 4 list items (call it dialog1) where the 3rd item calls another AlertDialog (call it dialog2) which includes an EditText for some data input and later calls a method to perform it.
Later the user hits Back button or Home button to exit the Action Mode.
The problem is that dialog2 shows up alternatively like first time user selects the list items, Chooses "Operations" action item and chooses the 3rd item which calls dialog2. Now dialog2 will appear as it is supposed to. Later the user hits the Back button to quit the Action Mode.
The SECOND TIME user performs the same steps dialog2 doesn't appear.
The logcat shows this error in both the cases:
09-04 10:53:12.096 6299-6299/com.project.pcmanager
W/InputEventReceiver: Attempted to finish an input event but the input
event receiver has already been disposed.
Some code:
public void sendAction(final Context context, final EventModel model, int position) {
JSONObject object = new JSONObject();
String[] operations = getResources().getStringArray(R.array.operations);
// null set before is modified here
model.setEventTitle(operations[position]);
final String ip = model.getEventIP();
switch (position) {
case 0:
try {
object.put("command", "power_off");
notifyUser();
LogUtils.addEntry(model.toString());
execCommand(ip,object);
} catch (JSONException e) {
e.printStackTrace();
}
break;
case 1:
try {
object.put("command", "reboot");
notifyUser();
LogUtils.addEntry(model.toString());
execCommand(ip,object);
} catch (JSONException e) {
e.printStackTrace();
}
break;
case 2:
//Show AlertDialog with EditText on it for command input
final EditText txtCommand = new EditText(context);
// Set some properties to EditText
txtCommand.setPadding(16, 16, 16, 16);
txtCommand.setMinHeight(150);
txtCommand.setHint("Ex: ping google.com");
txtCommand.setSingleLine();
new AlertDialog.Builder(context)
.setTitle("Run a task")
.setView(txtCommand)
.setCancelable(false)
.setPositiveButton("Run",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String command = txtCommand.getText().toString();
if (command.length() > 0) {
JSONObject object = new JSONObject();
try {
object.put("run", command);
object.put("ip", ip);
notifyUser();
LogUtils.addEntry(model.toString());
performRemoteExec(object);
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Toast.makeText(context, "Please provide a command first!", Toast.LENGTH_SHORT).show();
}
}
}).setNeutralButton("Cancel", null).show();
break;
case 3:
notifyUser();
LogUtils.addEntry(model.toString());
getScreenshot(ip);
break;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
listView.setAdapter(adapter);
listView.setEmptyView(emptyView);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
//Change the title bar with the items selected
mode.setTitle(listView.getCheckedItemCount() + " selected");
//select the clicked item
adapter.toggleSelection(position);
}
/**
* Called when action mode is first created.
* The menu supplied will be used to generate action buttons for the action mode.
* #param mode ActionMode being created
* #param menu Menu used to populate action buttons
* #return true if the action mode should be created,
* false if entering this mode should be aborted.
*/
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
onContextMode = true;
mode.getMenuInflater().inflate(R.menu.menu_client_select_main, menu);
return true;
}
/**
* Called to refresh an action mode's action menu whenever it is invalidated.
* #return true if the menu or action mode was updated, false otherwise.
*/
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
/**
* Called to report a user click on an action button.
* #return true if this callback handled the event,
* false if the standard MenuItem invocation should continue.
*/
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
int id = item.getItemId();
if (id == R.id.menu_operations) {
final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setItems(R.array.operations, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
SparseBooleanArray selectedIds = adapter.getSelectedIds();
// traverse the array to find chosen clients
for (int i = 0; i < selectedIds.size(); i++) {
if (selectedIds.get(i)) {
ClientModel item = adapter.getItem(i);
String ip = item.getClientIP();
String os = item.getOSType();
// null will be treated soon
EventModel model = new EventModel(ip, null, os);
sendAction(builder.getContext(),model, which);
}
}
}
});
builder.show();
}
return true;
}
/**
* Called when an action mode is about to be exited and destroyed.
*/
#Override
public void onDestroyActionMode(ActionMode mode) {
onContextMode = false;
}
});
}
Ok so I figured the problem myself. It turns out the culprit was me using SparseBooleanArray to get selected clients and I was wrong.
In my code it was:
SparseBooleanArray selectedIds = adapter.getSelectedIds();
So, I removed this SparseBooleanArray with a new implementation technique. I used ArrayList<ClientMode> selectedItems to store all the selected models in my Adapter class.
Also, I created a simple method called clearSelections that calls selectedItems.clear() method in it. I call this method at on onDestroyActionMode as per my app requirement.
HOW I FOUND THIS?
I simply placed a bunch of System.out.println statements all around onCreate and sendAction to find out the culprit.
I have two activities. In the second activity I have a spinner. what I would like to happen is after the user selects an item from the spinner it will save via actionbar press and on back press which will load the previous activity. Based on my research my activity is supposed to look something like the following below but it's not working what am I doing wrong??
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit);
getActionBar().setDisplayHomeAsUpEnabled(true);
spin = (Spinner)findViewById(R.id.editspin);
Intent i = this.getIntent();
note = new ArgueItem();
note.setKey(i.getStringExtra("key"));
note.setText(i.getStringExtra("text"));
EditText et = (EditText)findViewById(R.id.argueEdit);
et.setText(note.getText());
et.setSelection(note.getText().length());
}private boolean saveState() {
prefs = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor prefEditor = prefs.edit();
int daddy = spin.getSelectedItemPosition();
prefEditor.putInt("savedValue",daddy);
prefEditor.commit();
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
EditText et = (EditText)findViewById(R.id.argueEdit);
String argueText = et.getText().toString();
if(argueText.equals("")){
Toast.makeText(this, "Please Enter A New ", Toast.LENGTH_SHORT).show();
return false;
}
if (item.getItemId() == android.R.id.home) {
saveAndFinish();
}
return false;
}
#Override
public void onBackPressed() {
EditText et = (EditText)findViewById(R.id.argueEdit);
String argueText = et.getText().toString();
if(argueText.equals("")){
Toast.makeText(this, "Please Enter A New ", Toast.LENGTH_SHORT).show();
return;
}else{
saveAndFinish();
}
In your second activity, you have to override the onPause() and. Inside it write the saving process.
protected void onPause(){
super.onPause();
//Include the code which, save the data.
}
You should use a FragmentActivity and add/remove fragments within the same activity.
check these resources:
http://developer.android.com/guide/components/fragments.html
http://www.vogella.com/articles/AndroidFragments/article.html
This is how i'm initializing my spinner which is in the ActionBar. I'm not adding it as a custom view, but I'm using the drop down menu feature.
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
actionBar.setListNavigationCallbacks(adapter, new ActionBar.OnNavigationListener() {
#Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
//save in preferences
PreferenceManager.getDefaultSharedPreferences(MainActivity.this).edit().
putInt(SELECTED_DIARY_PREF, itemPosition).commit();
return true;
}
});
int selPosition = PreferenceManager.getDefaultSharedPreferences(this).getInt(SELECTED_DIARY_PREF, 0);
actionBar.setSelectedNavigationItem(selPosition);
What this code does is: saving the preference when an item of the menu is clicked, and restoring that preference when the activity is launched. Hope it helps.
I have a button in my menu with a “promo code” inside. I need to check if a user already clicked it so I can tell him (the next time he clicks it) “You already redeemed this promo code!” How do I do that? I need only the piece of code where I can check for button clicked.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
boolean clicked = false;
switch (item.getItemId()) {
case R.id.getcode:
SharedPreferences pref = getSharedPreferences("promo", MODE_PRIVATE);
boolean activated = pref.getBoolean("activated", false);
if(activated == false) { Button btn = (Button) findViewById(R.id.getcode);
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this);
dlgAlert.setMessage(getString(R.string.congrats) + "\n" + getString(R.string.promcd) + "\n" + "ASC2013-"+Build.ID+"-"+android.os.Build.SERIAL.charAt(3)+"-"+Build.SERIAL.charAt(6)+"-"+Build.SERIAL.charAt(9)+"-"+Build.SERIAL.charAt(12));
dlgAlert.setPositiveButton(R.string.go,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] {"lorenzocascio#gmail.com"});
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(R.string.validreq)+Build.BOOTLOADER);
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, getString(R.string.why) + "\n" + getString(R.string.validreq1) +"\n"+getString(R.string.dialogMSG1);
emailIntent.setType("plain/text");
startActivity(emailIntent);
}
});
dlgAlert.setCancelable(true);
dlgAlert.create().show();
SharedPreferences.Editor editor = pref.edit();
editor.putBoolean("activated", true);
editor.commit();
}
break;
}
switch (item.getItemId()) {
case R.id.settings:
Intent settings = new Intent(MainActivity.this, Settings.class);
MainActivity.this.startActivity(settings);
}
return true;
}
How about a simple boolean flag?
Set it to false in the beginning - as soon as the user clicks - set it to true.
private boolean clicked = false; // this is a member variable
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(clicked) {
Toast.makeText(getActivity(), "You already clicked!", 1000).show();
} else {
Toast.makeText(getActivity(), "You clicked for the first time!", 1000).show();
}
clicked = true;
}
}
}
Please be aware that the "clicked" boolean variable must be a member variable of your Activity, otherwise it will not be visible inside onClick(). A variable being a member variable simply means that it belongs to the class it is in, and not just occurs in a specific method. In the above code, "btn" would be a "normal" variable since it only appears inside onCreate() (a method), whereas "clicked" is declared for the Activity (the class it is in), and is therefore a member variable.
If you want to save if the user has clicked even after the app was closed and gets reopened, take a look at the SharedPreferences.
SharedPreferences prefs = this.getSharedPreferences("com.example.app", Context.MODE_PRIVATE);
boolean clicked;
clicked = prefs.getBoolean("yourkey", false); // get a value, use whatever key you want
prefs.edit().putBoolean("yourkey", clicked).commit(); // save a value, use same key
You can save a flag in shared preferences if the user clicks the button. Next time, you can check in the shared preferences if there exists the flag.
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SharedPreferences pref = getSharedPreferences("promo", MODE_PRIVATE);
boolean activated = pref.getBoolean("activated", false);
if(activated == false) { // User hasn't actived the promocode -> activate it
SharedPreferences.Editor editor = pref.edit();
editor.putBoolean("activated", true);
editor.commit();
}
}
The dialog:
public class ClearDialog extends Dialog {
private MainActivity context;
public ClearDialog(MainActivity context) {
super(context);
this.context = context;
setContentView(R.layout.clear_dialog);
setTitle("something");
setCanceledOnTouchOutside(false);
setCancelable(true);
}
/* not overriding anymore
#Override
public void onBackPressed() {
return;
}
still doesnt work */
#Override
protected void onStart() {
super.onStart();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = preferences.edit();
editor.clear();
editor.commit();
ResourceHelpers.removeAllResources();
context.onResourcesDeleted();
}
}
The Activity:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.itemLogoff:
loginDialog.show(); //this is another dialog
break;
case R.id.itemSync:
Intent syncer = new Intent(MainActivity.this, SyncActivity.class);
MainActivity.this.startActivity(syncer);
break;
case R.id.itemClear:
new AlertDialog.Builder(this)
.setIcon(R.drawable.ic_action_alert)
.setTitle("something")
.setMessage("something")
.setPositiveButton("something", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
showDeleteDialog();
}
})
.setNegativeButton("something", null)
.show();
break;
}
return true;
}
private void showDeleteDialog() {
cd = new ClearDialog(this); //this is the dialog
cd.show();
}
public void onResourcesDeleted() {
cd.dismiss();
loginDialog.show();
}
So.. The user clicks on "Delete all data" from the ActionBar (optionsmenu). I open an AlertDialog asking if he's sure. Then if he's sure, I open a dialog that shows a spinning ProgressBar.
The problem: it won't dismiss!
The loginDialog (all data is lost so I want the user to login again...) comes up in the background. The ClearDialog won't dismiss...
I think that the problem is here (don't override in this way that method):
#Override
public void onBackPressed() {
return;
}
You can already obtain a modal dialog with .setCancelable(false)
Please take a loog at this documentation: http://developer.android.com/guide/topics/ui/dialogs.html#AlertDialog
Give the following property for dialogue
.setCancelable(true);
its just like .setTitle() or .setMessage in your code....
On top of StErMi's answer, which you should follow, also switch the two lines in your onResourcesDeleted() method. The login dialog is called, and takes over before your dismiss is called.
public void onResourcesDeleted() {
cd.dismiss();
loginDialog.show();
}