Android SharedPreferences auto incrementing technique - java

I wanted some feedback on this approach. My apologies if this is confusing or nonsensical. (thats probably why I'm asking because im unsure.)
My app auto assigns clientID's to a textview at first launch - is auto set to 100. To do this from that point forward I store an int value to sharedpreferences. At Oncreate I run a check against this specific ID in the sharedpreferences and later it either increments or assigns back to 100. The challenge was that sharedpreferences (that I know of) can only take a string value i.e. (editor.putString("CLIENTID", ID);) or editor.putInt("ID", c);
I wanted to avoid using a database for this portion to minimize overhead (could be wrong) There are validations in place that prevent this from being incremented unless certain conditions are met.
c is my persisted counter used in the shared preferences.
Here's what I did at oncreate:
public String ID; //global
int checkCount = prefs.getInt("ID", c); //get the current ID value currently set or last set.
if( checkCount > 100)
{
c = checkCount; //whatever the value of c is from its latest increment the counter c set to this
}
else if (checkCount <= 100)
{
c = 100; //base value of clientIDs //assign base value for starting clientIDs
}
ID = "" + c + ""; //sets value of the counter to a string
//Parsing integer was not passing correctly.
clientID.setText(ID);
In the onclick:
//Once all the conditions are met pass the clientID for this instance.
SharedPreferences.Editor editor = prefs.edit(); //USING EDITOR TO ADD TO THE PREFERENCES
editor.putInt("ID", c);
....// then other stuff.
Any thoughts? My apologies if this is a noob question. I just want to be sure about this approach if this app goes all the way.
Thanks

Related

How can I get and set a string resource dynamically in a for-loop using a findViewById() method?

In my app, I want a counter from 0 to 8 to decide the number of players in a game.
Below there are 8 possible fields to write a name inside, which are all set to invisible. If the players-counter is set to 3 players, there should be the first 3 fields visible. Depending on the actual number of the counter, the visibility of the fields changes (1player = first field, 5 players = first 5 fields).
When the +1 (player) button is clicked, a certain method is activated. I tried to run a for-loop everytime the button is clicked. In this for-loop from 0 to "whatever amount" (max. 8 players) the actual fields should be found with "findById" and set to visible.
I tried it with a string resource (.xml) and I can get the text of the resource but with my thought process, I have to update the string resource to every number of the field (if 3 players: "field_" + "1", "field_" + "2", "field_" + "3").
How can I get and (most importantly) set/update a string resource for this specific purpose?
(Switch is too inefficient and I can't use a string with the findViewBy Id()-method by updating the String (not string resource) like mentioned before.
Please help, and accept the fact that I'm new to Android Studio for one week!)
You can use "getIdentifier" which takes a String parameter. So you can set the type as "id" in the second parameter of this method. This method returns the id of the view you want, but beware, it will throw a "FATAL EXCEPTION" if the id of the View doesn't exist. With this id, you can use findViewById to fetch the TextView and change its visibility. The "getIdentifier" method can be called from the "getResources()" method.
Below you can see what it would be like to make visible a TextView that has the id "textView1":
int id = getResources().getIdentifier("textView1", "id", getPackageName());
TextView textView = findViewById(id);
textView.setVisibility(View.VISIBLE);
Below you can see how you would make 8 TextView with id 1 to 8 visible:
TextView textView;
for (int i = 1; i <= 8; i++) {
int id = getResources().getIdentifier("textView" + i, "id", getPackageName());
textView = findViewById(id);
textView.setVisibility(View.VISIBLE);
}
So, just put the limit at i <= x , with x being the limit of players who will play:
TextView textView;
for (int i = 1; i <= totalPlayers; i++) {
int id = getResources().getIdentifier("textView" + i, "id", getPackageName());
textView = findViewById(id);
textView.setVisibility(View.VISIBLE);
}
Do you just want to make some EditTexts visible and others not? Personally I'd keep it simple, do the lookups once (in onCreate or wherever) and store the references in a list. Then when you need to display n fields, you can just iterate over the list and set the first n to VISIBLE and the rest to INVISIBLE.
I feel like it's fine to just list all the EditText IDs (R.id.field_1 etc) and generate your list of actual Views from that, but if that repetition bothers you, there's a few things you could do. Like:
set a tag attribute on each field in the XML, and use findViewWithTag to look them up, generating the lookup strings programmatically, like "field_" + i
do a similar thing with the resource ID, like in #Moises's answer
lookup their containing layout, use getChildCount and [getChildAt] to iterate over the views in that layout, and use isInstance to collect all the EditTexts in order3
create and add the EditTexts in code - you probably don't want to do this, but you could!
I'm not really sure what you mean about the string resource or what you're trying to do - I'd honestly just make a list of R.id.field_1 etc, iterate over that to do findViewById on each and store those in a new list, and you're done. Also my Java's a bit rusty so sorry no example code!

Using SharedPrefernces to sum Integers from a RecyclerView

I'm trying to create an App that sums time.
My situation:
I have a RecyclerView with a lot of elements, and each of those has a different time attribute.
Now, when an element is clicked, then another and another I want all those attributes to be summed and the final result to be displayed in another activity.
So what I'm trying to do is to achieve this using SharedPrefernces like this:
private void getTime(int time) {
SharedPreferences sharedPreferences = mContext.getSharedPreferences("sharedPrefs", MODE_PRIVATE);
int time0 = sharedPreferences.getInt("TimeRetrieve", 0);
int sum = time0 + time;
SharedPreferences sharedPreferences2 = mContext.getSharedPreferences("sharedPrefs", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences2.edit();
editor.putInt("Time", sum);
editor.apply();
TimeRetrieve gets the total time that is displayed ion the TextView, so if it's the first time it's defaulted to 0, of course.
After that it's supposed to sum that retrieved int with the int of the Item that has just been clicked and then saved in another SharedPref: Time.
Time gets sent to the TextView, where it gets retrieved by TimeRetrieve
But his doesn't work..
First, you are using 2 different keys : TimeRetrieve and Time. So, you can't make the sum.
Second, why are you using 2 SharedPreferences object ? Only one is needed.
Third, you don't need to use SharedPreferences here. You just have to sum what you want in a variable and then, pass it to the other Activity with extra bundle.
Is there a reason you're using two different SharedPreferences to get and put data? Consider using something like this:
private void GetTime(int time) {
SharedPreferences sharedPreferences = mContext.getDefaultSharedPreferences("sharedPrefs", MODE_PRIVATE);
int time0 = sharedPreferences.getInt("TimeRetrieve", 0);
int sum = time0 + time;
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt("TimeRetrieve", sum);
editor.apply();
Notice the call to getDefaultSharedPreferences. This will get the default com.companyname.package.yourapplication SharedPreferences file, and you should be using only that file if you want to set and retrieve data from it. There are other reasons you would create multiple SharedPreferences files, but I don't think that's what you're trying to do. You're also using two different keys, which is definitely a part of the problem as well. I changed them in the code above so that they match and you're referencing the same key both times.

MaterialDrawer set selected profile

I use the MaterialDrawer library by Mike Penz.
In my OnCreate, profiles are added to the drawer from a linkedHashMap. When a profile gets selected, the new selected profile is saved in a sharedPreference.
My Question: if I launch the App again, how can I set the profile, whichs name is stored in the sharedPreference, as the selected?
Edit: Without an identifier? Or is this not possible?
The MaterialDrawer requires an identifier given to it's elements so that you can reselect them (and that the Drawer itself can re-select them upon configuration changes) again.
Simply provide any id. You can use something like this:
private static long hashString64Bit(CharSequence str) {
long result = 0xcbf29ce484222325L;
final int len = str.length();
for (int i = 0; i < len; i++) {
result ^= str.charAt(i);
result *= 0x100000001b3L;
}
return result;
}
To generate an long identifier for your string, or you generate some kind of hashcode.

Bukkit ScoreBoard Acting Weird

I have a score board like so :
int time = 15;
private ScoreboardManager sbManager;
private Scoreboard scoreBoard;
private Objective obj;
private Score s0;
public void init(Player player) {
sbManager = Bukkit.getScoreboardManager();
scoreBoard = sbManager.getNewScoreboard();
obj = scoreBoard.registerNewObjective("ScoreBoard", "dummy");
obj.setDisplaySlot(DisplaySlot.SIDEBAR);
obj.setDisplayName("Test");
s0 = obj.getScore(Bukkit.getOfflinePlayer("Time = " + time));
s0.setScore(6);
player.setScoreboard(scoreBoard);
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new Runnable(){
public void run() {
time--;
updateScoreBoard(player);
System.out.println(time);
}
},20, 20);
}
And whenever I try to update it, it just dosen't work and btw my score board is a "fancy" one, so it should look like :
Time = time 6 <- the '6' is the default minecraft score.
Here's an example of my update method:
public void updateScoreBoard(Player p){
s0 = obj.getScore(Bukkit.getOfflinePlayer("Time =" + time));
s0.setScore(6);
p.setScoreboard(scoreBoard);
}
Because you're using scoreboards in an unconventional way, things are bound to get tricky. By "fancy" I assume you mean the scoreboards which display a score's name and value right next to each other on the left side, which is done by placing the actual score value inside the name String of the score (like you have already done).
The problem with your code specifically is that you are not actually changing the value of the existing score entry (since that value is set to 6 to keep the entry in the same row of the display) but creating a new score entry every time you update the display, since score entries are identified by their name and not their score value (this is required so that different score entries can have the same value, for example a player can have a "bank balance" score with a value of 2 and an "amount of deaths" score with a value of 2).
If this weren't the case for example, your new score entry with name "Time = 14" and a score value of 6 would override the previous score entry with name "Time = 15" because of the identical score value, but this is not the case.
When I tested your code snippet, more rows (score entries) were added until the display filled to maximum capacity. I can only assume this is what you meant by your code "acting weird" since you didn't elaborate on the expected and observed results of your code.
You'll want to remove the previous score entry with the outdated value. Because the API is not intended to be used this way, one cannot simply remove a score entry from an objective (resetting the score doesn't remove the entire entry).
You'll therefore need to create a new scoreboard with a new objective etc. every time you want to update a single "fancy" score entry. This also means that all scores displayed in the scoreboard need to be kept track of independently and re-added and re-set to the new scoreboard whenever any other "fancy" score is updated.
These changes to your updateScoreboard method did the trick for me:
public void updateScoreBoard(Player p) {
scoreBoard = sbManager.getNewScoreboard();
obj = scoreBoard.registerNewObjective("ScoreBoard", "dummy");
obj.setDisplaySlot(DisplaySlot.SIDEBAR);
obj.setDisplayName("Test");
s0 = obj.getScore(Bukkit.getOfflinePlayer("Time = " + time));
s0.setScore(6);
p.setScoreboard(scoreBoard);
}
Note that this method only fixes the immediate issue of more entries being added, if you want more "fancy" and possibly even normal score entries, all of those will need to be handled respectively.
All this extra work and having meaningless numbers/values always on the right of the display seem like a large trade-off just to remove a little whitespace between a score's name and value.
Some other tips: You don't need to update the sbManager variable every time you initiate the scoreboard for a new player, the manager is always the same object, so using Bukkit.getScoreboardManager() once should suffice.

Difference between += and ++ in Java

I have a global variable that I modify in three different methods. It starts at 0, one method adds by 3, the next one by 2 and the last one by 1. They are all related to a button of their own.
When I click the "plus 1" button, the counter remains at 0 and I need another push to get it to 1. Interestingly, if I start with the other two buttons the counter acts accordingly but if I click my "plus 1" button again, it needs two pushes and acts weird like if it was holding the add...
public void addThreeForTeamB(View view) {
displayForTeamB(scoreTeamB += 3);
}
public void addTwoForTeamB(View view) {
displayForTeamB(scoreTeamB += 2);
}
public void addOneForTeamB(View view) {
displayForTeamB(scoreTeamB ++);
}
So that's the way it is managed, the cool thing is that when I change the last method to a "scoreTeamB += 1" it acts as it should, just adding without conflict.
My question is about the difference between this two operators to better understand the reason behind the slight discrepancy generated when using this 2 operators on the same variable.
scoreTeamB++ returns the previous value of the variable (before it was incremented). += returns the value that was assigned to the variable.
If you replace scoreTeamB++ with ++scoreTeamB or with scoreTeamB +=1 you'll get the new (incremented) value of the variable.
To make this code work as you expect, you should use prefix ++ operator instead of postfix one. Prefix ++ operator(as well as -- operator, apparently) returns incremented value, while postfix operator ++ returns value of variable before increment.
Those may be implemented like this:
public static Integer prefixIncrement(Integer value) {
value = value + 1;
return value;
}
public static Integer postfixIncrement(Integer value) {
Integer returnValue = new Integer(value);
value = value + 1;
return returnValue;
}

Categories