Android, Xamarin: Cannot write to App Preferences via Singleton - android

Im our app, we have a class with app preferences, that stores certain data. A short version of this class looks like this:
public class AppPreferences
{
private ISharedPreferences mSharedPrefs;
private ISharedPreferencesEditor mPrefsEditor;
private Context mContext;
public AppPreferences(Context context)
{
this.mContext = context;
mSharedPrefs = PreferenceManager.GetDefaultSharedPreferences(mContext);
mPrefsEditor = mSharedPrefs.Edit();
}
public void SaveAutoLogIn(bool autologindone)
{
mPrefsEditor.PutBoolean(AUTOLOGIN, autologindone);
mPrefsEditor.Commit();
}
public bool GetSaveAutoLogIn()
{
return mSharedPrefs.GetBoolean(AUTOLOGIN, false);
}
public void saveLocationPermissionGranted(bool granted)
{
mPrefsEditor.PutBoolean(LOCATIONPERMISSION, granted);
mPrefsEditor.Commit();
}
public void savePermissionGranted(bool granted)
{
mPrefsEditor.PutBoolean(PERMISSIONS, granted);
mPrefsEditor.Commit();
}
}
But instead of continuesly instantiating this class in every activity it is needed in, I have decided to create a singleton class (Shorted):
class Preferences : AbstractPreferences<Preferences>
{
// öffentliche Felder und Methoden
public string usernameKey { get; set; }
public string emailKey { get; set; }
public int numberOfNews { get; set; }
public bool locationpermission { get; set; }
public int numberofnewschats { get; set; }
AppPreferences ap;
private Preferences()
{
}
public void GetPreferences(Context mContext)
{
ap = new AppPreferences(mContext);
this.usernameKey = ap.getUsernameKey();
this.emailKey = ap.getEmailKey()
}
public void DeletePreferences()
{
ap.deletePreferences();
}
public void DeleteTutorialPrefs()
{
ap.deleteTutorialPrefs();
}
public void SetPreferencesDeviceID(string key)
{
ap.saveDeviceID(key);
}
}
Okay, so basically, this class that inherets from:
public abstract class AbstractPreferences<T> where T : class
{
// Lazy Instanziierung
private static readonly Lazy<T> _instance = new Lazy<T>(() => CreateSingletonInstance());
public static T Instance
{
get
{
// throw new System.InvalidOperationException("out");
return _instance.Value;
}
}
private static T CreateSingletonInstance()
{
// Konstruktion des Singleton-Objekts
return Activator.CreateInstance(typeof(T), true) as T;
}
}
}
Now instantiates all app preferences at once and then sets them to an object like:
Preferences.Preferences prf = Preferences.Preferences.Instance;
prf.GetPreferences(mContext);
This was neccissarry, since any other way caused the app preferences to crash. But here is the problem:
I cannot SET any prefs. Retrieving them works just fine - but when I set a value, like a bool set to true - after I retrieve just this value, I get the default value in return (false). I debugged this as far as I could. When I am in the first class (AppPreferences) I see that the right value is beeing transported into the the final function: For instance:
public void SaveAutoLogIn(bool autologindone)
{
mPrefsEditor.PutBoolean(AUTOLOGIN, autologindone);
mPrefsEditor.Commit();
}
But after retrieving a value from the function I never get was has been set to it. I know, this is a complicated problem - but I really need your guys help. I hope you can help me! Thanks a lot!

Related

What is Design Pattern where we can pass the string name to a method and that method chooses which further method to call

I recently got following example where we are passing the action name to the method as string and then the method decides the function that needs to be called.
is this a good way of solving problem or is there some better way as well
public static final String ACTION_CHARGING_REMINDER = "charging-reminder";
public static void executeTask(Context context, String action) {
if (ACTION_INCREMENT_WATER_COUNT.equals(action)) {
incrementWaterCount(context);
} else if (ACTION_DISMISS_NOTIFICATION.equals(action)) {
NotificationUtils.clearAllNotifications(context);
} else if(ACTION_CHARGING_REMINDER.equals(action)){
issueChargeReminder(context);
}
}
I'd do something like this. This can be extended as much as you want, and obviously just an example:
static abstract class ActionHandler {
private String action;
public ActionHandler(String action) {
this.action = action;
}
public boolean canHandleAction(String input) {
return this.action.equals(input);
}
public abstract void handleAction();
}
static class OneActionHandler extends ActionHandler {
public OneActionHandler(String action) {
super(action);
}
#Override
public void handleAction() {
//...
}
}
static class TwoActionHandler extends ActionHandler {
public TwoActionHandler(String action) {
super(action);
}
#Override
public void handleAction() {
//...
}
}
static class Test {
private ActionHandler[] handlers;
public Test() {
handlers = new ActionHandler[]{new OneActionHandler("action1"), new TwoActionHandler("action2")};
}
public void handleAction(String action) {
for(ActionHandler i : handlers) {
if(i.canHandleAction(action)) {
i.handleAction();
break;
}
}
}
}
This sounds a lot like the react/redux, action/reduction pattern.
Reducers specify how the application's state changes in response to
actions sent to the store. Remember that actions only describe what
happened, but don't describe how the application's state changes.

Local unit testing with Mockito in Android studio

Can someone please show me a working unit test om this code, using mockito? Im new to testing in Android studio and could really need some help.
public class PreferenceHelper {
public static final String SHARED_PREFS_NAME = "EDUBACK_PREFS";
public static final String PREF_KEY_IS_STUDENT = "PREF_KEY_IS_STUDENT";
private final SharedPreferences mPref;
public PreferenceHelper(Context context) {
mPref = context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
}
public void setIsStudent(boolean isStudent) {
mPref.edit().putBoolean(PREF_KEY_IS_STUDENT, isStudent).apply();
}
public boolean getIsStudent() {
return mPref.getBoolean(PREF_KEY_IS_STUDENT, true); // Default true
}}
Actually it is not necessary to use mockito here.
You can test your class something like that (for assertions I use org.assertj:assertj-core:3.5.2 library):
#RunWith(RobolectricTestRunner.class)
public class PreferenceHelperTest {
private SharedPreferences sharedPreferences;
private PreferenceHelper preferenceHelper;
#Before
public void setUp() {
sharedPreferences = RuntimeEnvironment.application.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
preferenceHelper = new PreferenceHelper(ShadowApplication.getInstance().getApplicationContext());
}
#Test
public void setIsStudent_whenIsStudentIsTrue() {
preferenceHelper.setIsStudent(true);
assertThat(sharedPreferences.getBoolean(PREF_KEY_IS_STUDENT, false)).isTrue();
}
#Test
public void setIsStudent_whenIsStudentIsFalse() {
preferenceHelper.setIsStudent(false);
assertThat(sharedPreferences.getBoolean(PREF_KEY_IS_STUDENT, true)).isFalse();
}
#Test
public void getIsStudent_whenIsStudentIsNull() {
boolean getIsStudent = preferenceHelper.getIsStudent();
assertThat(getIsStudent).isTrue();
}
#Test
public void getIsStudent_whenIsStudentIsFalse() {
preferenceHelper.setIsStudent(false);
boolean getIsStudent = preferenceHelper.getIsStudent();
assertThat(getIsStudent).isFalse();
}
#Test
public void getIsStudent_whenIsStudentIsTrue() {
preferenceHelper.setIsStudent(true);
boolean getIsStudent = preferenceHelper.getIsStudent();
assertThat(getIsStudent).isTrue();
}
}

Android Extend double class

I have my Class Adapter , and I need to have the access of two class ! Then I can put public class JSONAdapter extends ArrayAdapter<Voiture> { for have access in my class " Voiture " but I need to have the acceesss in my class "Moniteur" too , and I can"t put that :
public class JSONAdapter extends ArrayAdapter<Voiture>,ArrayAdapter<Moniteur> {
I need to view attributes of my class " Voiture " and " Moniteur " ...
Do you have the solution for me please ? Thanks
EDIT : Ok thanks you , this is the code of my class VOITURE :
public class Voiture {
private int idV = -1; // permet de voir si le parent est enregistré dans la BDD
private String marqueV;
private String dateAchatV;
private String PlaqueImmatriculationV;
public Voiture(String marqueV, String plaqueImmatriculationV) {
this.marqueV = marqueV;
PlaqueImmatriculationV = plaqueImmatriculationV;
}
public Voiture(JSONAdapter jsonAdapter) {
this.marqueV = marqueV;
this.PlaqueImmatriculationV = PlaqueImmatriculationV;
}
public int getIdV() {
return idV;
}
public void setIdV(int idV) {
this.idV = idV;
}
public String getMarqueV() {
return marqueV;
}
public void setMarqueV(String marqueV) {
this.marqueV = marqueV;
}
public String getDateAchatV() {
return dateAchatV;
}
public void setDateAchatV(String dateAchatV) {
this.dateAchatV = dateAchatV;
}
public String getPlaqueImmatriculationV() {
return PlaqueImmatriculationV;
}
public void setPlaqueImmatriculationV(String plaqueImmatriculationV) {
PlaqueImmatriculationV = plaqueImmatriculationV;
}
}
This is the code of my class Moniteur :
public class Moniteur {
private int idM;
private String nomM;
private String prenomM;
private String adresseM;
private String telephoneM;
public Moniteur(String nomM, String prenomM,String adresseM,String telephoneM) {
this.nomM = nomM;
this.prenomM = prenomM;
this.adresseM = adresseM;
this.telephoneM = telephoneM;
}
public int getIdM() { return idM; }
public void setIdM(int idM) { this.idM = idM; }
public String getNomM() {
return nomM;
}
public void setNomM(String nomM) {
this.nomM = nomM;
}
public String getPrenomM() {
return prenomM;
}
public void setPrenomM(String prenomM) {
this.prenomM = prenomM;
}
public String getAdresseM() {
return adresseM;
}
public void setAdresseM(String adresseM) {
this.adresseM = adresseM;
}
public String getTelephoneM() {
return telephoneM;
}
public void setTelephoneM(String telephoneM) {
this.telephoneM = telephoneM;
}
}
The purpose of these two classes and how they relate is not clear, but if you want to store both of them in a single container (which is what you are trying to do) you will need to define a common interface between them (or an abstract class). I don't speak French so you will have a easier time creating a good name.
I suggest creating an interface:
public interface AbstractItem
{
//TODO define common functions in this class
}
then implement this interface in your classes:
public class Voiture implements AbstractItem
{ ... }
public class Moniteur implements AbstractItem
{ ... }
Then, you can create an array adapter that will hold both of these items:
public class JSONAdapter extends ArrayAdapter<AbstractItem>
{ ... }
If I understand correctly, "Voiture" means "car" and "Moniteur" means "instructor" or "teacher".
So, it sounds like you are implementing a type of "driving school" where there are teachers with cars that they use/drive.
If that is the case, you really only need an ArrayAdapter<Monituer> and you could implement your Moniteur class like so.
public class Moniteur {
private List<Voiture> voitures;
public Monituer() {
voitures = new ArrayList<Voiture>();
}
public void ajouterVoiture(Voiture v) {
voitures.add(v);
}
public List<Voiture> obtientVoitures() {
return voitures;
}
}
Or maybe I don't understand what is trying to be displayed in the adapters. In that case, feel free to comment below.

Object-oriented-ness got out of control (plus maybe some threading problems)

I don't have much experience with building well-designed object oriented systems, and this time I improvised, which lead to the system not working and not giving me any errors.
Basically in my android app, I have a user profile activity that calls a class that queries the remote database using the user ID, and returns values for user avatar and user name.
Until the class was nested inside the profile activity class it was alright, but I decided to move it out of there and change some other stuff and now when I go to My profile I do not see my avatar and I do not see my user name.
Here is the GetUserData class:
public class GetUserData extends Activity {
private String currentlyLoggedInUserString;
SharedPreferences sharedPrefs;
Editor editor;
int currentlyLoggedInUser;
private JSONParser jsonParser = new JSONParser();
private Configurationz configurationz = new Configurationz();
private ToastMaker toastMaker = new ToastMaker();
private static final String TAG_SUCCESS = "success";
private static final String TAG_USER_AVATAR = "user_avatar";
private static final String TAG_USER_NAME = "user_name";
private static final String TAG_USER_EMAIL = "user_email";
private static final String TAG_USER_SEX = "user_sex";
private static final String TAG_USER_DATE_REGISTERED = "user_date_registered";
private static final String TAG_USER_LAST_SEEN = "user_last_seen";
private static final String TAG_USER_PASSWORD = "user_password";
private static final String APP_SHARED_PREFS = "asdasd_preferences";
private String userName;
private String userEmail;
private String userSex;
private String userPassword;
private String userAvatar;
private String userDateRegistered;
private String userLastSeen;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public String getUserSex() {
return userSex;
}
public void setUserSex(String userSex) {
this.userSex = userSex;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserAvatar() {
return userAvatar;
}
public void setUserAvatar(String userAvatar) {
this.userAvatar = userAvatar;
}
public String getUserDateRegistered() {
return userDateRegistered;
}
public void setUserDateRegistered(String userDateRegistered) {
this.userDateRegistered = userDateRegistered;
}
public String getUserLastSeen() {
return userLastSeen;
}
public void setUserLastSeen(String userLastSeen) {
this.userLastSeen = userLastSeen;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sharedPrefs = getApplicationContext().getSharedPreferences(APP_SHARED_PREFS, Context.MODE_PRIVATE);
new GetUserDataGetter().execute();
}
public class GetUserDataGetter extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
int success;
try {
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
// fix these shitty variables.
currentlyLoggedInUser = sharedPrefs.getInt("currentLoggedInUserId", 0);
currentlyLoggedInUserString = Integer.toString(currentlyLoggedInUser);
parameters.add(new BasicNameValuePair("user_id", currentlyLoggedInUserString));
final JSONObject json = jsonParser.makeHttpRequest(configurationz.URL_PHP_GET_USER_DATA, "POST", parameters);
success = json.getInt(TAG_SUCCESS);
if (success == 1) {
// user data found
setUserLastSeen(json.getString(TAG_USER_LAST_SEEN));
setUserDateRegistered(json.getString(TAG_USER_DATE_REGISTERED));
setUserAvatar(json.getString(TAG_USER_AVATAR));
setUserSex(json.getString(TAG_USER_SEX));
setUserPassword(json.getString(TAG_USER_PASSWORD));
setUserEmail(json.getString(TAG_USER_EMAIL));
setUserName(json.getString(TAG_USER_NAME));
//return json.getString(TAG_USER_AVATAR);
return null;
} else if (success == 2) {
//toast about not being able to connect to db;
runOnUiThread(new Runnable() {
public void run() {
//this might cause some SHIT!!!!!!!!!!!! TEST IT!!!
toastMaker.toast(getBaseContext(), configurationz.ERROR_MESSAGES_SIGNUP_DEVICE_UNABLE_TO_TAKE_PHOTOS, configurationz, Toast.LENGTH_LONG);
}
});
setUserLastSeen("");
setUserDateRegistered("");
setUserAvatar("");
setUserSex("");
setUserPassword("");
setUserEmail("");
setUserName("");
return null;
} else {
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
}
and here is the MyProfile class:
public class MyProfile extends ActionBarAndSlidingMenu {
private TableRow myProfileActionButtonsHolder;
private TextView tvUserName;
private ImageButton iUserAvatar;
private Bitmap iUserAvatarBitmap;
private String avatarPath;
private String userName;
private static final String APP_SHARED_PREFS = "asdasd_preferences";
SharedPreferences sharedPrefs;
Editor editor;
int currentlyLoggedInUser;
boolean userLoggedInState = false;
private GetUserData getUserData = new GetUserData();
public MyProfile() {
super(R.string.app_name);
}
// do a check here whether this is the user themselves or some other user
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sharedPrefs = getApplicationContext().getSharedPreferences(APP_SHARED_PREFS, Context.MODE_PRIVATE);
setContentView(R.layout.user_profile);
// check whether user is logged in, otherwise redirect them to
// login/signup page
userLoggedInState = sharedPrefs.getBoolean("userLoggedInState", false);
if (!userLoggedInState) {
// start intent to get them out of here.
// Research whether this step is necessary at all
}
// define the view components
myProfileActionButtonsHolder = (TableRow) findViewById(R.id.userProfileActionButtonsHolder);
// set avatar image
iUserAvatar = (ImageButton) findViewById(R.id.iUserAvatar);
avatarPath = getUserData.getUserAvatar();
if (avatarPath != "") {
iUserAvatarBitmap = BitmapFactory.decodeFile(avatarPath);
iUserAvatar.setImageBitmap(iUserAvatarBitmap);
} else {
iUserAvatar.setImageResource(R.drawable.avatar_default_male);
}
//set user display name
userName = getUserData.getUserName();
tvUserName = (TextView) findViewById(R.id.tvUserName);
tvUserName.setText(userName);
// create action buttons fragment with "edit" and "settings" buttons
getSupportFragmentManager().beginTransaction().replace(R.id.userProfileActionButtonsHolder, new MyProfileActionButtonsFragment()).commit();
}
}
First, you need to read up on programming in general and proper coding guidelines in particular, as this is a bit of a chaos. As soon as your project becomes more complex, this gets unreadable and undebuggable. Second, you should read up on how Android works.
Here's your problem in a nutshell:
An Activity is not just Android's own version of a class and you can't use it as such. An Activity represents a screen that is displayed to the user. No screen to display? No Activity.
Thus, your getUserData Activity should be a regular class and not extend activity.
Now, in MyProfile you just declare a member variable with
private GetUserData getUserData = new GetUserData();
This does nothing and it certainly never runs that class' onCreate. Thus, your task is never executed and all your fields return null.
Here's what to do in a nutshell:
Create a class UserDetails that has a constructor that takes the username, etc. plus the getters necessary to get these details. Add nothing else. This is what we call Java's version of a value object.
public class UserDetails {
private final String mUsername;
public UserDetails(String username) {
mUsername = username;
}
public String getUsername() {
return mUsername;
}
}
Create an interface called IOnUserDetailsReceivedListener with the method onUserDetailsReceived(UserDetails userDetails). The reason for this is that your download task will take some time. You need to get informed when it's done and that's what we use this interface for. This is called a listener pattern.
public interface IOnUserDetailsReceivedListener {
public void onUserDetailsReceived(UserDetails userDetails);
public void onUserDetailsError();
}
Create a class Downloader that contains your AsyncTask and that has a method retrieveUserDetails(); or something. In that method, run the async task to download. When you get the data from the server, fill it into a new UserDetails(...) object and then call listener.onUserDetailsReceived(userDetails).
public class UserDetailsDownloader {
private IOnUserDetailsReceivedListener mListener;
public UserDetailsDownloader(IOnUserDetailsReceivedListener listener) {
mListener = listener;
}
public void downloadUserDetails() {
//Execute the async task here. In it's onPostExecute, do mListener.onUserDetailsReceived(userDetails).
}
private class DownloaderTask extends AsyncTask<String, Integer, UserDetails> {
#Override
protected UserDetails doInBackground(String... params) {
//Download code
//In downloading there might go stuff wrong. If so, return null as an easy method without any error handling.
UserDetails userDetails = new UserDetails("downloadedUsername");
return userDetails;
}
#Override
protected void onPostExecute(UserDetails userDetails) {
if(userDetails == null) {
if(mListener != null) {
//Something went wrong. Tell the listener.
mListener.onUserDetailsError();
}
} else {
if(mListener != null) {
//Cool! Lets pass the userDetails to the activity.
mListener.onUserDetailsReceiver(userDetails);
}
}
}
}
}
Let your activity implements IOnUserDetailsReceivedListener.
public void UserActivity extends Activity implements IOnUserDetailsReceivedListener {
private UserDetailsDownloader mUserDetailsDownloader;
public void onCreate(...) {
mUserDetailsDownloader = new UserDetailsDownloader(this);
mUserDetailsDownloader.downloadUserDetails();
}
public void onUserDetailsReceived(UserDetails userDetails) {
//Yeeh we received user data.
}
public void onUserDetailsError() {
//Something went wrong. Tell the user?
}
}
When your task is done, it'll call your Activities onUserDetailsReceived method and pass you the UserDetails value object with which you can then do what you want.
I don't know if this is your only problem or not but too much for a comment. You shouldn't use runOnUiThread() in doInBackground()
runOnUiThread(new Runnable() {
public void run() {
//this might cause some SHIT!!!!!!!!!!!! TEST IT!!!
toastMaker.toast(getBaseContext(), configurationz.ERROR_MESSAGES_SIGNUP_DEVICE_UNABLE_TO_TAKE_PHOTOS, configurationz, Toast.LENGTH_LONG);
}
});
this is why AsyncTask has onPostExecute() and its other methods...they all run on the UI Thread except for doInBackground()
Instead of return null, returnsuccessand depending on that value, do what you need to inonPostExecute()`.
Edit
onPostExecute() gets its parameter from what doInBackground() returns which is the third param in your declaration public class GetUserDataGetter extends AsyncTask<String, String, String>. So you can change that param or return a String to onPostExecute() from doInBackground().
AsyncTask Docs

creating parcelable in android from some of the fields of a class

i have the following class which i intent to pass from one activity to another:
public class Ad extends ListItem implements parcelable{
private String _type;
private String _recordID;
private String _line1;
private String _line2;
private String _line3;
private String _line4;
private String _url;
private IOnUiNeedToUpdateListener _listener;
private boolean _notActive = false;
private String _alertText;
private Double _longitude;
private Double _latitude;
}
i want to pass an array of such objects from one activity to another. however, i do not need to pass all fields.
is it possible to create a parcel only from the desired fields and send it?
It's your code that writes to Parcel and your code that reads from Parcel. So basically yes. You can write whatever you want. Content of all members, content of some, no members, but other values you use to restore state of the object etc, etc.
Try design your class like this..
public class Form implements Parcelable {
private String formdata1;
private String formdata2;
private String formdata3;
private String formdata4;
public Form() {
}
public Form(Parcel in) {
setFormdata1(in.readString());
setFormdata2(in.readString());
setFormdata3(in.readString());
setFormdata4(in.readString());
}
public String getFormdata1() {
return formdata1;
}
public void setFormdata1(String formdata1) {
this.formdata1 = formdata1;
}
public String getFormdata2() {
return formdata2;
}
public void setFormdata2(String formdata2) {
this.formdata2 = formdata2;
}
public String getFormdata3() {
return formdata3;
}
public void setFormdata3(String formdata3) {
this.formdata3 = formdata3;
}
public String getFormdata4() {
return formdata4;
}
public void setFormdata4(String formdata4) {
this.formdata4 = formdata4;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel in, int arg1) {
in.writeString(getFormdata1());
in.writeString(getFormdata2());
in.writeString(getFormdata3());
in.writeString(getFormdata4());
}
public static final Parcelable.Creator<Form> CREATOR = new Parcelable.Creator<Form>() {
#Override
public Form createFromParcel(Parcel in) {
return new Form(in);
}
#Override
public Form[] newArray(int size) {
return new Form[size];
}
};
}

Categories

Resources