0

Yesterday, I built a SettingsActivity for my Android app where the user can enter the URL of a webservice-server. I save this using:

editor = sharedPref.edit();
editor.putString(
    getString(R.string.SAVED_URL_MOBILEHELPER), lvsURL_mobilehelper);
editor.commit();

in the SharedPreferences after the "save" button is pressed.

In the onStart() I read the setting to set the saved value into the belonging text-field:

// line 29
String lvsURL_mobilehelper = sharedPref.getString(
    getString(R.string.SAVED_URL_MOBILEHELPER), "");

This also worked well yesterday; the last string I entered and successfully read from the settings was "testURL12345".

Today, I was trying to add user-authentication around my application and since that, I get a ClassCastException when I open the SettingsActivity:

Caused by: java.lang.ClassCastException: java.lang.Long cannot be cast to
    java.lang.String
at android.app.SharedPreferencesImpl.getString(SharedPreferencesImpl.java:224)
at de.unibonn.sdb.wissappmobile.activities.SettingsActivity.onResume(
    SettingsActivity.java:29)

Does anyone have an idea why this all worked fine yesterday and now it doesn't?

Note: I don't want to store the user credentials in an AccountManager or persistent in my preferences, because the app shall be used on a "business tablet" and not a "personal tablet". The user credentials are needed for HTTP-Basic authentication. So my idea is to check in the parent Activity if the user is "logged in" and not inactive for more than 1800 seconds.

SettingsActivity:

/*
 * Activity for settings page (webservice URL)
 */
public class SettingsActivity extends AppFragmentActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_settings);
  }

  @Override
  protected void onResume() {
    super.onResume();

    // Fill content

    // URL of the Mobile Helper
    String lvsURL_mobilehelper = sharedPref.getString(
        getString(R.string.SAVED_URL_MOBILEHELPER), "");
    EditText dfsURLMobileHelper = (EditText) findViewById(R.id.dfsURLMobileHelper);
    dfsURLMobileHelper.setText(lvsURL_mobilehelper);        
  }

  /*
   * Action called when pressing the "Save"-Button
   * 
   * Saves the entered Data in a local file.
   */
  public void ClickBtnSave(View view) {
    EditText dfsURLMobileHelper = (EditText) findViewById(R.id.dfsURLMobileHelper);
    TextView txtError = (TextView) findViewById(R.id.txtError);

    String lvsURL_mobilehelper = dfsURLMobileHelper.getText().toString();
    String Eceptiontext = "";

    Boolean success = false;

    // Write to file
    try {
      editor = sharedPref.edit();
      editor.putString(getString(R.string.SAVED_URL_MOBILEHELPER), lvsURL_mobilehelper);
      editor.commit();

      success = true;
    } catch (Exception e) {
      success = false;
      Eceptiontext = e.getLocalizedMessage();
    }

    if (success) {
      txtError.setText(getString(R.string.SAVING_SUCCESS));
    } else {
      txtError.setText(getString(R.string.SAVING_FAILED) + " : " +  Eceptiontext);
    }
  }     

  /*
   * Action called when pressing the "Back"-Button
   * 
   * Opens the Search-Acitivity
   */
  public void ClickBtnBack(View view) {
    // Back to SearchActivity
    Intent intent = new Intent(this, SearchActivity.class);
    startActivity(intent);
  }        
}

Parent AppFragmentActivity:

/**
 * Class to handle global Callbacks (e.g. user credentials)
 */
public class AppFragmentActivity extends FragmentActivity  {

  protected SharedPreferences sharedPref;
  protected SharedPreferences.Editor editor;    

  protected String WebServiceUsername;
  protected String WebServicePassword;


  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_appfragmentactivity);
  } 


  @Override
  protected void onResume () {
    super.onResume();


    // Check if user is "logged in".
    // Meaning: Are there given user credentials and are they valid of was the user inactive for too long?

    // We only do this "onResume" because this callback is the only one, which is called everytime an user 
    // starts/restarts/resumes an application
    checkForUserCredentials();


    // Set new "last action" now "now"
    setLastAction(new Date().getTime());
  }

  @Override
  protected void onStart () {
    // Fill content
    super.onStart();

    // Set global sharedPreferences
    sharedPref = getSharedPreferences(
        getString(R.string.FILE_settings_file), Context.MODE_PRIVATE);
  }



  /*
   * Checks if user credentials are valid meaning if they are set and not too old
   */
  private void checkForUserCredentials() {
    // Get filehandle to PreferencesFile


    long TimeLastAction = sharedPref.getLong(
        getString(R.string.SETTINGS_USER_LAST_ACTION), 0);
    long TimeNow = new Date().getTime();

    // Ask for User credentials when last action is too long ago
    if(TimeLastAction < (TimeNow - 1800)) {
      // Inactive for too long

      // Set credentials back
      setUsernameAndPassword("", "");

    } else {
      WebServiceUsername = sharedPref.getString(
          getString(R.string.SETTINGS_USER_USERNAME), "");
      WebServicePassword = sharedPref.getString(
          getString(R.string.SETTINGS_USER_PASSWORD), "");              
    }
  }

  /*
   * Saves the given last action in the sharedPreferences
   * @param long LastAction - Time of the last action
   */
  private void setLastAction(long LastAction) {
    editor = sharedPref.edit();
    editor.putLong(getString(R.string.SETTINGS_USER_LAST_ACTION), LastAction);
    editor.commit();        
  }

  /*
   * Saves the given username and userpassword sharedPreferences
   * @param String username
   * @param String password
   */
  private void setUsernameAndPassword(String username, String password) {
    editor = sharedPref.edit();
    editor.putString(
        getString(R.string.SETTINGS_USER_USERNAME), username);
    editor.putString(
        getString(R.string.SETTINGS_USER_PASSWORD), username);
    editor.commit();    

    WebServiceUsername = username;
    WebServicePassword = password;
  } 

  /*
   * Method called when pressing the OK-Button
   */
    public void ClickBtnOK(View view) {
        // Save User-Creentials

      EditText dfsUsername = (EditText) findViewById(R.id.dfsUsername);
      String lvsUsername = dfsUsername.getText().toString();        

      EditText dfsPassword = (EditText) findViewById(R.id.dfsPassword);
      String lvsPassword = dfsPassword.getText().toString();        

      if(lvsUsername.equals("") || lvsPassword.equals("")) {
        TextView txtError = (TextView) findViewById(R.id.txtError);
        txtError.setText(getString(R.string.ERR_Name_or_Password_empty));
      } else {
        // Save credentials
        setUsernameAndPassword(lvsUsername, lvsPassword);
        setLastAction(new Date().getTime());

        // open Searchactivity
          Intent intent = new Intent(this, SearchActivity.class);
          startActivity(intent);            

      }
    }   

    @Override
    protected void onPause() {
      super.onPause();
      setLastAction(new Date().getTime());
    }

    @Override
  protected void onStop() {
    super.onStop();
    setLastAction(0);
    setUsernameAndPassword("", "");
  }
}
ataulm
  • 15,195
  • 7
  • 50
  • 92
bish
  • 3,381
  • 9
  • 48
  • 69
  • Well, if Long, probably because of you put long there. Because of you are using R.string. sometimes it messes up resources ids, so need for clean project, or you have same string values for these ids in your string.xml. Simply saying, somewhere in logic you put long in same key. – Volodymyr Lykhonis Aug 11 '13 at 15:18
  • I agree with Vladimir, especially your putting username in password also `editor.putString(getString(R.string.SETTINGS_USER_PASSWORD), username);` – DevZer0 Aug 11 '13 at 15:20
  • what is the value of the string referred to by "getString(R.string.SAVED_URL_MOBILEHELPER)"? – ataulm Aug 11 '13 at 15:21
  • 1
    Just a little side note - I wouldn't use your values.xml file to store the names for your shared prefs items, what if the user changes the language on their phone? – jcw Aug 11 '13 at 15:34
  • Vladimir How can I clean up my project and how can I prevent my app from messing up resources Id? I'm quite new to android :/. The R.string-using I saw on the developers.android-tutorials so I thought it is best practise DevZero Thanks. Correcting the mistake ataulm the entry in strings.xml is "SAVED_URL_MOBILEHELPER". The last successfull saved string from the textfield yesterday was "testURL12345" (see above) jcw Changing the language isn't a problem as long the strings are not translated – bish Aug 11 '13 at 15:39
  • @VladimirLichonos Thanks for your tip with the reosurces ID. After a run of "editor.clear()" the activity runs again. Looks like there was a wrong variable saved. If you want to repost your tip as an answer I can accept it – bish Aug 11 '13 at 16:05
  • If you're using Eclipse, Project > Clean – ataulm Aug 11 '13 at 16:16

1 Answers1

0

Well, if Long, probably because of you put long there. Because of you are using R.string. sometimes it messes up resources ids, so need for clean project, or you have same string values for these ids in your string.xml. Simply saying, somewhere in logic you put long in same key

p.s. I think best practice is to use public static final String MY_PREFERENCE_KEY = "my_preference_key";

Volodymyr Lykhonis
  • 2,936
  • 2
  • 17
  • 13